artalk 2.2.11 → 2.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/dist/Artalk.css +1 -1
  2. package/dist/Artalk.es.js +1872 -1143
  3. package/dist/Artalk.iife.js +1 -1
  4. package/dist/Artalk.js +1 -1
  5. package/dist/ArtalkLite.css +1 -0
  6. package/dist/ArtalkLite.es.js +5123 -0
  7. package/dist/ArtalkLite.iife.js +1 -0
  8. package/dist/ArtalkLite.js +1 -0
  9. package/index.html +5 -3
  10. package/package.json +7 -5
  11. package/src/api/index.ts +24 -4
  12. package/src/api/request.ts +50 -81
  13. package/src/artalk.ts +131 -127
  14. package/src/comment/actions.ts +86 -0
  15. package/src/{components/html → comment}/comment.html +1 -1
  16. package/src/comment/comment.ts +191 -0
  17. package/src/comment/index.ts +3 -0
  18. package/src/comment/render.ts +425 -0
  19. package/src/components/action-btn.ts +6 -3
  20. package/src/components/dialog.ts +7 -3
  21. package/src/components/read-more-btn.ts +6 -2
  22. package/src/context.ts +204 -13
  23. package/src/defaults.ts +15 -4
  24. package/src/editor/editor.html +18 -0
  25. package/src/editor/editor.ts +419 -0
  26. package/src/editor/index.ts +3 -0
  27. package/src/editor/plugs/editor-plug.ts +51 -0
  28. package/src/{components/editor-plugs → editor/plugs}/emoticons-plug.less +2 -1
  29. package/src/{components/editor-plugs → editor/plugs}/emoticons-plug.ts +65 -63
  30. package/src/editor/plugs/header-input-plug.ts +78 -0
  31. package/src/{components/editor-plugs → editor/plugs}/preview-plug.less +0 -0
  32. package/src/editor/plugs/preview-plug.ts +40 -0
  33. package/src/editor/plugs/upload-plug.ts +124 -0
  34. package/src/i18n/en.ts +78 -0
  35. package/src/i18n/index.ts +21 -0
  36. package/src/i18n/zh-CN.ts +82 -0
  37. package/src/layer/index.ts +4 -0
  38. package/src/{components → layer}/layer.ts +9 -9
  39. package/src/{components/html → layer}/sidebar-layer.html +0 -0
  40. package/src/{components → layer}/sidebar-layer.ts +17 -47
  41. package/src/lib/checker/admin-checker.ts +7 -7
  42. package/src/lib/checker/captcha-checker.ts +5 -6
  43. package/src/lib/checker/index.ts +22 -17
  44. package/src/lib/component.ts +7 -2
  45. package/src/lib/stat.ts +63 -0
  46. package/src/lib/ui.ts +3 -10
  47. package/src/lib/user.ts +20 -3
  48. package/src/lib/utils.ts +23 -9
  49. package/src/list/index.ts +3 -0
  50. package/src/{components → list}/list-lite.ts +83 -111
  51. package/src/{components → list}/list-nest.ts +0 -0
  52. package/src/{components/html → list}/list.html +3 -6
  53. package/src/{components → list}/list.ts +44 -42
  54. package/src/style/_variables.less +1 -2
  55. package/src/style/comment.less +26 -13
  56. package/src/style/editor.less +22 -14
  57. package/src/style/list.less +6 -9
  58. package/src/style/main.less +9 -8
  59. package/src/style/pagination.less +1 -1
  60. package/test/ArtalkCount.html +16 -0
  61. package/test/ArtalkI18n.html +15 -0
  62. package/test/ArtalkLite.html +15 -0
  63. package/types/artalk-config.d.ts +50 -32
  64. package/types/context.d.ts +128 -0
  65. package/types/event.d.ts +6 -66
  66. package/types/global.d.ts +1 -0
  67. package/types/plug.d.ts +4 -0
  68. package/{vite-common.config.ts → vite-base.config.ts} +6 -4
  69. package/vite-demo.config.ts +2 -4
  70. package/vite-lite.config.ts +22 -0
  71. package/vite.config.ts +9 -18
  72. package/src/components/_component.ts.txt +0 -10
  73. package/src/components/comment.ts +0 -605
  74. package/src/components/editor-plugs/_example-plug.ts.txt +0 -29
  75. package/src/components/editor-plugs/editor-plug.ts +0 -20
  76. package/src/components/editor-plugs/preview-plug.ts +0 -48
  77. package/src/components/editor.ts +0 -604
  78. package/src/components/html/editor.html +0 -18
package/dist/Artalk.es.js CHANGED
@@ -1,4 +1,6 @@
1
1
  var __defProp = Object.defineProperty;
2
+ var __defProps = Object.defineProperties;
3
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
2
4
  var __getOwnPropSymbols = Object.getOwnPropertySymbols;
3
5
  var __hasOwnProp = Object.prototype.hasOwnProperty;
4
6
  var __propIsEnum = Object.prototype.propertyIsEnumerable;
@@ -14,6 +16,7 @@ var __spreadValues = (a, b) => {
14
16
  }
15
17
  return a;
16
18
  };
19
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
17
20
  var __publicField = (obj, key, value) => {
18
21
  __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
19
22
  return value;
@@ -39,9 +42,146 @@ var __async = (__this, __arguments, generator) => {
39
42
  });
40
43
  };
41
44
  var main = "";
45
+ var en = {
46
+ placeholder: "Leave a comment",
47
+ noComment: "No Comment",
48
+ send: "Send",
49
+ nick: "Nickname",
50
+ email: "Email",
51
+ link: "Website",
52
+ emoticon: "Emoji",
53
+ preview: "Preview",
54
+ image: "Image",
55
+ uploadFail: "Upload Failed",
56
+ commentFail: "Failed to comment",
57
+ restoredMsg: "Content has been restored",
58
+ onlyAdminCanReply: "Only admin can reply",
59
+ uploadLoginMsg: "Please fill in your name and email to upload",
60
+ counter: "{count} Comments",
61
+ sortLatest: "Latest",
62
+ sortOldest: "Oldest",
63
+ sortBest: "Best",
64
+ sortAuthor: "Author",
65
+ openComment: "Open Comment",
66
+ closeComment: "Close Comment",
67
+ listLoadFailMsg: "Failed to load comments",
68
+ listRetry: "Click to retry",
69
+ loadMore: "Load More",
70
+ admin: "Admin",
71
+ reply: "Reply",
72
+ voteUp: "Up",
73
+ voteDown: "Down",
74
+ voteFail: "Vote Failed",
75
+ readMore: "Read More",
76
+ actionConfirm: "Confirm",
77
+ collapse: "Collapse",
78
+ collapsed: "Collapsed",
79
+ collapsedMsg: "This comment has been collapsed",
80
+ expand: "Expand",
81
+ approved: "Approved",
82
+ pending: "Pending",
83
+ pendingMsg: "Pending, visible only to commenter.",
84
+ delete: "Delete",
85
+ deleteConfirm: "Confirm",
86
+ pin: "Pin",
87
+ unpin: "Unpin",
88
+ seconds: "seconds ago",
89
+ minutes: "minutes ago",
90
+ hours: "hours ago",
91
+ days: "days ago",
92
+ now: "just now",
93
+ adminCheck: "Enter admin password:",
94
+ captchaCheck: "Enter the CAPTCHA to continue:",
95
+ confirm: "Confirm",
96
+ cancel: "Cancel",
97
+ msgCenter: "Messages",
98
+ ctrlCenter: "Admin",
99
+ frontend: "Frontend",
100
+ backend: "Backend",
101
+ loading: "Loading",
102
+ loadFail: "Load Failed",
103
+ editing: "Editing",
104
+ editFail: "Edit Failed",
105
+ deleting: "Deleting",
106
+ deleteFail: "Delete Failed",
107
+ reqGot: "Request got",
108
+ reqAborted: "Request timed out or terminated unexpectedly"
109
+ };
110
+ const zhCN = {
111
+ placeholder: "\u952E\u5165\u5185\u5BB9...",
112
+ noComment: "\u300C\u6B64\u65F6\u65E0\u58F0\u80DC\u6709\u58F0\u300D",
113
+ send: "\u53D1\u9001\u8BC4\u8BBA",
114
+ nick: "\u6635\u79F0",
115
+ email: "\u90AE\u4EF6",
116
+ link: "\u7F51\u5740",
117
+ emoticon: "\u8868\u60C5",
118
+ preview: "\u9884\u89C8",
119
+ image: "\u56FE\u7247",
120
+ uploadFail: "\u4E0A\u4F20\u5931\u8D25",
121
+ commentFail: "\u8BC4\u8BBA\u5931\u8D25",
122
+ restoredMsg: "\u5185\u5BB9\u5DF2\u81EA\u52A8\u6062\u590D",
123
+ onlyAdminCanReply: "\u4EC5\u7BA1\u7406\u5458\u53EF\u8BC4\u8BBA",
124
+ uploadLoginMsg: "\u586B\u5165\u4F60\u7684\u540D\u5B57\u90AE\u7BB1\u624D\u80FD\u4E0A\u4F20\u54E6",
125
+ counter: "{count} \u6761\u8BC4\u8BBA",
126
+ sortLatest: "\u6700\u65B0",
127
+ sortOldest: "\u6700\u65E9",
128
+ sortBest: "\u6700\u70ED",
129
+ sortAuthor: "\u4F5C\u8005",
130
+ openComment: "\u6253\u5F00\u8BC4\u8BBA",
131
+ closeComment: "\u5173\u95ED\u8BC4\u8BBA",
132
+ listLoadFailMsg: "\u65E0\u6CD5\u83B7\u53D6\u8BC4\u8BBA\u5217\u8868\u6570\u636E",
133
+ listRetry: "\u70B9\u51FB\u91CD\u65B0\u83B7\u53D6",
134
+ loadMore: "\u52A0\u8F7D\u66F4\u591A",
135
+ admin: "\u7BA1\u7406\u5458",
136
+ reply: "\u56DE\u590D",
137
+ voteUp: "\u8D5E\u540C",
138
+ voteDown: "\u53CD\u5BF9",
139
+ voteFail: "\u6295\u7968\u5931\u8D25",
140
+ readMore: "\u9605\u8BFB\u66F4\u591A",
141
+ actionConfirm: "\u786E\u8BA4\u64CD\u4F5C",
142
+ collapse: "\u6298\u53E0",
143
+ collapsed: "\u5DF2\u6298\u53E0",
144
+ collapsedMsg: "\u8BE5\u8BC4\u8BBA\u5DF2\u88AB\u7CFB\u7EDF\u6216\u7BA1\u7406\u5458\u6298\u53E0",
145
+ expand: "\u53D6\u6D88\u6298\u53E0",
146
+ approved: "\u5DF2\u5BA1",
147
+ pending: "\u5F85\u5BA1",
148
+ pendingMsg: "\u5BA1\u6838\u4E2D\uFF0C\u4EC5\u672C\u4EBA\u53EF\u89C1\u3002",
149
+ delete: "\u5220\u9664",
150
+ deleteConfirm: "\u786E\u8BA4\u5220\u9664",
151
+ pin: "\u7F6E\u9876",
152
+ unpin: "\u53D6\u6D88\u7F6E\u9876",
153
+ seconds: "\u79D2\u524D",
154
+ minutes: "\u5206\u949F\u524D",
155
+ hours: "\u5C0F\u65F6\u524D",
156
+ days: "\u5929\u524D",
157
+ now: "\u521A\u521A",
158
+ adminCheck: "\u952E\u5165\u5BC6\u7801\u6765\u9A8C\u8BC1\u7BA1\u7406\u5458\u8EAB\u4EFD\uFF1A",
159
+ captchaCheck: "\u952E\u5165\u9A8C\u8BC1\u7801\u7EE7\u7EED\uFF1A",
160
+ confirm: "\u786E\u8BA4",
161
+ cancel: "\u53D6\u6D88",
162
+ msgCenter: "\u901A\u77E5\u4E2D\u5FC3",
163
+ ctrlCenter: "\u63A7\u5236\u4E2D\u5FC3",
164
+ frontend: "\u524D\u7AEF",
165
+ backend: "\u540E\u7AEF",
166
+ loading: "\u52A0\u8F7D\u4E2D",
167
+ loadFail: "\u52A0\u8F7D\u5931\u8D25",
168
+ editing: "\u4FEE\u6539\u4E2D",
169
+ editFail: "\u4FEE\u6539\u5931\u8D25",
170
+ deleting: "\u5220\u9664\u4E2D",
171
+ deleteFail: "\u5220\u9664\u5931\u8D25",
172
+ reqGot: "\u8BF7\u6C42\u54CD\u5E94",
173
+ reqAborted: "\u8BF7\u6C42\u8D85\u65F6\u6216\u610F\u5916\u7EC8\u6B62"
174
+ };
175
+ const internal = {
176
+ "en": en,
177
+ "en-US": en,
178
+ "zh-CN": zhCN
179
+ };
42
180
  class User {
43
- constructor(conf) {
181
+ constructor(ctx) {
182
+ __publicField(this, "ctx");
44
183
  __publicField(this, "data");
184
+ this.ctx = ctx;
45
185
  const localUser = JSON.parse(window.localStorage.getItem("ArtalkUser") || "{}");
46
186
  this.data = {
47
187
  nick: localUser.nick || "",
@@ -51,79 +191,23 @@ class User {
51
191
  isAdmin: localUser.isAdmin || false
52
192
  };
53
193
  }
54
- save() {
194
+ update(obj = {}) {
195
+ Object.entries(obj).forEach(([key, value]) => {
196
+ this.data[key] = value;
197
+ });
55
198
  window.localStorage.setItem("ArtalkUser", JSON.stringify(this.data));
199
+ this.ctx.trigger("user-changed", this.ctx.user.data);
56
200
  }
57
- checkHasBasicUserInfo() {
58
- return !!this.data.nick && !!this.data.email;
59
- }
60
- }
61
- class Context {
62
- constructor(rootEl, conf) {
63
- __publicField(this, "cid");
64
- __publicField(this, "$root");
65
- __publicField(this, "conf");
66
- __publicField(this, "user");
67
- __publicField(this, "eventList", []);
68
- __publicField(this, "markedInstance");
69
- __publicField(this, "markedReplacers", []);
70
- this.cid = +new Date();
71
- this.$root = rootEl;
72
- this.conf = conf;
73
- this.user = new User(this.conf);
74
- this.$root.setAttribute("atk-run-id", this.cid.toString());
75
- }
76
- on(name, handler, scope = "internal") {
77
- this.eventList.push({ name, handler, scope });
78
- }
79
- off(name, handler, scope = "internal") {
80
- this.eventList = this.eventList.filter((evt) => {
81
- if (handler)
82
- return !(evt.name === name && evt.handler === handler && evt.scope === scope);
83
- return !(evt.name === name && evt.scope === scope);
201
+ logout() {
202
+ this.update({
203
+ token: "",
204
+ isAdmin: false
84
205
  });
85
206
  }
86
- trigger(name, payload, scope) {
87
- this.eventList.filter((evt) => evt.name === name && (scope ? evt.scope === scope : true)).map((evt) => evt.handler).forEach((handler) => handler(payload));
207
+ checkHasBasicUserInfo() {
208
+ return !!this.data.nick && !!this.data.email;
88
209
  }
89
210
  }
90
- const defaults$3 = {
91
- el: "",
92
- pageKey: "",
93
- server: "",
94
- site: "",
95
- placeholder: "\u952E\u5165\u5185\u5BB9...",
96
- noComment: "\u300C\u6B64\u65F6\u65E0\u58F0\u80DC\u6709\u58F0\u300D",
97
- sendBtn: "\u53D1\u9001\u8BC4\u8BBA",
98
- darkMode: false,
99
- editorTravel: true,
100
- flatMode: "auto",
101
- nestMax: 2,
102
- nestSort: "DATE_ASC",
103
- emoticons: "https://cdn.jsdelivr.net/gh/ArtalkJS/Emoticons/grps/default.json",
104
- vote: true,
105
- voteDown: false,
106
- uaBadge: true,
107
- listSort: true,
108
- pvEl: "#ArtalkPV",
109
- gravatar: {
110
- default: "mp",
111
- mirror: "https://sdn.geekzu.org/avatar/"
112
- },
113
- pagination: {
114
- pageSize: 20,
115
- readMore: true,
116
- autoLoad: true
117
- },
118
- heightLimit: {
119
- content: 300,
120
- children: 400
121
- },
122
- imgUpload: true,
123
- reqTimeout: 15e3,
124
- versionCheck: true,
125
- useBackendConf: false
126
- };
127
211
  class Component {
128
212
  constructor(ctx) {
129
213
  __publicField(this, "$el");
@@ -132,6 +216,9 @@ class Component {
132
216
  this.ctx = ctx;
133
217
  this.conf = ctx.conf;
134
218
  }
219
+ $t(key, args = {}) {
220
+ return this.ctx.$t(key, args);
221
+ }
135
222
  }
136
223
  function getDefaults() {
137
224
  return {
@@ -156,9 +243,9 @@ function getDefaults() {
156
243
  xhtml: false
157
244
  };
158
245
  }
159
- let defaults$2 = getDefaults();
246
+ let defaults$3 = getDefaults();
160
247
  function changeDefaults(newDefaults) {
161
- defaults$2 = newDefaults;
248
+ defaults$3 = newDefaults;
162
249
  }
163
250
  const escapeTest = /[&<>"']/;
164
251
  const escapeReplace = /[&<>"']/g;
@@ -381,15 +468,14 @@ function outputLink(cap, link, raw, lexer) {
381
468
  };
382
469
  lexer.state.inLink = false;
383
470
  return token;
384
- } else {
385
- return {
386
- type: "image",
387
- raw,
388
- href,
389
- title,
390
- text: escape(text)
391
- };
392
471
  }
472
+ return {
473
+ type: "image",
474
+ raw,
475
+ href,
476
+ title,
477
+ text: escape(text)
478
+ };
393
479
  }
394
480
  function indentCodeCompensation(raw, text) {
395
481
  const matchIndentToCode = raw.match(/^(\s+)(?:```)/);
@@ -411,7 +497,7 @@ function indentCodeCompensation(raw, text) {
411
497
  }
412
498
  class Tokenizer {
413
499
  constructor(options) {
414
- this.options = options || defaults$2;
500
+ this.options = options || defaults$3;
415
501
  }
416
502
  space(src) {
417
503
  const cap = this.rules.block.newline.exec(src);
@@ -538,7 +624,8 @@ class Tokenizer {
538
624
  endEarly = true;
539
625
  }
540
626
  if (!endEarly) {
541
- const nextBulletRegex = new RegExp(`^ {0,${Math.min(3, indent - 1)}}(?:[*+-]|\\d{1,9}[.)])`);
627
+ const nextBulletRegex = new RegExp(`^ {0,${Math.min(3, indent - 1)}}(?:[*+-]|\\d{1,9}[.)])((?: [^\\n]*)?(?:\\n|$))`);
628
+ const hrRegex = new RegExp(`^ {0,${Math.min(3, indent - 1)}}((?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$)`);
542
629
  while (src) {
543
630
  rawLine = src.split("\n", 1)[0];
544
631
  line = rawLine;
@@ -548,6 +635,9 @@ class Tokenizer {
548
635
  if (nextBulletRegex.test(line)) {
549
636
  break;
550
637
  }
638
+ if (hrRegex.test(src)) {
639
+ break;
640
+ }
551
641
  if (line.search(/[^ ]/) >= indent || !line.trim()) {
552
642
  itemContents += "\n" + line.slice(indent);
553
643
  } else if (!blankLine) {
@@ -683,14 +773,14 @@ class Tokenizer {
683
773
  l = item.header.length;
684
774
  for (j = 0; j < l; j++) {
685
775
  item.header[j].tokens = [];
686
- this.lexer.inlineTokens(item.header[j].text, item.header[j].tokens);
776
+ this.lexer.inline(item.header[j].text, item.header[j].tokens);
687
777
  }
688
778
  l = item.rows.length;
689
779
  for (j = 0; j < l; j++) {
690
780
  row = item.rows[j];
691
781
  for (k = 0; k < row.length; k++) {
692
782
  row[k].tokens = [];
693
- this.lexer.inlineTokens(row[k].text, row[k].tokens);
783
+ this.lexer.inline(row[k].text, row[k].tokens);
694
784
  }
695
785
  }
696
786
  return item;
@@ -1126,7 +1216,7 @@ class Lexer {
1126
1216
  constructor(options) {
1127
1217
  this.tokens = [];
1128
1218
  this.tokens.links = /* @__PURE__ */ Object.create(null);
1129
- this.options = options || defaults$2;
1219
+ this.options = options || defaults$3;
1130
1220
  this.options.tokenizer = this.options.tokenizer || new Tokenizer();
1131
1221
  this.tokenizer = this.options.tokenizer;
1132
1222
  this.tokenizer.options = this.options;
@@ -1474,7 +1564,7 @@ class Lexer {
1474
1564
  }
1475
1565
  class Renderer {
1476
1566
  constructor(options) {
1477
- this.options = options || defaults$2;
1567
+ this.options = options || defaults$3;
1478
1568
  }
1479
1569
  code(code, infostring, escaped) {
1480
1570
  const lang = (infostring || "").match(/\S*/)[0];
@@ -1644,7 +1734,7 @@ class Slugger {
1644
1734
  }
1645
1735
  class Parser {
1646
1736
  constructor(options) {
1647
- this.options = options || defaults$2;
1737
+ this.options = options || defaults$3;
1648
1738
  this.options.renderer = this.options.renderer || new Renderer();
1649
1739
  this.renderer = this.options.renderer;
1650
1740
  this.renderer.options = this.options;
@@ -1935,7 +2025,7 @@ marked$1.options = marked$1.setOptions = function(opt) {
1935
2025
  return marked$1;
1936
2026
  };
1937
2027
  marked$1.getDefaults = getDefaults;
1938
- marked$1.defaults = defaults$2;
2028
+ marked$1.defaults = defaults$3;
1939
2029
  marked$1.use = function(...args) {
1940
2030
  const opts = merge({}, ...args);
1941
2031
  const extensions = marked$1.defaults.extensions || { renderers: {}, childTokens: {} };
@@ -2097,6 +2187,11 @@ marked$1.lexer = Lexer.lex;
2097
2187
  marked$1.Tokenizer = Tokenizer;
2098
2188
  marked$1.Slugger = Slugger;
2099
2189
  marked$1.parse = marked$1;
2190
+ marked$1.options;
2191
+ marked$1.setOptions;
2192
+ marked$1.use;
2193
+ marked$1.walkTokens;
2194
+ marked$1.parseInline;
2100
2195
  Parser.parse;
2101
2196
  Lexer.lex;
2102
2197
  var commonjsGlobal = typeof globalThis !== "undefined" ? globalThis : typeof window !== "undefined" ? window : typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : {};
@@ -2418,7 +2513,7 @@ function sanitizer$1(buffer, options) {
2418
2513
  }
2419
2514
  }
2420
2515
  var sanitizer_1 = sanitizer$1;
2421
- var defaults$1 = {
2516
+ var defaults$2 = {
2422
2517
  allowedAttributes: {
2423
2518
  a: ["href", "name", "target", "title", "aria-label"],
2424
2519
  iframe: ["allowfullscreen", "frameborder", "src"],
@@ -2474,19 +2569,19 @@ var defaults$1 = {
2474
2569
  ],
2475
2570
  filter: null
2476
2571
  };
2477
- var defaults_1 = defaults$1;
2572
+ var defaults_1 = defaults$2;
2478
2573
  var assign = assignment_1;
2479
2574
  var parser = parser_1;
2480
2575
  var sanitizer = sanitizer_1;
2481
- var defaults = defaults_1;
2576
+ var defaults$1 = defaults_1;
2482
2577
  function insane(html, options, strict) {
2483
2578
  var buffer = [];
2484
- var configuration = strict === true ? options : assign({}, defaults, options);
2579
+ var configuration = strict === true ? options : assign({}, defaults$1, options);
2485
2580
  var handler = sanitizer(buffer, configuration);
2486
2581
  parser(html, handler);
2487
2582
  return buffer.join("");
2488
2583
  }
2489
- insane.defaults = defaults;
2584
+ insane.defaults = defaults$1;
2490
2585
  var insane_1 = insane;
2491
2586
  var hanabi$1 = { exports: {} };
2492
2587
  (function(module, exports) {
@@ -2583,7 +2678,7 @@ function dateFormat(date) {
2583
2678
  const vYear = padWithZeros(date.getFullYear(), 2);
2584
2679
  return `${vYear}-${vMonth}-${vDay}`;
2585
2680
  }
2586
- function timeAgo(date) {
2681
+ function timeAgo(date, ctx) {
2587
2682
  try {
2588
2683
  const oldTime = date.getTime();
2589
2684
  const currTime = new Date().getTime();
@@ -2598,16 +2693,16 @@ function timeAgo(date) {
2598
2693
  if (minutes === 0) {
2599
2694
  const leave3 = leave2 % (60 * 1e3);
2600
2695
  const seconds = Math.round(leave3 / 1e3);
2601
- return `${seconds} \u79D2\u524D`;
2696
+ return `${seconds} ${ctx.$t("seconds")}`;
2602
2697
  }
2603
- return `${minutes} \u5206\u949F\u524D`;
2698
+ return `${minutes} ${ctx.$t("minutes")}`;
2604
2699
  }
2605
- return `${hours} \u5C0F\u65F6\u524D`;
2700
+ return `${hours} ${ctx.$t("hours")}`;
2606
2701
  }
2607
2702
  if (days < 0)
2608
- return "\u521A\u521A";
2703
+ return ctx.$t("now");
2609
2704
  if (days < 8) {
2610
- return `${days} \u5929\u524D`;
2705
+ return `${days} ${ctx.$t("days")}`;
2611
2706
  }
2612
2707
  return dateFormat(date);
2613
2708
  } catch (error) {
@@ -2637,8 +2732,7 @@ function onImagesLoaded($container, event) {
2637
2732
  }
2638
2733
  }
2639
2734
  function getGravatarURL(ctx, emailMD5) {
2640
- var _a, _b;
2641
- return `${(((_a = ctx.conf.gravatar) == null ? void 0 : _a.mirror) || "").replace(/\/$/, "")}/${emailMD5}?d=${encodeURIComponent(((_b = ctx.conf.gravatar) == null ? void 0 : _b.default) || "")}&s=80`;
2735
+ return `${ctx.conf.gravatar.mirror.replace(/\/$/, "")}/${emailMD5}?d=${encodeURIComponent(ctx.conf.gravatar.default)}&s=80`;
2642
2736
  }
2643
2737
  function versionCompare(a, b) {
2644
2738
  const pa = a.split(".");
@@ -2658,6 +2752,12 @@ function versionCompare(a, b) {
2658
2752
  return 0;
2659
2753
  }
2660
2754
  function initMarked(ctx) {
2755
+ try {
2756
+ if (!marked$1.name)
2757
+ return;
2758
+ } catch (e) {
2759
+ return;
2760
+ }
2661
2761
  const renderer = new marked$1.Renderer();
2662
2762
  const orgLinkRenderer = renderer.link;
2663
2763
  renderer.link = (href, title, text) => {
@@ -2694,7 +2794,12 @@ function initMarked(ctx) {
2694
2794
  ctx.markedInstance = nMarked;
2695
2795
  }
2696
2796
  function marked(ctx, src) {
2697
- let dest = insane_1(ctx.markedInstance.parse(src), {
2797
+ var _a;
2798
+ let markedContent = (_a = ctx.markedInstance) == null ? void 0 : _a.parse(src);
2799
+ if (!markedContent) {
2800
+ markedContent = src.replace(/```\s*([^]+?.*?[^]+?[^]+?)```/g, (_, code) => `<pre><code>${hanabi(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>");
2801
+ }
2802
+ let dest = insane_1(markedContent, {
2698
2803
  allowedClasses: {},
2699
2804
  allowedSchemes: ["http", "https", "mailto"],
2700
2805
  allowedTags: [
@@ -2834,8 +2939,6 @@ function mergeDeep(target, source) {
2834
2939
  return target;
2835
2940
  }
2836
2941
  function showLoading(parentElem, conf) {
2837
- if (parentElem instanceof Context)
2838
- parentElem = parentElem.$root;
2839
2942
  let $loading = parentElem.querySelector(".atk-loading");
2840
2943
  if (!$loading) {
2841
2944
  $loading = createElement(`<div class="atk-loading atk-fade-in" style="display: none;">
@@ -2857,8 +2960,6 @@ function showLoading(parentElem, conf) {
2857
2960
  }
2858
2961
  }
2859
2962
  function hideLoading(parentElem) {
2860
- if (parentElem instanceof Context)
2861
- parentElem = parentElem.$root;
2862
2963
  const $loading = parentElem.querySelector(".atk-loading");
2863
2964
  if ($loading)
2864
2965
  $loading.style.display = "none";
@@ -2921,8 +3022,6 @@ function playFadeInAnim(elem, after) {
2921
3022
  playFadeAnim(elem, after, "in");
2922
3023
  }
2923
3024
  function setError(parentElem, html, title = '<span class="atk-error-title">Artalk Error</span>') {
2924
- if (parentElem instanceof Context)
2925
- parentElem = parentElem.$root;
2926
3025
  let elem = parentElem.querySelector(".atk-error-layer");
2927
3026
  if (html === null) {
2928
3027
  if (elem !== null)
@@ -3081,102 +3180,56 @@ function GetLayerWrap(ctx) {
3081
3180
  const $mask = $wrap.querySelector(".atk-layer-mask");
3082
3181
  return { $wrap, $mask };
3083
3182
  }
3084
- class Dialog {
3085
- constructor(contentEl) {
3086
- __publicField(this, "$el");
3087
- __publicField(this, "$content");
3088
- __publicField(this, "$actions");
3089
- this.$el = createElement(`<div class="atk-layer-dialog-wrap">
3090
- <div class="atk-layer-dialog">
3091
- <div class="atk-layer-dialog-content"></div>
3092
- <div class="atk-layer-dialog-actions"></div>
3093
- </div>
3094
- </div>`);
3095
- this.$actions = this.$el.querySelector(".atk-layer-dialog-actions");
3096
- this.$content = this.$el.querySelector(".atk-layer-dialog-content");
3097
- this.$content.appendChild(contentEl);
3098
- return this;
3099
- }
3100
- setYes(handler) {
3101
- const btn = createElement('<button data-action="confirm">\u786E\u5B9A</button>');
3102
- btn.onclick = this.onBtnClick(handler);
3103
- this.$actions.appendChild(btn);
3104
- return this;
3105
- }
3106
- setNo(handler) {
3107
- const btn = createElement('<button data-action="cancel">\u53D6\u6D88</button>');
3108
- btn.onclick = this.onBtnClick(handler);
3109
- this.$actions.appendChild(btn);
3110
- return this;
3111
- }
3112
- onBtnClick(handler) {
3113
- return (evt) => {
3114
- const re = handler(evt.currentTarget, this);
3115
- if (re === void 0 || re === true) {
3116
- this.$el.remove();
3117
- }
3118
- };
3119
- }
3120
- }
3121
3183
  function Fetch(ctx, input, init, timeout) {
3122
3184
  return __async(this, null, function* () {
3185
+ var _a, _b;
3123
3186
  if (ctx.user.data.token) {
3124
- const requestHeaders = new Headers();
3125
- requestHeaders.set("Authorization", `Bearer ${ctx.user.data.token}`);
3126
- init.headers = requestHeaders;
3127
- }
3128
- try {
3129
- let resp;
3130
- if (typeof timeout !== "number" && ctx.conf.reqTimeout === 0 || timeout === 0) {
3131
- resp = yield fetch(input, init);
3132
- } else {
3133
- resp = yield timeoutPromise(timeout || ctx.conf.reqTimeout || 15e3, fetch(input, init));
3134
- }
3135
- const noAccessCodes = [401, 400];
3136
- if (!resp.ok && !noAccessCodes.includes(resp.status))
3137
- throw new Error(`\u8BF7\u6C42\u54CD\u5E94 ${resp.status}`);
3138
- let json = yield resp.json();
3139
- const recall = (resolve, reject) => {
3140
- Fetch(ctx, input, init).then((d) => {
3141
- resolve(d);
3142
- }).catch((err) => {
3143
- reject(err);
3144
- });
3145
- };
3146
- if (json.data && json.data.need_captcha) {
3147
- json = yield new Promise((resolve, reject) => {
3148
- ctx.trigger("checker-captcha", {
3149
- imgData: json.data.img_data,
3150
- iframe: json.data.iframe,
3151
- onSuccess: () => {
3152
- recall(resolve, reject);
3153
- },
3154
- onCancel: () => {
3155
- reject(json);
3156
- }
3157
- });
3187
+ const headers = new Headers(init.headers);
3188
+ headers.set("Authorization", `Bearer ${ctx.user.data.token}`);
3189
+ init.headers = headers;
3190
+ }
3191
+ const resp = yield timeoutFetch(ctx, input, timeout || ctx.conf.reqTimeout || 15e3, init);
3192
+ const respHttpCode = resp.status;
3193
+ const noAccessCodes = [401, 400];
3194
+ const isNoAccess = noAccessCodes.includes(respHttpCode);
3195
+ if (!resp.ok && !isNoAccess)
3196
+ throw new Error(`${ctx.$t("reqGot")} ${respHttpCode}`);
3197
+ let json = yield resp.json();
3198
+ const recall = (resolve, reject) => {
3199
+ Fetch(ctx, input, init).then((d) => {
3200
+ resolve(d);
3201
+ }).catch((e) => {
3202
+ reject(e);
3203
+ });
3204
+ };
3205
+ if ((_a = json.data) == null ? void 0 : _a.need_captcha) {
3206
+ json = yield new Promise((resolve, reject) => {
3207
+ ctx.checkCaptcha({
3208
+ imgData: json.data.img_data,
3209
+ iframe: json.data.iframe,
3210
+ onSuccess: () => {
3211
+ recall(resolve, reject);
3212
+ },
3213
+ onCancel: () => {
3214
+ reject(json);
3215
+ }
3158
3216
  });
3159
- } else if (json.data && json.data.need_login || noAccessCodes.includes(resp.status)) {
3160
- json = yield new Promise((resolve, reject) => {
3161
- ctx.trigger("checker-admin", {
3162
- onSuccess: () => {
3163
- recall(resolve, reject);
3164
- },
3165
- onCancel: () => {
3166
- reject(json);
3167
- }
3168
- });
3217
+ });
3218
+ } else if (((_b = json.data) == null ? void 0 : _b.need_login) || isNoAccess) {
3219
+ json = yield new Promise((resolve, reject) => {
3220
+ ctx.checkAdmin({
3221
+ onSuccess: () => {
3222
+ recall(resolve, reject);
3223
+ },
3224
+ onCancel: () => {
3225
+ reject(json);
3226
+ }
3169
3227
  });
3170
- }
3171
- if (!json.success)
3172
- throw json;
3173
- return json;
3174
- } catch (err) {
3175
- console.error(err);
3176
- if (err instanceof TypeError)
3177
- throw new Error(`\u7F51\u7EDC\u9519\u8BEF`);
3178
- throw err;
3228
+ });
3179
3229
  }
3230
+ if (!json.success)
3231
+ throw json;
3232
+ return json;
3180
3233
  });
3181
3234
  }
3182
3235
  function POST(ctx, url, data) {
@@ -3195,20 +3248,390 @@ function ToFormData(object) {
3195
3248
  Object.keys(object).forEach((key) => formData.append(key, String(object[key])));
3196
3249
  return formData;
3197
3250
  }
3198
- function timeoutPromise(ms, promise) {
3199
- return new Promise((resolve, reject) => {
3200
- const timeoutId = setTimeout(() => {
3201
- reject(new Error("\u8BF7\u6C42\u8D85\u65F6"));
3202
- }, ms);
3203
- promise.then((res) => {
3204
- clearTimeout(timeoutId);
3205
- resolve(res);
3206
- }, (err) => {
3207
- clearTimeout(timeoutId);
3208
- reject(err);
3251
+ function timeoutFetch(ctx, url, ms, opts) {
3252
+ var _a;
3253
+ const controller = new AbortController();
3254
+ (_a = opts.signal) == null ? void 0 : _a.addEventListener("abort", () => controller.abort());
3255
+ let promise = fetch(url, __spreadProps(__spreadValues({}, opts), { signal: controller.signal }));
3256
+ if (ms > 0) {
3257
+ const timer = setTimeout(() => controller.abort(), ms);
3258
+ promise.finally(() => {
3259
+ clearTimeout(timer);
3209
3260
  });
3261
+ }
3262
+ promise = promise.catch((err) => {
3263
+ throw (err || {}).name === "AbortError" ? new Error(ctx.$t("reqAborted")) : err;
3210
3264
  });
3265
+ return promise;
3211
3266
  }
3267
+ (function(factory) {
3268
+ factory();
3269
+ })(function() {
3270
+ function _classCallCheck(instance, Constructor) {
3271
+ if (!(instance instanceof Constructor)) {
3272
+ throw new TypeError("Cannot call a class as a function");
3273
+ }
3274
+ }
3275
+ function _defineProperties(target, props) {
3276
+ for (var i = 0; i < props.length; i++) {
3277
+ var descriptor = props[i];
3278
+ descriptor.enumerable = descriptor.enumerable || false;
3279
+ descriptor.configurable = true;
3280
+ if ("value" in descriptor)
3281
+ descriptor.writable = true;
3282
+ Object.defineProperty(target, descriptor.key, descriptor);
3283
+ }
3284
+ }
3285
+ function _createClass(Constructor, protoProps, staticProps) {
3286
+ if (protoProps)
3287
+ _defineProperties(Constructor.prototype, protoProps);
3288
+ if (staticProps)
3289
+ _defineProperties(Constructor, staticProps);
3290
+ return Constructor;
3291
+ }
3292
+ function _inherits(subClass, superClass) {
3293
+ if (typeof superClass !== "function" && superClass !== null) {
3294
+ throw new TypeError("Super expression must either be null or a function");
3295
+ }
3296
+ subClass.prototype = Object.create(superClass && superClass.prototype, {
3297
+ constructor: {
3298
+ value: subClass,
3299
+ writable: true,
3300
+ configurable: true
3301
+ }
3302
+ });
3303
+ if (superClass)
3304
+ _setPrototypeOf(subClass, superClass);
3305
+ }
3306
+ function _getPrototypeOf(o) {
3307
+ _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf2(o2) {
3308
+ return o2.__proto__ || Object.getPrototypeOf(o2);
3309
+ };
3310
+ return _getPrototypeOf(o);
3311
+ }
3312
+ function _setPrototypeOf(o, p) {
3313
+ _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf2(o2, p2) {
3314
+ o2.__proto__ = p2;
3315
+ return o2;
3316
+ };
3317
+ return _setPrototypeOf(o, p);
3318
+ }
3319
+ function _isNativeReflectConstruct() {
3320
+ if (typeof Reflect === "undefined" || !Reflect.construct)
3321
+ return false;
3322
+ if (Reflect.construct.sham)
3323
+ return false;
3324
+ if (typeof Proxy === "function")
3325
+ return true;
3326
+ try {
3327
+ Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function() {
3328
+ }));
3329
+ return true;
3330
+ } catch (e) {
3331
+ return false;
3332
+ }
3333
+ }
3334
+ function _assertThisInitialized(self2) {
3335
+ if (self2 === void 0) {
3336
+ throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
3337
+ }
3338
+ return self2;
3339
+ }
3340
+ function _possibleConstructorReturn(self2, call) {
3341
+ if (call && (typeof call === "object" || typeof call === "function")) {
3342
+ return call;
3343
+ }
3344
+ return _assertThisInitialized(self2);
3345
+ }
3346
+ function _createSuper(Derived) {
3347
+ var hasNativeReflectConstruct = _isNativeReflectConstruct();
3348
+ return function _createSuperInternal() {
3349
+ var Super = _getPrototypeOf(Derived), result;
3350
+ if (hasNativeReflectConstruct) {
3351
+ var NewTarget = _getPrototypeOf(this).constructor;
3352
+ result = Reflect.construct(Super, arguments, NewTarget);
3353
+ } else {
3354
+ result = Super.apply(this, arguments);
3355
+ }
3356
+ return _possibleConstructorReturn(this, result);
3357
+ };
3358
+ }
3359
+ function _superPropBase(object, property) {
3360
+ while (!Object.prototype.hasOwnProperty.call(object, property)) {
3361
+ object = _getPrototypeOf(object);
3362
+ if (object === null)
3363
+ break;
3364
+ }
3365
+ return object;
3366
+ }
3367
+ function _get(target, property, receiver) {
3368
+ if (typeof Reflect !== "undefined" && Reflect.get) {
3369
+ _get = Reflect.get;
3370
+ } else {
3371
+ _get = function _get2(target2, property2, receiver2) {
3372
+ var base = _superPropBase(target2, property2);
3373
+ if (!base)
3374
+ return;
3375
+ var desc = Object.getOwnPropertyDescriptor(base, property2);
3376
+ if (desc.get) {
3377
+ return desc.get.call(receiver2);
3378
+ }
3379
+ return desc.value;
3380
+ };
3381
+ }
3382
+ return _get(target, property, receiver || target);
3383
+ }
3384
+ var Emitter = /* @__PURE__ */ function() {
3385
+ function Emitter2() {
3386
+ _classCallCheck(this, Emitter2);
3387
+ Object.defineProperty(this, "listeners", {
3388
+ value: {},
3389
+ writable: true,
3390
+ configurable: true
3391
+ });
3392
+ }
3393
+ _createClass(Emitter2, [{
3394
+ key: "addEventListener",
3395
+ value: function addEventListener(type, callback, options) {
3396
+ if (!(type in this.listeners)) {
3397
+ this.listeners[type] = [];
3398
+ }
3399
+ this.listeners[type].push({
3400
+ callback,
3401
+ options
3402
+ });
3403
+ }
3404
+ }, {
3405
+ key: "removeEventListener",
3406
+ value: function removeEventListener(type, callback) {
3407
+ if (!(type in this.listeners)) {
3408
+ return;
3409
+ }
3410
+ var stack = this.listeners[type];
3411
+ for (var i = 0, l = stack.length; i < l; i++) {
3412
+ if (stack[i].callback === callback) {
3413
+ stack.splice(i, 1);
3414
+ return;
3415
+ }
3416
+ }
3417
+ }
3418
+ }, {
3419
+ key: "dispatchEvent",
3420
+ value: function dispatchEvent(event) {
3421
+ if (!(event.type in this.listeners)) {
3422
+ return;
3423
+ }
3424
+ var stack = this.listeners[event.type];
3425
+ var stackToCall = stack.slice();
3426
+ for (var i = 0, l = stackToCall.length; i < l; i++) {
3427
+ var listener = stackToCall[i];
3428
+ try {
3429
+ listener.callback.call(this, event);
3430
+ } catch (e) {
3431
+ Promise.resolve().then(function() {
3432
+ throw e;
3433
+ });
3434
+ }
3435
+ if (listener.options && listener.options.once) {
3436
+ this.removeEventListener(event.type, listener.callback);
3437
+ }
3438
+ }
3439
+ return !event.defaultPrevented;
3440
+ }
3441
+ }]);
3442
+ return Emitter2;
3443
+ }();
3444
+ var AbortSignal = /* @__PURE__ */ function(_Emitter) {
3445
+ _inherits(AbortSignal2, _Emitter);
3446
+ var _super = _createSuper(AbortSignal2);
3447
+ function AbortSignal2() {
3448
+ var _this;
3449
+ _classCallCheck(this, AbortSignal2);
3450
+ _this = _super.call(this);
3451
+ if (!_this.listeners) {
3452
+ Emitter.call(_assertThisInitialized(_this));
3453
+ }
3454
+ Object.defineProperty(_assertThisInitialized(_this), "aborted", {
3455
+ value: false,
3456
+ writable: true,
3457
+ configurable: true
3458
+ });
3459
+ Object.defineProperty(_assertThisInitialized(_this), "onabort", {
3460
+ value: null,
3461
+ writable: true,
3462
+ configurable: true
3463
+ });
3464
+ return _this;
3465
+ }
3466
+ _createClass(AbortSignal2, [{
3467
+ key: "toString",
3468
+ value: function toString() {
3469
+ return "[object AbortSignal]";
3470
+ }
3471
+ }, {
3472
+ key: "dispatchEvent",
3473
+ value: function dispatchEvent(event) {
3474
+ if (event.type === "abort") {
3475
+ this.aborted = true;
3476
+ if (typeof this.onabort === "function") {
3477
+ this.onabort.call(this, event);
3478
+ }
3479
+ }
3480
+ _get(_getPrototypeOf(AbortSignal2.prototype), "dispatchEvent", this).call(this, event);
3481
+ }
3482
+ }]);
3483
+ return AbortSignal2;
3484
+ }(Emitter);
3485
+ var AbortController2 = /* @__PURE__ */ function() {
3486
+ function AbortController3() {
3487
+ _classCallCheck(this, AbortController3);
3488
+ Object.defineProperty(this, "signal", {
3489
+ value: new AbortSignal(),
3490
+ writable: true,
3491
+ configurable: true
3492
+ });
3493
+ }
3494
+ _createClass(AbortController3, [{
3495
+ key: "abort",
3496
+ value: function abort() {
3497
+ var event;
3498
+ try {
3499
+ event = new Event("abort");
3500
+ } catch (e) {
3501
+ if (typeof document !== "undefined") {
3502
+ if (!document.createEvent) {
3503
+ event = document.createEventObject();
3504
+ event.type = "abort";
3505
+ } else {
3506
+ event = document.createEvent("Event");
3507
+ event.initEvent("abort", false, false);
3508
+ }
3509
+ } else {
3510
+ event = {
3511
+ type: "abort",
3512
+ bubbles: false,
3513
+ cancelable: false
3514
+ };
3515
+ }
3516
+ }
3517
+ this.signal.dispatchEvent(event);
3518
+ }
3519
+ }, {
3520
+ key: "toString",
3521
+ value: function toString() {
3522
+ return "[object AbortController]";
3523
+ }
3524
+ }]);
3525
+ return AbortController3;
3526
+ }();
3527
+ if (typeof Symbol !== "undefined" && Symbol.toStringTag) {
3528
+ AbortController2.prototype[Symbol.toStringTag] = "AbortController";
3529
+ AbortSignal.prototype[Symbol.toStringTag] = "AbortSignal";
3530
+ }
3531
+ function polyfillNeeded(self2) {
3532
+ if (self2.__FORCE_INSTALL_ABORTCONTROLLER_POLYFILL) {
3533
+ console.log("__FORCE_INSTALL_ABORTCONTROLLER_POLYFILL=true is set, will force install polyfill");
3534
+ return true;
3535
+ }
3536
+ return typeof self2.Request === "function" && !self2.Request.prototype.hasOwnProperty("signal") || !self2.AbortController;
3537
+ }
3538
+ function abortableFetchDecorator(patchTargets) {
3539
+ if (typeof patchTargets === "function") {
3540
+ patchTargets = {
3541
+ fetch: patchTargets
3542
+ };
3543
+ }
3544
+ var _patchTargets = patchTargets, fetch2 = _patchTargets.fetch, _patchTargets$Request = _patchTargets.Request, NativeRequest = _patchTargets$Request === void 0 ? fetch2.Request : _patchTargets$Request, NativeAbortController = _patchTargets.AbortController, _patchTargets$__FORCE = _patchTargets.__FORCE_INSTALL_ABORTCONTROLLER_POLYFILL, __FORCE_INSTALL_ABORTCONTROLLER_POLYFILL = _patchTargets$__FORCE === void 0 ? false : _patchTargets$__FORCE;
3545
+ if (!polyfillNeeded({
3546
+ fetch: fetch2,
3547
+ Request: NativeRequest,
3548
+ AbortController: NativeAbortController,
3549
+ __FORCE_INSTALL_ABORTCONTROLLER_POLYFILL
3550
+ })) {
3551
+ return {
3552
+ fetch: fetch2,
3553
+ Request
3554
+ };
3555
+ }
3556
+ var Request = NativeRequest;
3557
+ if (Request && !Request.prototype.hasOwnProperty("signal") || __FORCE_INSTALL_ABORTCONTROLLER_POLYFILL) {
3558
+ Request = function Request2(input, init) {
3559
+ var signal;
3560
+ if (init && init.signal) {
3561
+ signal = init.signal;
3562
+ delete init.signal;
3563
+ }
3564
+ var request = new NativeRequest(input, init);
3565
+ if (signal) {
3566
+ Object.defineProperty(request, "signal", {
3567
+ writable: false,
3568
+ enumerable: false,
3569
+ configurable: true,
3570
+ value: signal
3571
+ });
3572
+ }
3573
+ return request;
3574
+ };
3575
+ Request.prototype = NativeRequest.prototype;
3576
+ }
3577
+ var realFetch = fetch2;
3578
+ var abortableFetch = function abortableFetch2(input, init) {
3579
+ var signal = Request && Request.prototype.isPrototypeOf(input) ? input.signal : init ? init.signal : void 0;
3580
+ if (signal) {
3581
+ var abortError;
3582
+ try {
3583
+ abortError = new DOMException("Aborted", "AbortError");
3584
+ } catch (err) {
3585
+ abortError = new Error("Aborted");
3586
+ abortError.name = "AbortError";
3587
+ }
3588
+ if (signal.aborted) {
3589
+ return Promise.reject(abortError);
3590
+ }
3591
+ var cancellation = new Promise(function(_, reject) {
3592
+ signal.addEventListener("abort", function() {
3593
+ return reject(abortError);
3594
+ }, {
3595
+ once: true
3596
+ });
3597
+ });
3598
+ if (init && init.signal) {
3599
+ delete init.signal;
3600
+ }
3601
+ return Promise.race([cancellation, realFetch(input, init)]);
3602
+ }
3603
+ return realFetch(input, init);
3604
+ };
3605
+ return {
3606
+ fetch: abortableFetch,
3607
+ Request
3608
+ };
3609
+ }
3610
+ (function(self2) {
3611
+ if (!polyfillNeeded(self2)) {
3612
+ return;
3613
+ }
3614
+ if (!self2.fetch) {
3615
+ console.warn("fetch() is not available, cannot install abortcontroller-polyfill");
3616
+ return;
3617
+ }
3618
+ var _abortableFetch = abortableFetchDecorator(self2), fetch2 = _abortableFetch.fetch, Request = _abortableFetch.Request;
3619
+ self2.fetch = fetch2;
3620
+ self2.Request = Request;
3621
+ Object.defineProperty(self2, "AbortController", {
3622
+ writable: true,
3623
+ enumerable: false,
3624
+ configurable: true,
3625
+ value: AbortController2
3626
+ });
3627
+ Object.defineProperty(self2, "AbortSignal", {
3628
+ writable: true,
3629
+ enumerable: false,
3630
+ configurable: true,
3631
+ value: AbortSignal
3632
+ });
3633
+ })(typeof self !== "undefined" ? self : commonjsGlobal);
3634
+ });
3212
3635
  class Api {
3213
3636
  constructor(ctx) {
3214
3637
  __publicField(this, "ctx");
@@ -3281,7 +3704,6 @@ class Api {
3281
3704
  }
3282
3705
  userGet(name, email) {
3283
3706
  const ctrl = new AbortController();
3284
- const { signal } = ctrl;
3285
3707
  const params = {
3286
3708
  name,
3287
3709
  email,
@@ -3290,7 +3712,7 @@ class Api {
3290
3712
  const req = Fetch(this.ctx, `${this.baseURL}/user-get`, {
3291
3713
  method: "POST",
3292
3714
  body: ToFormData(params),
3293
- signal
3715
+ signal: ctrl.signal
3294
3716
  }).then((json) => ({
3295
3717
  user: json.data.user,
3296
3718
  is_login: json.data.is_login,
@@ -3435,14 +3857,28 @@ class Api {
3435
3857
  return p.pv;
3436
3858
  });
3437
3859
  }
3438
- imgUpload(file) {
3860
+ stat(type, pageKeys, limit) {
3439
3861
  return __async(this, null, function* () {
3440
3862
  const params = {
3441
- name: this.ctx.user.data.nick,
3442
- email: this.ctx.user.data.email,
3443
- page_key: this.ctx.conf.pageKey
3863
+ type,
3864
+ site_name: this.ctx.conf.site || ""
3444
3865
  };
3445
- if (this.ctx.conf.site)
3866
+ if (pageKeys)
3867
+ params.page_keys = Array.isArray(pageKeys) ? pageKeys.join(",") : pageKeys;
3868
+ if (limit)
3869
+ params.limit = limit;
3870
+ const data = yield POST(this.ctx, `${this.baseURL}/stat`, params);
3871
+ return data;
3872
+ });
3873
+ }
3874
+ imgUpload(file) {
3875
+ return __async(this, null, function* () {
3876
+ const params = {
3877
+ name: this.ctx.user.data.nick,
3878
+ email: this.ctx.user.data.email,
3879
+ page_key: this.ctx.conf.pageKey
3880
+ };
3881
+ if (this.ctx.conf.site)
3446
3882
  params.site_name = this.ctx.conf.site;
3447
3883
  const form = ToFormData(params);
3448
3884
  form.set("file", file);
@@ -3462,6 +3898,8 @@ class Api {
3462
3898
  conf.emoticons = conf.emoticons.trim();
3463
3899
  if (conf.emoticons.startsWith("[") || conf.emoticons.startsWith("{")) {
3464
3900
  conf.emoticons = JSON.parse(conf.emoticons);
3901
+ } else if (conf.emoticons === "false") {
3902
+ conf.emoticons = false;
3465
3903
  }
3466
3904
  }
3467
3905
  return conf;
@@ -3494,9 +3932,251 @@ class Api {
3494
3932
  return POST(this.ctx, `${this.baseURL}/admin/cache-warm`, params);
3495
3933
  }
3496
3934
  }
3935
+ class Context {
3936
+ constructor(conf, $root) {
3937
+ __publicField(this, "api");
3938
+ __publicField(this, "editor");
3939
+ __publicField(this, "list");
3940
+ __publicField(this, "sidebarLayer");
3941
+ __publicField(this, "checkerLauncher");
3942
+ __publicField(this, "cid");
3943
+ __publicField(this, "conf");
3944
+ __publicField(this, "user");
3945
+ __publicField(this, "$root");
3946
+ __publicField(this, "markedInstance");
3947
+ __publicField(this, "markedReplacers", []);
3948
+ __publicField(this, "commentList", []);
3949
+ __publicField(this, "eventList", []);
3950
+ this.cid = +new Date();
3951
+ this.conf = conf;
3952
+ this.user = new User(this);
3953
+ this.$root = $root || document.createElement("div");
3954
+ this.$root.setAttribute("atk-run-id", this.cid.toString());
3955
+ this.$root.classList.add("artalk");
3956
+ this.$root.innerHTML = "";
3957
+ this.api = new Api(this);
3958
+ }
3959
+ setApi(api) {
3960
+ this.api = api;
3961
+ }
3962
+ setEditor(editor2) {
3963
+ this.editor = editor2;
3964
+ }
3965
+ setList(list2) {
3966
+ this.list = list2;
3967
+ }
3968
+ setSidebarLayer(sidebarLayer2) {
3969
+ this.sidebarLayer = sidebarLayer2;
3970
+ }
3971
+ setCheckerLauncher(checkerLauncher) {
3972
+ this.checkerLauncher = checkerLauncher;
3973
+ }
3974
+ getApi() {
3975
+ return this.api;
3976
+ }
3977
+ getCommentList() {
3978
+ return this.commentList;
3979
+ }
3980
+ getCommentDataList() {
3981
+ return this.commentList.map((c) => c.getData());
3982
+ }
3983
+ findComment(id) {
3984
+ return this.commentList.find((c) => c.getData().id === id);
3985
+ }
3986
+ deleteComment(_comment) {
3987
+ let comment2;
3988
+ if (typeof _comment === "number") {
3989
+ const findComment = this.findComment(_comment);
3990
+ if (!findComment)
3991
+ throw Error(`Comment ${_comment} cannot be found`);
3992
+ comment2 = findComment;
3993
+ } else
3994
+ comment2 = _comment;
3995
+ comment2.getEl().remove();
3996
+ this.commentList.splice(this.commentList.indexOf(comment2), 1);
3997
+ const listData = this.list.getData();
3998
+ if (listData)
3999
+ listData.total -= 1;
4000
+ this.list.refreshUI();
4001
+ }
4002
+ clearAllComments() {
4003
+ this.list.getCommentsWrapEl().innerHTML = "";
4004
+ this.list.clearData();
4005
+ this.commentList = [];
4006
+ }
4007
+ insertComment(commentData) {
4008
+ this.list.insertComment(commentData);
4009
+ }
4010
+ replyComment(commentData, $comment, scroll) {
4011
+ this.editor.setReply(commentData, $comment, scroll);
4012
+ }
4013
+ cancelReplyComment() {
4014
+ this.editor.cancelReply();
4015
+ }
4016
+ updateNotifies(notifies) {
4017
+ this.list.updateUnread(notifies);
4018
+ }
4019
+ listReload() {
4020
+ this.list.reload();
4021
+ }
4022
+ listRefreshUI() {
4023
+ this.list.refreshUI();
4024
+ }
4025
+ editorOpen() {
4026
+ this.editor.open();
4027
+ }
4028
+ editorClose() {
4029
+ this.editor.close();
4030
+ }
4031
+ editorShowLoading() {
4032
+ this.editor.showLoading();
4033
+ }
4034
+ editorHideLoading() {
4035
+ this.editor.hideLoading();
4036
+ }
4037
+ editorShowNotify(msg, type) {
4038
+ this.editor.showNotify(msg, type);
4039
+ }
4040
+ editorTravel($el) {
4041
+ this.editor.travel($el);
4042
+ }
4043
+ editorTravelBack() {
4044
+ this.editor.travelBack();
4045
+ }
4046
+ showSidebar(payload) {
4047
+ this.sidebarLayer.show(payload);
4048
+ }
4049
+ hideSidebar() {
4050
+ this.sidebarLayer.hide();
4051
+ }
4052
+ checkAdmin(payload) {
4053
+ this.checkerLauncher.checkAdmin(payload);
4054
+ }
4055
+ checkCaptcha(payload) {
4056
+ this.checkerLauncher.checkCaptcha(payload);
4057
+ }
4058
+ checkAdminShowEl() {
4059
+ const items = [];
4060
+ this.$root.querySelectorAll(`[atk-only-admin-show]`).forEach((item) => items.push(item));
4061
+ const { $wrap: $layerWrap } = GetLayerWrap(this);
4062
+ if ($layerWrap)
4063
+ $layerWrap.querySelectorAll(`[atk-only-admin-show]`).forEach((item) => items.push(item));
4064
+ const $sidebarEl = document.querySelector(".atk-sidebar");
4065
+ if ($sidebarEl)
4066
+ $sidebarEl.querySelectorAll(`[atk-only-admin-show]`).forEach((item) => items.push(item));
4067
+ items.forEach(($item) => {
4068
+ if (this.user.data.isAdmin)
4069
+ $item.classList.remove("atk-hide");
4070
+ else
4071
+ $item.classList.add("atk-hide");
4072
+ });
4073
+ }
4074
+ on(name, handler, scope = "internal") {
4075
+ this.eventList.push({ name, handler, scope });
4076
+ }
4077
+ off(name, handler, scope = "internal") {
4078
+ this.eventList = this.eventList.filter((evt) => {
4079
+ if (handler)
4080
+ return !(evt.name === name && evt.handler === handler && evt.scope === scope);
4081
+ return !(evt.name === name && evt.scope === scope);
4082
+ });
4083
+ }
4084
+ trigger(name, payload, scope) {
4085
+ this.eventList.filter((evt) => evt.name === name && (scope ? evt.scope === scope : true)).map((evt) => evt.handler).forEach((handler) => handler(payload));
4086
+ }
4087
+ $t(key, args = {}) {
4088
+ let locales = this.conf.locale;
4089
+ if (typeof locales === "string") {
4090
+ locales = internal[locales];
4091
+ }
4092
+ let str = (locales == null ? void 0 : locales[key]) || key;
4093
+ str = str.replace(/\{\s*(\w+?)\s*\}/g, (_, token) => args[token] || "");
4094
+ return str;
4095
+ }
4096
+ }
4097
+ const defaults = {
4098
+ el: "",
4099
+ pageKey: "",
4100
+ pageTitle: "",
4101
+ server: "",
4102
+ site: "",
4103
+ placeholder: "",
4104
+ noComment: "",
4105
+ sendBtn: "",
4106
+ darkMode: false,
4107
+ editorTravel: true,
4108
+ flatMode: "auto",
4109
+ nestMax: 2,
4110
+ nestSort: "DATE_ASC",
4111
+ emoticons: "https://cdn.jsdelivr.net/gh/ArtalkJS/Emoticons/grps/default.json",
4112
+ vote: true,
4113
+ voteDown: false,
4114
+ uaBadge: true,
4115
+ listSort: true,
4116
+ preview: true,
4117
+ countEl: "#ArtalkCount",
4118
+ pvEl: "#ArtalkPV",
4119
+ gravatar: {
4120
+ default: "mp",
4121
+ mirror: "https://sdn.geekzu.org/avatar/"
4122
+ },
4123
+ pagination: {
4124
+ pageSize: 20,
4125
+ readMore: true,
4126
+ autoLoad: true
4127
+ },
4128
+ heightLimit: {
4129
+ content: 300,
4130
+ children: 400
4131
+ },
4132
+ imgUpload: true,
4133
+ reqTimeout: 15e3,
4134
+ versionCheck: true,
4135
+ useBackendConf: false,
4136
+ locale: "zh-CN"
4137
+ };
4138
+ class Dialog {
4139
+ constructor(ctx, contentEl) {
4140
+ __publicField(this, "ctx");
4141
+ __publicField(this, "$el");
4142
+ __publicField(this, "$content");
4143
+ __publicField(this, "$actions");
4144
+ this.ctx = ctx;
4145
+ this.$el = createElement(`<div class="atk-layer-dialog-wrap">
4146
+ <div class="atk-layer-dialog">
4147
+ <div class="atk-layer-dialog-content"></div>
4148
+ <div class="atk-layer-dialog-actions"></div>
4149
+ </div>
4150
+ </div>`);
4151
+ this.$actions = this.$el.querySelector(".atk-layer-dialog-actions");
4152
+ this.$content = this.$el.querySelector(".atk-layer-dialog-content");
4153
+ this.$content.appendChild(contentEl);
4154
+ return this;
4155
+ }
4156
+ setYes(handler) {
4157
+ const btn = createElement(`<button data-action="confirm">${this.ctx.$t("confirm")}</button>`);
4158
+ btn.onclick = this.onBtnClick(handler);
4159
+ this.$actions.appendChild(btn);
4160
+ return this;
4161
+ }
4162
+ setNo(handler) {
4163
+ const btn = createElement(`<button data-action="cancel">${this.ctx.$t("cancel")}</button>`);
4164
+ btn.onclick = this.onBtnClick(handler);
4165
+ this.$actions.appendChild(btn);
4166
+ return this;
4167
+ }
4168
+ onBtnClick(handler) {
4169
+ return (evt) => {
4170
+ const re = handler(evt.currentTarget, this);
4171
+ if (re === void 0 || re === true) {
4172
+ this.$el.remove();
4173
+ }
4174
+ };
4175
+ }
4176
+ }
3497
4177
  const CaptchaChecker = {
3498
4178
  request(that, ctx, inputVal) {
3499
- return new Api(that.ctx).captchaCheck(inputVal);
4179
+ return that.ctx.getApi().captchaCheck(inputVal);
3500
4180
  },
3501
4181
  body(that, ctx) {
3502
4182
  if (that.captchaConf.iframe) {
@@ -3526,7 +4206,7 @@ const CaptchaChecker = {
3526
4206
  return;
3527
4207
  let isPass = false;
3528
4208
  try {
3529
- const resp = yield new Api(that.ctx).captchaStatus();
4209
+ const resp = yield that.ctx.getApi().captchaStatus();
3530
4210
  isPass = resp.is_pass;
3531
4211
  } catch (e) {
3532
4212
  isPass = false;
@@ -3544,13 +4224,13 @@ const CaptchaChecker = {
3544
4224
  };
3545
4225
  return $iframeWrap;
3546
4226
  }
3547
- const elem = createElement(`<span><img class="atk-captcha-img" src="${that.captchaConf.imgData || ""}" alt="\u9A8C\u8BC1\u7801">\u6572\u5165\u9A8C\u8BC1\u7801\u7EE7\u7EED\uFF1A</span>`);
4227
+ const elem = createElement(`<span><img class="atk-captcha-img" src="${that.captchaConf.imgData || ""}">${that.ctx.$t("captchaCheck")}</span>`);
3548
4228
  elem.querySelector(".atk-captcha-img").onclick = () => {
3549
4229
  const imgEl = elem.querySelector(".atk-captcha-img");
3550
- new Api(that.ctx).captchaGet().then((imgData) => {
4230
+ that.ctx.getApi().captchaGet().then((imgData) => {
3551
4231
  imgEl.setAttribute("src", imgData);
3552
4232
  }).catch((err) => {
3553
- console.error("\u9A8C\u8BC1\u7801\u83B7\u53D6\u5931\u8D25 ", err);
4233
+ console.error("Failed to get captcha image ", err);
3554
4234
  });
3555
4235
  };
3556
4236
  return elem;
@@ -3570,17 +4250,18 @@ const AdminChecker = {
3570
4250
  email: that.ctx.user.data.email,
3571
4251
  password: inputVal
3572
4252
  };
3573
- return new Api(that.ctx).login(data.name, data.email, data.password);
4253
+ return that.ctx.getApi().login(data.name, data.email, data.password);
3574
4254
  },
3575
4255
  body(that, ctx) {
3576
- return createElement("<span>\u6572\u5165\u5BC6\u7801\u6765\u9A8C\u8BC1\u7BA1\u7406\u5458\u8EAB\u4EFD\uFF1A</span>");
4256
+ return createElement(`<span>${that.ctx.$t("adminCheck")}</span>`);
3577
4257
  },
3578
4258
  onSuccess(that, ctx, userToken, inputVal, formEl) {
3579
- that.ctx.user.data.isAdmin = true;
3580
- that.ctx.user.data.token = userToken;
3581
- that.ctx.user.save();
4259
+ that.ctx.user.update({
4260
+ isAdmin: true,
4261
+ token: userToken
4262
+ });
3582
4263
  that.ctx.trigger("user-changed", that.ctx.user.data);
3583
- that.ctx.trigger("list-reload");
4264
+ that.ctx.listReload();
3584
4265
  },
3585
4266
  onError(that, ctx, err, inputVal, formEl) {
3586
4267
  }
@@ -3591,19 +4272,14 @@ class CheckerLauncher {
3591
4272
  __publicField(this, "launched", []);
3592
4273
  __publicField(this, "captchaConf", {});
3593
4274
  this.ctx = ctx;
3594
- this.initEventBind();
3595
4275
  }
3596
- initEventBind() {
3597
- this.ctx.on("checker-captcha", (conf) => {
3598
- if (conf.imgData)
3599
- this.captchaConf.imgData = conf.imgData;
3600
- if (conf.iframe)
3601
- this.captchaConf.iframe = conf.iframe;
3602
- this.fire(CaptchaChecker, conf);
3603
- });
3604
- this.ctx.on("checker-admin", (conf) => {
3605
- this.fire(AdminChecker, conf);
3606
- });
4276
+ checkCaptcha(payload) {
4277
+ this.captchaConf.imgData = payload.imgData;
4278
+ this.captchaConf.iframe = payload.iframe;
4279
+ this.fire(CaptchaChecker, payload);
4280
+ }
4281
+ checkAdmin(payload) {
4282
+ this.fire(AdminChecker, payload);
3607
4283
  }
3608
4284
  fire(checker, payload) {
3609
4285
  if (this.launched.includes(checker))
@@ -3643,7 +4319,7 @@ class CheckerLauncher {
3643
4319
  }
3644
4320
  };
3645
4321
  let btnTextOrg;
3646
- const dialog = new Dialog(formEl);
4322
+ const dialog = new Dialog(this.ctx, formEl);
3647
4323
  dialog.setYes((btnEl) => {
3648
4324
  const inputVal = $input.value.trim();
3649
4325
  if (!btnTextOrg)
@@ -3656,7 +4332,7 @@ class CheckerLauncher {
3656
4332
  btnEl.innerText = btnTextOrg || "";
3657
4333
  btnEl.classList.remove("error");
3658
4334
  };
3659
- btnEl.innerText = "\u52A0\u8F7D\u4E2D...";
4335
+ btnEl.innerText = `${this.ctx.$t("loading")}...`;
3660
4336
  checker.request(this, checkerCtx, inputVal).then((data) => {
3661
4337
  this.close(checker, layer);
3662
4338
  if (checker.onSuccess)
@@ -3695,30 +4371,68 @@ class CheckerLauncher {
3695
4371
  }
3696
4372
  }
3697
4373
  var editor = "";
3698
- var EditorHTML = '<div class="atk-main-editor">\n <div class="atk-header">\n <input name="nick" placeholder="\u6635\u79F0" class="atk-nick" type="text" required="required">\n <input name="email" placeholder="\u90AE\u7BB1" class="atk-email" type="email" required="required">\n <input name="link" placeholder="\u7F51\u5740 (https://)" class="atk-link" type="url">\n </div>\n <div class="atk-textarea-wrap">\n <textarea class="atk-textarea" placeholder=""></textarea>\n </div>\n <div class="atk-plug-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';
4374
+ var 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';
3699
4375
  var emoticonsPlug = "";
3700
4376
  class EditorPlug {
3701
4377
  constructor(editor2) {
3702
4378
  __publicField(this, "editor");
3703
- __publicField(this, "ctx");
4379
+ __publicField(this, "$panel");
4380
+ __publicField(this, "$btn");
4381
+ __publicField(this, "onHeaderInput");
3704
4382
  this.editor = editor2;
3705
- this.ctx = editor2.ctx;
4383
+ }
4384
+ get ctx() {
4385
+ return this.editor.ctx;
4386
+ }
4387
+ registerPanel(html = "<div></div>") {
4388
+ this.$panel = createElement(html);
4389
+ return this.$panel;
4390
+ }
4391
+ registerBtn(html) {
4392
+ this.$btn = createElement(`<span class="atk-plug-btn" data-plug-name="${this.constructor.name}">${html}</span>`);
4393
+ return this.$btn;
4394
+ }
4395
+ registerHeaderInputEvt(action) {
4396
+ this.onHeaderInput = action;
4397
+ }
4398
+ getPanel() {
4399
+ return this.$panel;
4400
+ }
4401
+ getBtn() {
4402
+ return this.$btn;
3706
4403
  }
3707
4404
  }
3708
4405
  __publicField(EditorPlug, "Name");
3709
- __publicField(EditorPlug, "BtnHTML");
3710
4406
  class EmoticonsPlug extends EditorPlug {
3711
4407
  constructor(editor2) {
3712
4408
  super(editor2);
3713
- __publicField(this, "$el");
3714
4409
  __publicField(this, "emoticons", []);
4410
+ __publicField(this, "loadingTask", null);
3715
4411
  __publicField(this, "$grpWrap");
3716
4412
  __publicField(this, "$grpSwitcher");
3717
- __publicField(this, "loadingTask", null);
3718
4413
  __publicField(this, "isListLoaded", false);
3719
4414
  __publicField(this, "isImgLoaded", false);
3720
4415
  this.editor = editor2;
3721
- this.$el = createElement(`<div class="atk-editor-plug-emoticons"></div>`);
4416
+ this.registerPanel(`<div class="atk-editor-plug-emoticons"></div>`);
4417
+ this.registerBtn(this.ctx.$t("emoticon"));
4418
+ window.setTimeout(() => {
4419
+ this.loadEmoticonsData();
4420
+ }, 1e3);
4421
+ }
4422
+ onPanelShow() {
4423
+ (() => __async(this, null, function* () {
4424
+ yield this.loadEmoticonsData();
4425
+ if (!this.isImgLoaded) {
4426
+ this.initEmoticonsList();
4427
+ this.isImgLoaded = true;
4428
+ }
4429
+ setTimeout(() => {
4430
+ this.changeListHeight();
4431
+ }, 30);
4432
+ }))();
4433
+ }
4434
+ onPanelHide() {
4435
+ this.$panel.parentElement.style.height = "";
3722
4436
  }
3723
4437
  loadEmoticonsData() {
3724
4438
  return __async(this, null, function* () {
@@ -3729,9 +4443,9 @@ class EmoticonsPlug extends EditorPlug {
3729
4443
  return;
3730
4444
  }
3731
4445
  this.loadingTask = (() => __async(this, null, function* () {
3732
- showLoading(this.$el);
4446
+ showLoading(this.$panel);
3733
4447
  this.emoticons = yield this.handleData(this.ctx.conf.emoticons);
3734
- hideLoading(this.$el);
4448
+ hideLoading(this.$panel);
3735
4449
  this.loadingTask = null;
3736
4450
  this.isListLoaded = true;
3737
4451
  }))();
@@ -3744,8 +4458,8 @@ class EmoticonsPlug extends EditorPlug {
3744
4458
  data = [data];
3745
4459
  }
3746
4460
  if (!Array.isArray(data)) {
3747
- setError(this.$el, "\u8868\u60C5\u5305\u6570\u636E\u5FC5\u987B\u4E3A Array/Object/String \u7C7B\u578B");
3748
- hideLoading(this.$el);
4461
+ setError(this.$panel, "\u8868\u60C5\u5305\u6570\u636E\u5FC5\u987B\u4E3A Array/Object/String \u7C7B\u578B");
4462
+ hideLoading(this.$panel);
3749
4463
  return [];
3750
4464
  }
3751
4465
  const pushGrp = (grp) => {
@@ -3798,8 +4512,8 @@ class EmoticonsPlug extends EditorPlug {
3798
4512
  const json = yield resp.json();
3799
4513
  return json;
3800
4514
  } catch (err) {
3801
- hideLoading(this.$el);
3802
- setError(this.$el, `\u8868\u60C5\u52A0\u8F7D\u5931\u8D25 ${String(err)}`);
4515
+ hideLoading(this.$panel);
4516
+ setError(this.$panel, `\u8868\u60C5\u52A0\u8F7D\u5931\u8D25 ${String(err)}`);
3803
4517
  return [];
3804
4518
  }
3805
4519
  });
@@ -3853,7 +4567,7 @@ class EmoticonsPlug extends EditorPlug {
3853
4567
  }
3854
4568
  initEmoticonsList() {
3855
4569
  this.$grpWrap = createElement(`<div class="atk-grp-wrap"></div>`);
3856
- this.$el.append(this.$grpWrap);
4570
+ this.$panel.append(this.$grpWrap);
3857
4571
  this.emoticons.forEach((grp, index) => {
3858
4572
  const $grp = createElement(`<div class="atk-grp" style="display: none;"></div>`);
3859
4573
  this.$grpWrap.append($grp);
@@ -3882,15 +4596,17 @@ class EmoticonsPlug extends EditorPlug {
3882
4596
  };
3883
4597
  });
3884
4598
  });
3885
- this.$grpSwitcher = createElement(`<div class="atk-grp-switcher"></div>`);
3886
- this.$el.append(this.$grpSwitcher);
3887
- this.emoticons.forEach((grp, index) => {
3888
- const $item = createElement("<span />");
3889
- $item.innerText = grp.name;
3890
- $item.setAttribute("data-index", String(index));
3891
- $item.onclick = () => this.openGrp(index);
3892
- this.$grpSwitcher.append($item);
3893
- });
4599
+ if (this.emoticons.length > 1) {
4600
+ this.$grpSwitcher = createElement(`<div class="atk-grp-switcher"></div>`);
4601
+ this.$panel.append(this.$grpSwitcher);
4602
+ this.emoticons.forEach((grp, index) => {
4603
+ const $item = createElement("<span />");
4604
+ $item.innerText = grp.name;
4605
+ $item.setAttribute("data-index", String(index));
4606
+ $item.onclick = () => this.openGrp(index);
4607
+ this.$grpSwitcher.append($item);
4608
+ });
4609
+ }
3894
4610
  if (this.emoticons.length > 0)
3895
4611
  this.openGrp(0);
3896
4612
  }
@@ -3908,26 +4624,8 @@ class EmoticonsPlug extends EditorPlug {
3908
4624
  (_a = this.$grpSwitcher.querySelector(`span[data-index="${index}"]`)) == null ? void 0 : _a.classList.add("active");
3909
4625
  this.changeListHeight();
3910
4626
  }
3911
- getEl() {
3912
- return this.$el;
3913
- }
3914
4627
  changeListHeight() {
3915
4628
  }
3916
- onShow() {
3917
- (() => __async(this, null, function* () {
3918
- yield this.loadEmoticonsData();
3919
- if (!this.isImgLoaded) {
3920
- this.initEmoticonsList();
3921
- this.isImgLoaded = true;
3922
- }
3923
- setTimeout(() => {
3924
- this.changeListHeight();
3925
- }, 30);
3926
- }))();
3927
- }
3928
- onHide() {
3929
- this.$el.parentElement.style.height = "";
3930
- }
3931
4629
  transEmoticonImageText(text) {
3932
4630
  if (!this.emoticons || !Array.isArray(this.emoticons))
3933
4631
  return text;
@@ -3942,177 +4640,262 @@ class EmoticonsPlug extends EditorPlug {
3942
4640
  }
3943
4641
  }
3944
4642
  __publicField(EmoticonsPlug, "Name", "emoticons");
3945
- __publicField(EmoticonsPlug, "BtnHTML", "\u8868\u60C5");
3946
- var previewPlug = "";
3947
- class PreviewPlug extends EditorPlug {
4643
+ class UploadPlug extends EditorPlug {
3948
4644
  constructor(editor2) {
3949
4645
  super(editor2);
3950
- __publicField(this, "$el");
3951
- __publicField(this, "binded", false);
3952
- this.initEl();
3953
- }
3954
- initEl() {
3955
- this.$el = createElement('<div class="atk-editor-plug-preview"></div>');
3956
- this.binded = false;
4646
+ __publicField(this, "$imgUploadInput");
4647
+ __publicField(this, "allowImgExts", ["png", "jpg", "jpeg", "gif", "bmp", "svg", "webp"]);
4648
+ this.$imgUploadInput = document.createElement("input");
4649
+ this.$imgUploadInput.type = "file";
4650
+ this.$imgUploadInput.style.display = "none";
4651
+ this.$imgUploadInput.accept = this.allowImgExts.map((o) => `.${o}`).join(",");
4652
+ const $btn = this.registerBtn(`${this.ctx.$t("image")}`);
4653
+ $btn.after(this.$imgUploadInput);
4654
+ $btn.onclick = () => {
4655
+ const $input = this.$imgUploadInput;
4656
+ $input.onchange = () => {
4657
+ (() => __async(this, null, function* () {
4658
+ if (!$input.files || $input.files.length === 0)
4659
+ return;
4660
+ const file = $input.files[0];
4661
+ this.uploadImg(file);
4662
+ }))();
4663
+ };
4664
+ $input.click();
4665
+ };
4666
+ this.ctx.on("conf-updated", () => {
4667
+ if (!this.ctx.conf.imgUpload) {
4668
+ this.getBtn().setAttribute("atk-only-admin-show", "");
4669
+ this.ctx.checkAdminShowEl();
4670
+ }
4671
+ });
4672
+ const uploadFromFileList = (files) => {
4673
+ if (!files)
4674
+ return;
4675
+ for (let i = 0; i < files.length; i++) {
4676
+ const file = files[i];
4677
+ this.uploadImg(file);
4678
+ }
4679
+ };
4680
+ this.editor.$textarea.addEventListener("dragover", (evt) => {
4681
+ evt.stopPropagation();
4682
+ evt.preventDefault();
4683
+ });
4684
+ this.editor.$textarea.addEventListener("drop", (evt) => {
4685
+ var _a;
4686
+ const files = (_a = evt.dataTransfer) == null ? void 0 : _a.files;
4687
+ if (files == null ? void 0 : files.length) {
4688
+ evt.preventDefault();
4689
+ uploadFromFileList(files);
4690
+ }
4691
+ });
4692
+ this.editor.$textarea.addEventListener("paste", (evt) => {
4693
+ var _a;
4694
+ const files = (_a = evt.clipboardData) == null ? void 0 : _a.files;
4695
+ if (files == null ? void 0 : files.length) {
4696
+ evt.preventDefault();
4697
+ uploadFromFileList(files);
4698
+ }
4699
+ });
3957
4700
  }
3958
- getEl() {
3959
- return this.$el;
4701
+ uploadImg(file) {
4702
+ return __async(this, null, function* () {
4703
+ const fileExt = /[^.]+$/.exec(file.name);
4704
+ if (!fileExt || !this.allowImgExts.includes(fileExt[0]))
4705
+ return;
4706
+ if (!this.ctx.user.checkHasBasicUserInfo()) {
4707
+ this.editor.showNotify(this.ctx.$t("uploadLoginMsg"), "w");
4708
+ return;
4709
+ }
4710
+ let insertPrefix = "\n";
4711
+ if (this.editor.$textarea.value.trim() === "")
4712
+ insertPrefix = "";
4713
+ const uploadPlaceholderTxt = `${insertPrefix}![](Uploading ${file.name}...)`;
4714
+ this.editor.insertContent(uploadPlaceholderTxt);
4715
+ let resp;
4716
+ try {
4717
+ if (!this.ctx.conf.imgUploader) {
4718
+ resp = yield this.ctx.getApi().imgUpload(file);
4719
+ } else {
4720
+ resp = yield this.ctx.conf.imgUploader(file);
4721
+ }
4722
+ } catch (err) {
4723
+ console.error(err);
4724
+ this.editor.showNotify(`${this.ctx.$t("uploadFail")}\uFF0C${err.msg}`, "e");
4725
+ }
4726
+ if (!!resp && resp.img_url) {
4727
+ let imgURL = resp.img_url;
4728
+ if (!isValidURL(imgURL))
4729
+ imgURL = getURLBasedOnApi(this.ctx, imgURL);
4730
+ this.editor.setContent(this.editor.$textarea.value.replace(uploadPlaceholderTxt, `${insertPrefix}![](${imgURL})`));
4731
+ } else {
4732
+ this.editor.setContent(this.editor.$textarea.value.replace(uploadPlaceholderTxt, ""));
4733
+ }
4734
+ });
3960
4735
  }
3961
- onShow() {
4736
+ }
4737
+ __publicField(UploadPlug, "Name", "upload");
4738
+ var previewPlug = "";
4739
+ class PreviewPlug extends EditorPlug {
4740
+ constructor(editor2) {
4741
+ super(editor2);
4742
+ __publicField(this, "isBind", false);
4743
+ this.registerPanel(`<div class="atk-editor-plug-preview"></div>`);
4744
+ let btnText = this.editor.$t("preview");
4745
+ if (this.ctx.markedInstance)
4746
+ btnText += ` <i title="Markdown is supported"><svg class="markdown" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><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>`;
4747
+ this.registerBtn(btnText);
4748
+ }
4749
+ onPanelShow() {
3962
4750
  this.updateContent();
3963
- if (!this.binded) {
4751
+ if (!this.isBind) {
3964
4752
  const event = () => {
3965
4753
  this.updateContent();
3966
4754
  };
3967
4755
  this.editor.$textarea.addEventListener("input", event);
3968
4756
  this.editor.$textarea.addEventListener("change", event);
3969
- this.binded = true;
4757
+ this.isBind = true;
3970
4758
  }
3971
4759
  }
3972
- onHide() {
3973
- }
3974
4760
  updateContent() {
3975
- if (this.$el.style.display !== "none") {
3976
- this.$el.innerHTML = this.editor.getContentMarked();
4761
+ if (this.$panel.style.display !== "none") {
4762
+ this.$panel.innerHTML = this.editor.getContentMarked();
3977
4763
  }
3978
4764
  }
3979
4765
  }
3980
4766
  __publicField(PreviewPlug, "Name", "preview");
3981
- __publicField(PreviewPlug, "BtnHTML", '\u9884\u89C8 <i title="Markdown is supported"><svg class="markdown" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><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>');
4767
+ class HeaderInputPlug extends EditorPlug {
4768
+ constructor(editor2) {
4769
+ super(editor2);
4770
+ __publicField(this, "queryUserInfo", {
4771
+ timeout: null,
4772
+ abortFunc: null
4773
+ });
4774
+ this.registerHeaderInputEvt((key, $input) => {
4775
+ if (key === "nick" || key === "email") {
4776
+ this.fetchUserInfo();
4777
+ }
4778
+ });
4779
+ this.editor.$link.addEventListener("change", () => {
4780
+ const link = this.editor.$link.value.trim();
4781
+ if (!!link && !/^(http|https):\/\//.test(link)) {
4782
+ this.editor.$link.value = `https://${link}`;
4783
+ this.ctx.user.update({ link: this.editor.$link.value });
4784
+ }
4785
+ });
4786
+ }
4787
+ fetchUserInfo() {
4788
+ this.ctx.user.logout();
4789
+ if (this.queryUserInfo.timeout)
4790
+ window.clearTimeout(this.queryUserInfo.timeout);
4791
+ if (this.queryUserInfo.abortFunc)
4792
+ this.queryUserInfo.abortFunc();
4793
+ this.queryUserInfo.timeout = window.setTimeout(() => {
4794
+ this.queryUserInfo.timeout = null;
4795
+ const { req, abort } = this.ctx.getApi().userGet(this.ctx.user.data.nick, this.ctx.user.data.email);
4796
+ this.queryUserInfo.abortFunc = abort;
4797
+ req.then((data) => {
4798
+ var _a;
4799
+ if (!data.is_login) {
4800
+ this.ctx.user.logout();
4801
+ }
4802
+ this.ctx.updateNotifies(data.unread);
4803
+ if (this.ctx.user.checkHasBasicUserInfo() && !data.is_login && ((_a = data.user) == null ? void 0 : _a.is_admin)) {
4804
+ this.showLoginDialog();
4805
+ }
4806
+ if (data.user && data.user.link) {
4807
+ this.editor.$link.value = data.user.link;
4808
+ this.ctx.user.update({ link: data.user.link });
4809
+ }
4810
+ }).catch(() => {
4811
+ }).finally(() => {
4812
+ this.queryUserInfo.abortFunc = null;
4813
+ });
4814
+ }, 400);
4815
+ }
4816
+ showLoginDialog() {
4817
+ this.ctx.checkAdmin({
4818
+ onSuccess: () => {
4819
+ }
4820
+ });
4821
+ }
4822
+ }
4823
+ __publicField(HeaderInputPlug, "Name", "headerInput");
3982
4824
  class Editor extends Component {
3983
4825
  constructor(ctx) {
3984
4826
  super(ctx);
3985
- __publicField(this, "LOADABLE_PLUG_LIST", [EmoticonsPlug, PreviewPlug]);
3986
- __publicField(this, "plugList", {});
3987
4827
  __publicField(this, "$header");
4828
+ __publicField(this, "$nick");
4829
+ __publicField(this, "$email");
4830
+ __publicField(this, "$link");
3988
4831
  __publicField(this, "$textareaWrap");
3989
4832
  __publicField(this, "$textarea");
3990
- __publicField(this, "$plugWrap");
3991
4833
  __publicField(this, "$bottom");
3992
- __publicField(this, "$plugBtnWrap");
3993
- __publicField(this, "$imgUploadBtn");
3994
- __publicField(this, "$imgUploadInput");
3995
4834
  __publicField(this, "$submitBtn");
3996
4835
  __publicField(this, "$notifyWrap");
3997
4836
  __publicField(this, "replyComment", null);
3998
4837
  __publicField(this, "$sendReply", null);
3999
4838
  __publicField(this, "isTraveling", false);
4000
- __publicField(this, "queryUserInfo", {
4001
- timeout: null,
4002
- abortFunc: null
4003
- });
4839
+ __publicField(this, "ENABLED_PLUGS", [EmoticonsPlug, UploadPlug, PreviewPlug, HeaderInputPlug]);
4840
+ __publicField(this, "plugList", {});
4004
4841
  __publicField(this, "openedPlugName", null);
4005
- __publicField(this, "allowImgExts", ["png", "jpg", "jpeg", "gif", "bmp", "svg", "webp"]);
4842
+ __publicField(this, "$plugPanelWrap");
4843
+ __publicField(this, "$plugBtnWrap");
4006
4844
  this.$el = createElement(EditorHTML);
4007
4845
  this.$header = this.$el.querySelector(".atk-header");
4846
+ this.$nick = this.$header.querySelector('[name="nick"]');
4847
+ this.$email = this.$header.querySelector('[name="email"]');
4848
+ this.$link = this.$header.querySelector('[name="link"]');
4008
4849
  this.$textareaWrap = this.$el.querySelector(".atk-textarea-wrap");
4009
4850
  this.$textarea = this.$el.querySelector(".atk-textarea");
4010
- this.$plugWrap = this.$el.querySelector(".atk-plug-wrap");
4011
4851
  this.$bottom = this.$el.querySelector(".atk-bottom");
4012
- this.$plugBtnWrap = this.$el.querySelector(".atk-plug-btn-wrap");
4013
4852
  this.$submitBtn = this.$el.querySelector(".atk-send-btn");
4014
4853
  this.$notifyWrap = this.$el.querySelector(".atk-notify-wrap");
4854
+ this.$plugBtnWrap = this.$el.querySelector(".atk-plug-btn-wrap");
4855
+ this.$plugPanelWrap = this.$el.querySelector(".atk-plug-panel-wrap");
4015
4856
  this.initLocalStorage();
4016
4857
  this.initHeader();
4017
4858
  this.initTextarea();
4018
- this.initEditorPlug();
4019
- this.initBottomPart();
4020
- this.ctx.on("editor-open", () => this.open());
4021
- this.ctx.on("editor-close", () => this.close());
4022
- this.ctx.on("editor-reply", (p) => this.setReply(p.data, p.$el, p.scroll));
4023
- this.ctx.on("editor-reply-cancel", () => this.cancelReply());
4024
- this.ctx.on("editor-show-loading", () => showLoading(this.$el));
4025
- this.ctx.on("editor-hide-loading", () => hideLoading(this.$el));
4026
- this.ctx.on("editor-notify", (f) => this.showNotify(f.msg, f.type));
4027
- this.ctx.on("editor-travel", ($el) => this.travel($el));
4028
- this.ctx.on("editor-travel-back", () => this.travelBack());
4029
- this.ctx.on("conf-updated", () => this.refreshUploadBtn());
4859
+ this.initPlugs();
4860
+ this.initSubmitBtn();
4861
+ this.ctx.on("conf-updated", () => {
4862
+ });
4030
4863
  }
4031
4864
  get user() {
4032
4865
  return this.ctx.user;
4033
4866
  }
4867
+ get $inputs() {
4868
+ return { nick: this.$nick, email: this.$email, link: this.$link };
4869
+ }
4034
4870
  initLocalStorage() {
4035
4871
  const localContent = window.localStorage.getItem("ArtalkContent") || "";
4036
4872
  if (localContent.trim() !== "") {
4037
- this.showNotify("\u5DF2\u81EA\u52A8\u6062\u590D", "i");
4873
+ this.showNotify(this.$t("restoredMsg"), "i");
4038
4874
  this.setContent(localContent);
4039
4875
  }
4040
- this.$textarea.addEventListener("input", () => {
4041
- this.saveContent();
4042
- });
4876
+ this.$textarea.addEventListener("input", () => this.saveToLocalStorage());
4877
+ }
4878
+ saveToLocalStorage() {
4879
+ window.localStorage.setItem("ArtalkContent", this.getContentOriginal().trim());
4043
4880
  }
4044
4881
  initHeader() {
4045
- Object.keys(this.user.data).forEach((field) => {
4046
- const inputEl = this.getInputEl(field);
4047
- if (inputEl && inputEl instanceof HTMLInputElement) {
4048
- inputEl.value = this.user.data[field] || "";
4049
- inputEl.addEventListener("input", () => this.onHeaderInput(field, inputEl));
4050
- }
4882
+ Object.entries(this.$inputs).forEach(([key, $input]) => {
4883
+ $input.value = this.user.data[key] || "";
4884
+ $input.addEventListener("input", () => this.onHeaderInput(key, $input));
4885
+ $input.placeholder = `${this.$t(key)}`;
4051
4886
  });
4052
- const $linkInput = this.getInputEl("link");
4053
- if ($linkInput) {
4054
- $linkInput.addEventListener("change", () => {
4055
- const link = $linkInput.value.trim();
4056
- if (!!link && !/^(http|https):\/\//.test(link)) {
4057
- $linkInput.value = `https://${link}`;
4058
- this.user.data.link = $linkInput.value;
4059
- this.saveUser();
4060
- }
4061
- });
4062
- }
4063
- }
4064
- getInputEl(field) {
4065
- const inputEl = this.$header.querySelector(`[name="${field}"]`);
4066
- return inputEl;
4067
- }
4068
- onHeaderInput(field, inputEl) {
4069
- this.user.data[field] = inputEl.value.trim();
4070
- if (field === "nick" || field === "email") {
4071
- this.user.data.token = "";
4072
- this.user.data.isAdmin = false;
4073
- if (this.queryUserInfo.timeout !== null)
4074
- window.clearTimeout(this.queryUserInfo.timeout);
4075
- if (this.queryUserInfo.abortFunc !== null)
4076
- this.queryUserInfo.abortFunc();
4077
- this.queryUserInfo.timeout = window.setTimeout(() => {
4078
- this.queryUserInfo.timeout = null;
4079
- const { req, abort } = new Api(this.ctx).userGet(this.user.data.nick, this.user.data.email);
4080
- this.queryUserInfo.abortFunc = abort;
4081
- req.then((data) => {
4082
- if (!data.is_login) {
4083
- this.user.data.token = "";
4084
- this.user.data.isAdmin = false;
4085
- }
4086
- this.ctx.trigger("unread-update", { notifies: data.unread });
4087
- if (this.user.checkHasBasicUserInfo() && !data.is_login && data.user && data.user.is_admin) {
4088
- this.showLoginDialog();
4089
- }
4090
- if (data.user && data.user.link) {
4091
- this.user.data.link = data.user.link;
4092
- this.getInputEl("link").value = data.user.link;
4093
- }
4094
- }).finally(() => {
4095
- this.queryUserInfo.abortFunc = null;
4096
- });
4097
- }, 400);
4098
- }
4099
- this.saveUser();
4100
4887
  }
4101
- showLoginDialog() {
4102
- this.ctx.trigger("checker-admin", {
4103
- onSuccess: () => {
4104
- }
4888
+ onHeaderInput(key, $input) {
4889
+ this.user.update({
4890
+ [key]: $input.value.trim()
4891
+ });
4892
+ Object.entries(this.plugList).forEach(([plugName, plug]) => {
4893
+ if (plug.onHeaderInput)
4894
+ plug.onHeaderInput(key, $input);
4105
4895
  });
4106
- }
4107
- saveUser() {
4108
- this.user.save();
4109
- this.ctx.trigger("user-changed", this.ctx.user.data);
4110
- }
4111
- saveContent() {
4112
- window.localStorage.setItem("ArtalkContent", this.getContentOriginal().trim());
4113
4896
  }
4114
4897
  initTextarea() {
4115
- this.$textarea.placeholder = this.ctx.conf.placeholder || "";
4898
+ this.$textarea.placeholder = this.ctx.conf.placeholder || this.$t("placeholder");
4116
4899
  this.$textarea.addEventListener("keydown", (e) => {
4117
4900
  const keyCode = e.keyCode || e.which;
4118
4901
  if (keyCode === 9) {
@@ -4120,159 +4903,36 @@ class Editor extends Component {
4120
4903
  this.insertContent(" ");
4121
4904
  }
4122
4905
  });
4123
- this.$textarea.addEventListener("input", (evt) => {
4906
+ this.$textarea.addEventListener("input", () => {
4124
4907
  this.adjustTextareaHeight();
4125
4908
  });
4126
4909
  }
4127
- adjustTextareaHeight() {
4128
- const diff = this.$textarea.offsetHeight - this.$textarea.clientHeight;
4129
- this.$textarea.style.height = "0px";
4130
- this.$textarea.style.height = `${this.$textarea.scrollHeight + diff}px`;
4910
+ initSubmitBtn() {
4911
+ this.$submitBtn.innerText = this.ctx.conf.sendBtn || this.$t("send");
4912
+ this.$submitBtn.addEventListener("click", () => this.submit());
4131
4913
  }
4132
- initEditorPlug() {
4133
- this.plugList = {};
4134
- this.$plugWrap.innerHTML = "";
4135
- this.$plugWrap.style.display = "none";
4136
- this.openedPlugName = null;
4137
- this.$plugBtnWrap.innerHTML = "";
4138
- this.LOADABLE_PLUG_LIST.forEach((PlugObj) => {
4139
- const btnElem = createElement(`<span class="atk-plug-btn" data-plug-name="${PlugObj.Name}">${PlugObj.BtnHTML}</span>`);
4140
- this.$plugBtnWrap.appendChild(btnElem);
4141
- if (PlugObj.Name === "emoticons") {
4142
- const emoPlug = new PlugObj(this);
4143
- this.plugList[PlugObj.Name] = emoPlug;
4144
- window.setTimeout(() => {
4145
- emoPlug.loadEmoticonsData();
4146
- }, 1e3);
4147
- }
4148
- btnElem.addEventListener("click", () => {
4149
- let plug = this.plugList[PlugObj.Name];
4150
- if (!plug) {
4151
- plug = new PlugObj(this);
4152
- this.plugList[PlugObj.Name] = plug;
4153
- }
4154
- this.$plugBtnWrap.querySelectorAll(".active").forEach((item) => item.classList.remove("active"));
4155
- if (PlugObj.Name === this.openedPlugName) {
4156
- plug.onHide();
4157
- this.$plugWrap.style.display = "none";
4158
- this.openedPlugName = null;
4159
- return;
4160
- }
4161
- if (this.$plugWrap.querySelector(`[data-plug-name="${PlugObj.Name}"]`) === null) {
4162
- const plugEl = plug.getEl();
4163
- plugEl.setAttribute("data-plug-name", PlugObj.Name);
4164
- plugEl.style.display = "none";
4165
- this.$plugWrap.appendChild(plugEl);
4166
- }
4167
- Array.from(this.$plugWrap.children).forEach((plugItemEl) => {
4168
- const plugItemName = plugItemEl.getAttribute("data-plug-name");
4169
- if (plugItemName === PlugObj.Name) {
4170
- plugItemEl.style.display = "";
4171
- this.plugList[plugItemName].onShow();
4172
- } else {
4173
- plugItemEl.style.display = "none";
4174
- this.plugList[plugItemName].onHide();
4175
- }
4176
- });
4177
- this.$plugWrap.style.display = "";
4178
- this.openedPlugName = PlugObj.Name;
4179
- btnElem.classList.add("active");
4180
- });
4181
- });
4182
- this.initImgUpload();
4183
- }
4184
- closePlug() {
4185
- this.$plugWrap.innerHTML = "";
4186
- this.$plugWrap.style.display = "none";
4187
- this.openedPlugName = null;
4914
+ getFinalContent() {
4915
+ let content = this.getContentOriginal();
4916
+ if (this.plugList.emoticons) {
4917
+ content = this.plugList.emoticons.transEmoticonImageText(content);
4918
+ }
4919
+ return content;
4188
4920
  }
4189
- initImgUpload() {
4190
- this.$imgUploadBtn = createElement(`<span class="atk-plug-btn">\u56FE\u7247</span>`);
4191
- this.$plugBtnWrap.querySelector('[data-plug-name="preview"]').before(this.$imgUploadBtn);
4192
- this.$imgUploadInput = document.createElement("input");
4193
- this.$imgUploadInput.type = "file";
4194
- this.$imgUploadInput.style.display = "none";
4195
- this.$imgUploadInput.accept = this.allowImgExts.map((o) => `.${o}`).join(",");
4196
- this.$imgUploadBtn.after(this.$imgUploadInput);
4197
- this.$imgUploadBtn.onclick = () => {
4198
- const $input = this.$imgUploadInput;
4199
- $input.onchange = () => {
4200
- (() => __async(this, null, function* () {
4201
- if (!$input.files || $input.files.length === 0)
4202
- return;
4203
- const file = $input.files[0];
4204
- this.uploadImg(file);
4205
- }))();
4206
- };
4207
- $input.click();
4208
- };
4209
- const uploadFromFileList = (files) => {
4210
- if (!files)
4211
- return;
4212
- for (let i = 0; i < files.length; i++) {
4213
- const file = files[i];
4214
- this.uploadImg(file);
4215
- }
4216
- };
4217
- this.$textarea.addEventListener("dragover", (evt) => {
4218
- evt.stopPropagation();
4219
- evt.preventDefault();
4220
- });
4221
- this.$textarea.addEventListener("drop", (evt) => {
4222
- var _a;
4223
- const files = (_a = evt.dataTransfer) == null ? void 0 : _a.files;
4224
- if (files == null ? void 0 : files.length) {
4225
- evt.preventDefault();
4226
- uploadFromFileList(files);
4227
- }
4228
- });
4229
- this.$textarea.addEventListener("paste", (evt) => {
4230
- var _a;
4231
- const files = (_a = evt.clipboardData) == null ? void 0 : _a.files;
4232
- if (files == null ? void 0 : files.length) {
4233
- evt.preventDefault();
4234
- uploadFromFileList(files);
4235
- }
4236
- });
4921
+ getContentOriginal() {
4922
+ return this.$textarea.value || "";
4237
4923
  }
4238
- refreshUploadBtn() {
4239
- if (!this.$imgUploadBtn)
4240
- return;
4241
- if (!this.ctx.conf.imgUpload) {
4242
- this.$imgUploadBtn.setAttribute("atk-only-admin-show", "");
4243
- this.ctx.trigger("check-admin-show-el");
4244
- }
4924
+ getContentMarked() {
4925
+ return marked(this.ctx, this.getFinalContent());
4245
4926
  }
4246
- uploadImg(file) {
4247
- return __async(this, null, function* () {
4248
- const fileExt = /[^.]+$/.exec(file.name);
4249
- if (!fileExt || !this.allowImgExts.includes(fileExt[0]))
4250
- return;
4251
- if (!this.ctx.user.checkHasBasicUserInfo()) {
4252
- this.showNotify("\u586B\u5165\u4F60\u7684\u540D\u5B57\u90AE\u7BB1\u624D\u80FD\u4E0A\u4F20\u54E6", "w");
4253
- return;
4254
- }
4255
- let insertPrefix = "\n";
4256
- if (this.$textarea.value.trim() === "")
4257
- insertPrefix = "";
4258
- const uploadPlaceholderTxt = `${insertPrefix}![](Uploading ${file.name}...)`;
4259
- this.insertContent(uploadPlaceholderTxt);
4260
- let resp;
4261
- try {
4262
- resp = yield new Api(this.ctx).imgUpload(file);
4263
- } catch (err) {
4264
- console.error(err);
4265
- this.showNotify(`\u56FE\u7247\u4E0A\u4F20\u5931\u8D25\uFF0C${err.msg}`, "e");
4266
- }
4267
- if (!!resp && resp.img_url) {
4268
- let imgURL = resp.img_url;
4269
- if (!isValidURL(imgURL))
4270
- imgURL = getURLBasedOnApi(this.ctx, imgURL);
4271
- this.setContent(this.$textarea.value.replace(uploadPlaceholderTxt, `${insertPrefix}![](${imgURL})`));
4272
- } else {
4273
- this.setContent(this.$textarea.value.replace(uploadPlaceholderTxt, ""));
4274
- }
4275
- });
4927
+ setContent(val) {
4928
+ this.$textarea.value = val;
4929
+ this.saveToLocalStorage();
4930
+ if (this.plugList.preview) {
4931
+ this.plugList.preview.updateContent();
4932
+ }
4933
+ window.setTimeout(() => {
4934
+ this.adjustTextareaHeight();
4935
+ }, 80);
4276
4936
  }
4277
4937
  insertContent(val) {
4278
4938
  if (document.selection) {
@@ -4293,48 +4953,21 @@ class Editor extends Component {
4293
4953
  this.$textarea.value += val;
4294
4954
  }
4295
4955
  }
4296
- setContent(val) {
4297
- this.$textarea.value = val;
4298
- this.saveContent();
4299
- if (!!this.plugList && !!this.plugList.preview) {
4300
- this.plugList.preview.updateContent();
4301
- }
4302
- window.setTimeout(() => {
4303
- this.adjustTextareaHeight();
4304
- }, 80);
4305
- }
4306
4956
  clearEditor() {
4307
4957
  this.setContent("");
4308
4958
  this.cancelReply();
4309
4959
  }
4310
- getFinalContent() {
4311
- let content = this.getContentOriginal();
4312
- if (this.plugList && this.plugList.emoticons) {
4313
- const emoticonsPlug2 = this.plugList.emoticons;
4314
- content = emoticonsPlug2.transEmoticonImageText(content);
4315
- }
4316
- return content;
4317
- }
4318
- getContentOriginal() {
4319
- return this.$textarea.value || "";
4320
- }
4321
- getContentMarked() {
4322
- return marked(this.ctx, this.getFinalContent());
4323
- }
4324
- initBottomPart() {
4325
- this.initReply();
4326
- this.initSubmit();
4327
- }
4328
- initReply() {
4329
- this.replyComment = null;
4330
- this.$sendReply = null;
4960
+ adjustTextareaHeight() {
4961
+ const diff = this.$textarea.offsetHeight - this.$textarea.clientHeight;
4962
+ this.$textarea.style.height = "0px";
4963
+ this.$textarea.style.height = `${this.$textarea.scrollHeight + diff}px`;
4331
4964
  }
4332
4965
  setReply(commentData, $comment, scroll = true) {
4333
4966
  if (this.replyComment !== null) {
4334
4967
  this.cancelReply();
4335
4968
  }
4336
4969
  if (this.$sendReply === null) {
4337
- this.$sendReply = createElement('<div class="atk-send-reply">\u56DE\u590D <span class="atk-text"></span><span class="atk-cancel" title="\u53D6\u6D88 AT">\xD7</span></div>');
4970
+ this.$sendReply = createElement(`<div class="atk-send-reply">${this.$t("reply")} <span class="atk-text"></span><span class="atk-cancel">\xD7</span></div>`);
4338
4971
  this.$sendReply.querySelector(".atk-text").innerText = `@${commentData.nick}`;
4339
4972
  this.$sendReply.addEventListener("click", () => {
4340
4973
  this.cancelReply();
@@ -4359,12 +4992,14 @@ class Editor extends Component {
4359
4992
  this.travelBack();
4360
4993
  }
4361
4994
  }
4362
- initSubmit() {
4363
- this.$submitBtn.innerText = this.ctx.conf.sendBtn || "Send";
4364
- this.$submitBtn.addEventListener("click", (evt) => {
4365
- evt.currentTarget;
4366
- this.submit();
4367
- });
4995
+ showNotify(msg, type) {
4996
+ showNotify(this.$notifyWrap, msg, type);
4997
+ }
4998
+ showLoading() {
4999
+ showLoading(this.$el);
5000
+ }
5001
+ hideLoading() {
5002
+ hideLoading(this.$el);
4368
5003
  }
4369
5004
  submit() {
4370
5005
  return __async(this, null, function* () {
@@ -4373,9 +5008,9 @@ class Editor extends Component {
4373
5008
  return;
4374
5009
  }
4375
5010
  this.ctx.trigger("editor-submit");
4376
- showLoading(this.$el);
5011
+ this.showLoading();
4377
5012
  try {
4378
- const nComment = yield new Api(this.ctx).add({
5013
+ const nComment = yield this.ctx.getApi().add({
4379
5014
  content: this.getFinalContent(),
4380
5015
  nick: this.user.data.nick,
4381
5016
  email: this.user.data.email,
@@ -4388,27 +5023,24 @@ class Editor extends Component {
4388
5023
  if (this.replyComment !== null && this.replyComment.page_key !== this.ctx.conf.pageKey) {
4389
5024
  window.open(`${this.replyComment.page_url}#atk-comment-${nComment.id}`);
4390
5025
  }
4391
- this.ctx.trigger("list-insert", nComment);
5026
+ this.ctx.insertComment(nComment);
4392
5027
  this.clearEditor();
4393
5028
  this.ctx.trigger("editor-submitted");
4394
5029
  } catch (err) {
4395
5030
  console.error(err);
4396
- this.showNotify(`\u8BC4\u8BBA\u5931\u8D25\uFF0C${err.msg || String(err)}`, "e");
5031
+ this.showNotify(`${this.$t("commentFail")}\uFF0C${err.msg || String(err)}`, "e");
4397
5032
  return;
4398
5033
  } finally {
4399
- hideLoading(this.$el);
5034
+ this.hideLoading();
4400
5035
  }
4401
5036
  });
4402
5037
  }
4403
- showNotify(msg, type) {
4404
- showNotify(this.$notifyWrap, msg, type);
4405
- }
4406
5038
  close() {
4407
5039
  if (!this.$textareaWrap.querySelector(".atk-comment-closed"))
4408
- this.$textareaWrap.prepend(createElement('<div class="atk-comment-closed">\u4EC5\u7BA1\u7406\u5458\u53EF\u8BC4\u8BBA</div>'));
5040
+ this.$textareaWrap.prepend(createElement(`<div class="atk-comment-closed">${this.$t("onlyAdminCanReply")}</div>`));
4409
5041
  if (!this.user.data.isAdmin) {
4410
5042
  this.$textarea.style.display = "none";
4411
- this.closePlug();
5043
+ this.closePlugPanel();
4412
5044
  this.$bottom.style.display = "none";
4413
5045
  } else {
4414
5046
  this.$textarea.style.display = "";
@@ -4440,12 +5072,76 @@ class Editor extends Component {
4440
5072
  if (this.replyComment !== null)
4441
5073
  this.cancelReply();
4442
5074
  }
4443
- initRemoteEmoticons() {
5075
+ initPlugs() {
5076
+ this.plugList = {};
5077
+ this.$plugPanelWrap.innerHTML = "";
5078
+ this.$plugPanelWrap.style.display = "none";
5079
+ this.openedPlugName = null;
5080
+ this.$plugBtnWrap.innerHTML = "";
5081
+ const disabledPlugs = [];
5082
+ if (!this.conf.emoticons)
5083
+ disabledPlugs.push("emoticons");
5084
+ if (!this.conf.preview)
5085
+ disabledPlugs.push("preview");
5086
+ this.ENABLED_PLUGS.forEach((Plug) => {
5087
+ const plugName = Plug.Name;
5088
+ if (disabledPlugs.includes(plugName))
5089
+ return;
5090
+ const plug = new Plug(this);
5091
+ this.plugList[plugName] = plug;
5092
+ const $btn = plug.getBtn();
5093
+ if ($btn) {
5094
+ this.$plugBtnWrap.appendChild($btn);
5095
+ $btn.onclick = $btn.onclick || (() => {
5096
+ this.$plugBtnWrap.querySelectorAll(".active").forEach((item) => item.classList.remove("active"));
5097
+ if (plugName === this.openedPlugName) {
5098
+ this.closePlugPanel();
5099
+ return;
5100
+ }
5101
+ this.openPlugPanel(plugName);
5102
+ $btn.classList.add("active");
5103
+ });
5104
+ const $panel = plug.getPanel();
5105
+ if ($panel) {
5106
+ $panel.setAttribute("data-plug-name", plugName);
5107
+ $panel.style.display = "none";
5108
+ this.$plugPanelWrap.appendChild($panel);
5109
+ }
5110
+ }
5111
+ });
5112
+ }
5113
+ openPlugPanel(plugName) {
5114
+ Object.entries(this.plugList).forEach(([aPlugName, plug]) => {
5115
+ const plugPanel = plug.getPanel();
5116
+ if (!plugPanel)
5117
+ return;
5118
+ if (aPlugName === plugName) {
5119
+ plugPanel.style.display = "";
5120
+ if (plug.onPanelShow)
5121
+ plug.onPanelShow();
5122
+ } else {
5123
+ plugPanel.style.display = "none";
5124
+ if (plug.onPanelHide)
5125
+ plug.onPanelHide();
5126
+ }
5127
+ });
5128
+ this.$plugPanelWrap.style.display = "";
5129
+ this.openedPlugName = plugName;
5130
+ }
5131
+ closePlugPanel() {
5132
+ if (!this.openedPlugName)
5133
+ return;
5134
+ const plug = this.plugList[this.openedPlugName];
5135
+ if (!plug)
5136
+ return;
5137
+ if (plug.onPanelHide)
5138
+ plug.onPanelHide();
5139
+ this.$plugPanelWrap.style.display = "none";
5140
+ this.openedPlugName = null;
4444
5141
  }
4445
5142
  }
4446
5143
  var list = "";
4447
- var ListHTML = '<div class="atk-list">\n <div class="atk-list-header">\n <div class="atk-comment-count">\n <div class="atk-text">\n <span class="atk-comment-count-num">0</span>\n \u6761\u8BC4\u8BBA\n </div>\n </div>\n <div class="atk-right-action">\n <span data-action="admin-close-comment" class="atk-hide" atk-only-admin-show>\u5173\u95ED\u8BC4\u8BBA</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">\u901A\u77E5\u4E2D\u5FC3</div>\n </span>\n </div>\n </div>\n <div class="atk-list-body"></div>\n <div class="atk-list-footer">\n <div class="atk-copyright"></div>\n </div>\n</div>\n';
4448
- var comment = "";
5144
+ var 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"></div>\n <div class="atk-list-footer">\n <div class="atk-copyright"></div>\n </div>\n</div>\n';
4449
5145
  const win = window || {};
4450
5146
  const nav = navigator || {};
4451
5147
  function Detect(userAgent) {
@@ -4636,9 +5332,10 @@ function Detect(userAgent) {
4636
5332
  }
4637
5333
  return dest;
4638
5334
  }
4639
- var 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-item atk-badge"></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';
5335
+ var comment = "";
4640
5336
  class ActionBtn {
4641
- constructor(conf) {
5337
+ constructor(ctx, conf) {
5338
+ __publicField(this, "ctx");
4642
5339
  __publicField(this, "conf");
4643
5340
  __publicField(this, "$el");
4644
5341
  __publicField(this, "isLoading", false);
@@ -4646,6 +5343,7 @@ class ActionBtn {
4646
5343
  __publicField(this, "msgRecTimerFunc");
4647
5344
  __publicField(this, "isConfirming", false);
4648
5345
  __publicField(this, "confirmRecTimer");
5346
+ this.ctx = ctx;
4649
5347
  this.$el = createElement(`<span class="atk-common-action-btn"></span>`);
4650
5348
  this.conf = typeof conf !== "object" ? { text: conf } : conf;
4651
5349
  this.$el.innerText = this.getText();
@@ -4677,7 +5375,7 @@ class ActionBtn {
4677
5375
  if (!this.isConfirming) {
4678
5376
  this.isConfirming = true;
4679
5377
  this.$el.classList.add("atk-btn-confirm");
4680
- this.$el.innerText = this.conf.confirmText || "\u786E\u8BA4\u64CD\u4F5C";
5378
+ this.$el.innerText = this.conf.confirmText || this.ctx.$t("actionConfirm");
4681
5379
  this.confirmRecTimer = window.setTimeout(() => confirmRestore(), 5e3);
4682
5380
  return;
4683
5381
  }
@@ -4705,7 +5403,7 @@ class ActionBtn {
4705
5403
  this.isLoading = value;
4706
5404
  if (value) {
4707
5405
  this.$el.classList.add("atk-btn-loading");
4708
- this.$el.innerText = loadingText || "\u52A0\u8F7D\u4E2D...";
5406
+ this.$el.innerText = loadingText || `${this.ctx.$t("loading")}...`;
4709
5407
  } else {
4710
5408
  this.$el.classList.remove("atk-btn-loading");
4711
5409
  this.$el.innerText = this.getText();
@@ -4753,40 +5451,33 @@ class ActionBtn {
4753
5451
  this.msgRecTimerFunc = void 0;
4754
5452
  }
4755
5453
  }
4756
- class Comment extends Component {
4757
- constructor(ctx, data) {
4758
- super(ctx);
4759
- __publicField(this, "data");
5454
+ var 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';
5455
+ class CommentRender {
5456
+ constructor(comment2) {
5457
+ __publicField(this, "comment");
5458
+ __publicField(this, "$el");
4760
5459
  __publicField(this, "$main");
4761
5460
  __publicField(this, "$header");
4762
5461
  __publicField(this, "$headerNick");
4763
- __publicField(this, "$headerBadge");
5462
+ __publicField(this, "$headerBadgeWrap");
4764
5463
  __publicField(this, "$body");
4765
5464
  __publicField(this, "$content");
4766
- __publicField(this, "$children");
5465
+ __publicField(this, "$childrenWrap");
4767
5466
  __publicField(this, "$actions");
4768
5467
  __publicField(this, "voteBtnUp");
4769
5468
  __publicField(this, "voteBtnDown");
4770
- __publicField(this, "parent");
4771
- __publicField(this, "nestCurt");
4772
- __publicField(this, "nestMax");
4773
- __publicField(this, "children", []);
4774
- __publicField(this, "flatMode", false);
4775
- __publicField(this, "replyTo");
4776
5469
  __publicField(this, "$replyTo");
4777
5470
  __publicField(this, "$replyAt");
4778
- __publicField(this, "afterRender");
4779
- __publicField(this, "unread", false);
4780
- __publicField(this, "openable", false);
4781
- __publicField(this, "openURL");
4782
- __publicField(this, "openEvt");
4783
- __publicField(this, "onReplyBtnClick");
4784
- __publicField(this, "onDelete");
4785
- this.nestMax = ctx.conf.nestMax || 3;
4786
- this.data = __spreadValues({}, data);
4787
- this.data.date = this.data.date.replace(/-/g, "/");
4788
- this.parent = null;
4789
- this.nestCurt = 1;
5471
+ this.comment = comment2;
5472
+ }
5473
+ get ctx() {
5474
+ return this.comment.ctx;
5475
+ }
5476
+ get data() {
5477
+ return this.comment.getData();
5478
+ }
5479
+ get cConf() {
5480
+ return this.comment.getConf();
4790
5481
  }
4791
5482
  render() {
4792
5483
  this.$el = createElement(CommentHTML);
@@ -4795,10 +5486,7 @@ class Comment extends Component {
4795
5486
  this.$body = this.$el.querySelector(".atk-body");
4796
5487
  this.$content = this.$body.querySelector(".atk-content");
4797
5488
  this.$actions = this.$el.querySelector(".atk-actions");
4798
- this.$children = null;
4799
5489
  this.$el.setAttribute("data-comment-id", `${this.data.id}`);
4800
- this.renderCheckUnread();
4801
- this.renderCheckClickable();
4802
5490
  this.renderAvatar();
4803
5491
  this.renderHeader();
4804
5492
  this.renderContent();
@@ -4806,35 +5494,13 @@ class Comment extends Component {
4806
5494
  this.renderReplyTo();
4807
5495
  this.renderPending();
4808
5496
  this.renderActionBtn();
4809
- if (this.afterRender)
4810
- this.afterRender();
5497
+ this.recoveryChildrenWrap();
4811
5498
  return this.$el;
4812
5499
  }
4813
- renderCheckUnread() {
4814
- if (this.unread)
4815
- this.$el.classList.add("atk-unread");
4816
- else
4817
- this.$el.classList.remove("atk-unread");
4818
- }
4819
- renderCheckClickable() {
4820
- if (this.openable) {
4821
- this.$el.classList.add("atk-openable");
4822
- } else {
4823
- this.$el.classList.remove("atk-openable");
4824
- }
4825
- this.$el.addEventListener("click", (evt) => {
4826
- if (this.openable && this.openURL) {
4827
- evt.preventDefault();
4828
- window.open(this.openURL);
4829
- }
4830
- if (this.openEvt)
4831
- this.openEvt();
4832
- });
4833
- }
4834
5500
  renderAvatar() {
4835
5501
  const $avatar = this.$el.querySelector(".atk-avatar");
4836
5502
  const $avatarImg = createElement("<img />");
4837
- $avatarImg.src = this.getGravatarUrl();
5503
+ $avatarImg.src = this.comment.getGravatarURL();
4838
5504
  if (this.data.link) {
4839
5505
  const $avatarA = createElement('<a target="_blank" rel="noreferrer noopener nofollow"></a>');
4840
5506
  $avatarA.href = this.data.link;
@@ -4854,196 +5520,414 @@ class Comment extends Component {
4854
5520
  } else {
4855
5521
  this.$headerNick.innerText = this.data.nick;
4856
5522
  }
4857
- this.$headerBadge = this.$el.querySelector(".atk-badge");
4858
- if (this.data.badge_name) {
4859
- this.$headerBadge.innerText = this.data.badge_name;
4860
- if (this.data.badge_color)
4861
- this.$headerBadge.style.backgroundColor = this.data.badge_color;
4862
- } else {
4863
- this.$headerBadge.remove();
4864
- this.$headerBadge = void 0;
5523
+ this.$headerBadgeWrap = this.$el.querySelector(".atk-badge-wrap");
5524
+ this.$headerBadgeWrap.innerHTML = "";
5525
+ const badgeText = this.data.badge_name;
5526
+ const badgeColor = this.data.badge_color;
5527
+ if (badgeText) {
5528
+ const $badge = createElement(`<span class="atk-badge"></span>`);
5529
+ $badge.innerText = badgeText.replace("\u7BA1\u7406\u5458", this.ctx.$t("admin"));
5530
+ $badge.style.backgroundColor = badgeColor || "";
5531
+ this.$headerBadgeWrap.append($badge);
4865
5532
  }
4866
5533
  if (this.data.is_pinned) {
4867
- const $pinnedBadge = createElement(`<span class="atk-item atk-pinned-badge">\u7F6E\u9876</span>`);
4868
- this.$headerNick.insertAdjacentElement("afterend", $pinnedBadge);
5534
+ const $pinnedBadge = createElement(`<span class="atk-pinned-badge">${this.ctx.$t("pin")}</span>`);
5535
+ this.$headerBadgeWrap.append($pinnedBadge);
4869
5536
  }
4870
5537
  const $date = this.$el.querySelector(".atk-date");
4871
- $date.innerText = this.getDateFormatted();
5538
+ $date.innerText = this.comment.getDateFormatted();
4872
5539
  $date.setAttribute("data-atk-comment-date", String(+new Date(this.data.date)));
4873
- if (this.conf.uaBadge) {
4874
- const $uaWrap = createElement(`<span class="atk-ua-wrap"></span>`);
5540
+ if (this.ctx.conf.uaBadge) {
5541
+ let $uaWrap = this.$header.querySelector("atk-ua-wrap");
5542
+ if (!$uaWrap) {
5543
+ $uaWrap = createElement(`<span class="atk-ua-wrap"></span>`);
5544
+ this.$header.append($uaWrap);
5545
+ }
5546
+ $uaWrap.innerHTML = "";
4875
5547
  const $uaBrowser = createElement(`<span class="atk-ua ua-browser"></span>`);
4876
5548
  const $usOS = createElement(`<span class="atk-ua ua-os"></span>`);
4877
- $uaBrowser.innerText = this.getUserUaBrowser();
4878
- $usOS.innerText = this.getUserUaOS();
5549
+ $uaBrowser.innerText = this.comment.getUserUaBrowser();
5550
+ $usOS.innerText = this.comment.getUserUaOS();
4879
5551
  $uaWrap.append($uaBrowser);
4880
5552
  $uaWrap.append($usOS);
4881
- this.$header.append($uaWrap);
4882
5553
  }
4883
5554
  }
4884
5555
  renderContent() {
4885
5556
  if (!this.data.is_collapsed) {
4886
- this.$content.innerHTML = this.getContentMarked();
5557
+ this.$content.innerHTML = this.comment.getContentMarked();
5558
+ this.$content.classList.remove("atk-hide", "atk-collapsed");
4887
5559
  return;
4888
5560
  }
4889
5561
  this.$content.classList.add("atk-hide", "atk-type-collapsed");
4890
5562
  const collapsedInfoEl = createElement(`
4891
5563
  <div class="atk-collapsed">
4892
- <span class="atk-text">\u8BE5\u8BC4\u8BBA\u5DF2\u88AB\u7CFB\u7EDF\u6216\u7BA1\u7406\u5458\u6298\u53E0</span>
4893
- <span class="atk-show-btn">\u67E5\u770B\u5185\u5BB9</span>
5564
+ <span class="atk-text">${this.ctx.$t("collapsedMsg")}</span>
5565
+ <span class="atk-show-btn">${this.ctx.$t("expand")}</span>
4894
5566
  </div>`);
4895
5567
  this.$body.insertAdjacentElement("beforeend", collapsedInfoEl);
4896
5568
  const contentShowBtn = collapsedInfoEl.querySelector(".atk-show-btn");
4897
5569
  contentShowBtn.addEventListener("click", (e) => {
4898
5570
  e.stopPropagation();
4899
5571
  if (this.$content.classList.contains("atk-hide")) {
4900
- this.$content.innerHTML = this.getContentMarked();
5572
+ this.$content.innerHTML = this.comment.getContentMarked();
4901
5573
  this.$content.classList.remove("atk-hide");
4902
5574
  playFadeInAnim(this.$content);
4903
- contentShowBtn.innerHTML = "\u6536\u8D77\u5185\u5BB9";
5575
+ contentShowBtn.innerHTML = this.ctx.$t("collapse");
4904
5576
  } else {
4905
5577
  this.$content.innerHTML = "";
4906
5578
  this.$content.classList.add("atk-hide");
4907
- contentShowBtn.innerHTML = "\u67E5\u770B\u5185\u5BB9";
5579
+ contentShowBtn.innerHTML = this.ctx.$t("expand");
4908
5580
  }
4909
5581
  });
4910
5582
  }
4911
5583
  renderReplyAt() {
4912
- if (this.flatMode || this.data.rid === 0)
4913
- return;
4914
- if (this.$replyAt)
5584
+ if (this.cConf.isFlatMode || this.data.rid === 0)
4915
5585
  return;
4916
- if (!this.replyTo)
5586
+ if (!this.cConf.replyTo)
4917
5587
  return;
4918
5588
  this.$replyAt = createElement(`<span class="atk-item atk-reply-at"><span class="atk-arrow"></span><span class="atk-nick"></span></span>`);
4919
- this.$replyAt.querySelector(".atk-nick").innerText = `${this.replyTo.nick}`;
5589
+ this.$replyAt.querySelector(".atk-nick").innerText = `${this.cConf.replyTo.nick}`;
4920
5590
  this.$replyAt.onclick = () => {
4921
- this.goToReplyComment();
5591
+ this.comment.getActions().goToReplyComment();
4922
5592
  };
4923
- const $after = this.$headerBadge || this.$headerNick;
4924
- $after.insertAdjacentElement("afterend", this.$replyAt);
5593
+ this.$headerBadgeWrap.insertAdjacentElement("afterend", this.$replyAt);
4925
5594
  }
4926
5595
  renderReplyTo() {
4927
- if (!this.flatMode)
5596
+ if (!this.cConf.isFlatMode)
4928
5597
  return;
4929
- if (!this.replyTo)
5598
+ if (!this.cConf.replyTo)
4930
5599
  return;
4931
5600
  this.$replyTo = createElement(`
4932
5601
  <div class="atk-reply-to">
4933
- <div class="atk-meta">\u56DE\u590D <span class="atk-nick"></span>:</div>
5602
+ <div class="atk-meta">${this.ctx.$t("reply")} <span class="atk-nick"></span>:</div>
4934
5603
  <div class="atk-content"></div>
4935
5604
  </div>`);
4936
5605
  const $nick = this.$replyTo.querySelector(".atk-nick");
4937
- $nick.innerText = `@${this.replyTo.nick}`;
5606
+ $nick.innerText = `@${this.cConf.replyTo.nick}`;
4938
5607
  $nick.onclick = () => {
4939
- this.goToReplyComment();
5608
+ this.comment.getActions().goToReplyComment();
4940
5609
  };
4941
- let replyContent = marked(this.ctx, this.replyTo.content);
4942
- if (this.replyTo.is_collapsed)
4943
- replyContent = "[\u5DF2\u6298\u53E0]";
5610
+ let replyContent = marked(this.ctx, this.cConf.replyTo.content);
5611
+ if (this.cConf.replyTo.is_collapsed)
5612
+ replyContent = `[${this.ctx.$t("collapsed")}]`;
4944
5613
  this.$replyTo.querySelector(".atk-content").innerHTML = replyContent;
4945
5614
  this.$body.prepend(this.$replyTo);
4946
5615
  }
4947
- goToReplyComment() {
4948
- const origHash = window.location.hash;
4949
- const modifyHash = `#atk-comment-${this.data.rid}`;
4950
- window.location.hash = modifyHash;
4951
- if (modifyHash === origHash)
4952
- window.dispatchEvent(new Event("hashchange"));
4953
- }
4954
5616
  renderPending() {
4955
5617
  if (!this.data.is_pending)
4956
5618
  return;
4957
- const pendingEl = createElement(`<div class="atk-pending">\u5BA1\u6838\u4E2D\uFF0C\u4EC5\u672C\u4EBA\u53EF\u89C1\u3002</div>`);
5619
+ const pendingEl = createElement(`<div class="atk-pending">${this.ctx.$t("pendingMsg")}</div>`);
4958
5620
  this.$body.prepend(pendingEl);
4959
5621
  }
4960
5622
  renderActionBtn() {
4961
5623
  if (this.ctx.conf.vote) {
4962
- this.voteBtnUp = new ActionBtn(() => `\u8D5E\u540C (${this.data.vote_up || 0})`).appendTo(this.$actions);
5624
+ this.voteBtnUp = new ActionBtn(this.ctx, () => `${this.ctx.$t("voteUp")} (${this.data.vote_up || 0})`).appendTo(this.$actions);
4963
5625
  this.voteBtnUp.setClick(() => {
4964
- this.vote("up");
5626
+ this.comment.getActions().vote("up");
4965
5627
  });
4966
5628
  if (this.ctx.conf.voteDown) {
4967
- this.voteBtnDown = new ActionBtn(() => `\u53CD\u5BF9 (${this.data.vote_down || 0})`).appendTo(this.$actions);
5629
+ this.voteBtnDown = new ActionBtn(this.ctx, () => `${this.ctx.$t("voteDown")} (${this.data.vote_down || 0})`).appendTo(this.$actions);
4968
5630
  this.voteBtnDown.setClick(() => {
4969
- this.vote("down");
5631
+ this.comment.getActions().vote("down");
4970
5632
  });
4971
5633
  }
4972
5634
  }
4973
5635
  if (this.data.is_allow_reply) {
4974
- const replyBtn = createElement(`<span>\u56DE\u590D</span>`);
5636
+ const replyBtn = createElement(`<span>${this.ctx.$t("reply")}</span>`);
4975
5637
  this.$actions.append(replyBtn);
4976
5638
  replyBtn.addEventListener("click", (e) => {
4977
5639
  e.stopPropagation();
4978
- if (!this.onReplyBtnClick) {
4979
- this.ctx.trigger("editor-reply", { data: this.data, $el: this.$el });
5640
+ if (!this.cConf.onReplyBtnClick) {
5641
+ this.ctx.replyComment(this.data, this.$el);
4980
5642
  } else {
4981
- this.onReplyBtnClick();
5643
+ this.cConf.onReplyBtnClick();
4982
5644
  }
4983
5645
  });
4984
5646
  }
4985
- const collapseBtn = new ActionBtn({
4986
- text: () => this.data.is_collapsed ? "\u53D6\u6D88\u6298\u53E0" : "\u6298\u53E0",
5647
+ const collapseBtn = new ActionBtn(this.ctx, {
5648
+ text: () => this.data.is_collapsed ? this.ctx.$t("expand") : this.ctx.$t("collapse"),
4987
5649
  adminOnly: true
4988
5650
  });
4989
5651
  collapseBtn.appendTo(this.$actions);
4990
5652
  collapseBtn.setClick(() => {
4991
- this.adminEdit("collapsed", collapseBtn);
5653
+ this.comment.getActions().adminEdit("collapsed", collapseBtn);
4992
5654
  });
4993
- const pendingBtn = new ActionBtn({
4994
- text: () => this.data.is_pending ? "\u5F85\u5BA1" : "\u5DF2\u5BA1",
5655
+ const pendingBtn = new ActionBtn(this.ctx, {
5656
+ text: () => this.data.is_pending ? this.ctx.$t("pending") : this.ctx.$t("approved"),
4995
5657
  adminOnly: true
4996
5658
  });
4997
5659
  pendingBtn.appendTo(this.$actions);
4998
5660
  pendingBtn.setClick(() => {
4999
- this.adminEdit("pending", pendingBtn);
5661
+ this.comment.getActions().adminEdit("pending", pendingBtn);
5000
5662
  });
5001
- const delBtn = new ActionBtn({
5002
- text: "\u5220\u9664",
5663
+ const delBtn = new ActionBtn(this.ctx, {
5664
+ text: this.ctx.$t("delete"),
5003
5665
  confirm: true,
5004
- confirmText: "\u786E\u8BA4\u5220\u9664",
5666
+ confirmText: this.ctx.$t("deleteConfirm"),
5005
5667
  adminOnly: true
5006
5668
  });
5007
5669
  delBtn.appendTo(this.$actions);
5008
5670
  delBtn.setClick(() => {
5009
- this.adminDelete(delBtn);
5671
+ this.comment.getActions().adminDelete(delBtn);
5010
5672
  });
5011
- const pinnedBtn = new ActionBtn({
5012
- text: () => this.data.is_pinned ? "\u53D6\u6D88\u7F6E\u9876" : "\u7F6E\u9876",
5673
+ const pinnedBtn = new ActionBtn(this.ctx, {
5674
+ text: () => this.data.is_pinned ? this.ctx.$t("unpin") : this.ctx.$t("pin"),
5013
5675
  adminOnly: true
5014
5676
  });
5015
5677
  pinnedBtn.appendTo(this.$actions);
5016
5678
  pinnedBtn.setClick(() => {
5017
- this.adminEdit("pinned", pendingBtn);
5679
+ this.comment.getActions().adminEdit("pinned", pendingBtn);
5680
+ });
5681
+ }
5682
+ checkHeightLimit() {
5683
+ this.checkHeightLimitArea("content");
5684
+ this.checkHeightLimitArea("children");
5685
+ }
5686
+ checkHeightLimitArea(area) {
5687
+ const childrenMaxH = this.ctx.conf.heightLimit.children;
5688
+ const contentMaxH = this.ctx.conf.heightLimit.content;
5689
+ if (area === "children" && !childrenMaxH)
5690
+ return;
5691
+ if (area === "content" && !contentMaxH)
5692
+ return;
5693
+ let maxHeight;
5694
+ if (area === "children")
5695
+ maxHeight = childrenMaxH;
5696
+ if (area === "content")
5697
+ maxHeight = contentMaxH;
5698
+ const checkEl = ($el) => {
5699
+ if (!$el)
5700
+ return;
5701
+ if (getHeight($el) > maxHeight) {
5702
+ this.heightLimitAdd($el, maxHeight);
5703
+ }
5704
+ };
5705
+ if (area === "children") {
5706
+ checkEl(this.$childrenWrap);
5707
+ } else if (area === "content") {
5708
+ checkEl(this.$content);
5709
+ checkEl(this.$replyTo);
5710
+ onImagesLoaded(this.$content, () => {
5711
+ checkEl(this.$content);
5712
+ });
5713
+ if (this.$replyTo) {
5714
+ onImagesLoaded(this.$replyTo, () => {
5715
+ checkEl(this.$replyTo);
5716
+ });
5717
+ }
5718
+ }
5719
+ }
5720
+ heightLimitRemove($el) {
5721
+ if (!$el)
5722
+ return;
5723
+ if (!$el.classList.contains("atk-height-limit"))
5724
+ return;
5725
+ $el.classList.remove("atk-height-limit");
5726
+ Array.from($el.children).forEach((e) => {
5727
+ if (e.classList.contains("atk-height-limit-btn"))
5728
+ e.remove();
5729
+ });
5730
+ $el.style.height = "";
5731
+ $el.style.overflow = "";
5732
+ }
5733
+ heightLimitRemoveForChildren() {
5734
+ if (!this.$childrenWrap)
5735
+ return;
5736
+ this.heightLimitRemove(this.$childrenWrap);
5737
+ }
5738
+ heightLimitAdd($el, maxHeight) {
5739
+ if (!$el)
5740
+ return;
5741
+ if ($el.classList.contains("atk-height-limit"))
5742
+ return;
5743
+ $el.classList.add("atk-height-limit");
5744
+ $el.style.height = `${maxHeight}px`;
5745
+ $el.style.overflow = "hidden";
5746
+ const $hideMoreOpenBtn = createElement(`<div class="atk-height-limit-btn">${this.ctx.$t("readMore")}</span>`);
5747
+ $hideMoreOpenBtn.onclick = (e) => {
5748
+ e.stopPropagation();
5749
+ this.heightLimitRemove($el);
5750
+ const children = this.comment.getChildren();
5751
+ if (children.length === 1)
5752
+ children[0].getRender().heightLimitRemove(children[0].getRender().$content);
5753
+ };
5754
+ $el.append($hideMoreOpenBtn);
5755
+ }
5756
+ playFadeAnim() {
5757
+ playFadeInAnim(this.comment.getRender().$el);
5758
+ }
5759
+ playFadeAnimForBody() {
5760
+ playFadeInAnim(this.comment.getRender().$body);
5761
+ }
5762
+ getChildrenWrap() {
5763
+ return this.$childrenWrap;
5764
+ }
5765
+ renderChildrenWrap() {
5766
+ if (!this.$childrenWrap) {
5767
+ this.$childrenWrap = createElement('<div class="atk-comment-children"></div>');
5768
+ this.$main.append(this.$childrenWrap);
5769
+ }
5770
+ return this.$childrenWrap;
5771
+ }
5772
+ recoveryChildrenWrap() {
5773
+ if (this.$childrenWrap) {
5774
+ this.$main.append(this.$childrenWrap);
5775
+ }
5776
+ }
5777
+ setUnread(val) {
5778
+ if (val)
5779
+ this.$el.classList.add("atk-unread");
5780
+ else
5781
+ this.$el.classList.remove("atk-unread");
5782
+ }
5783
+ setOpenable(val) {
5784
+ if (val)
5785
+ this.$el.classList.add("atk-openable");
5786
+ else
5787
+ this.$el.classList.remove("atk-openable");
5788
+ }
5789
+ setOpenURL(url) {
5790
+ this.setOpenable(true);
5791
+ this.$el.onclick = (evt) => {
5792
+ evt.preventDefault();
5793
+ window.open(url);
5794
+ if (this.cConf.openEvt)
5795
+ this.cConf.openEvt();
5796
+ };
5797
+ }
5798
+ setOpenAction(action) {
5799
+ this.setOpenable(true);
5800
+ this.$el.onclick = (evt) => {
5801
+ evt.preventDefault();
5802
+ action();
5803
+ };
5804
+ }
5805
+ }
5806
+ class CommentActions {
5807
+ constructor(comment2) {
5808
+ __publicField(this, "comment");
5809
+ this.comment = comment2;
5810
+ }
5811
+ get ctx() {
5812
+ return this.comment.ctx;
5813
+ }
5814
+ get data() {
5815
+ return this.comment.getData();
5816
+ }
5817
+ get cConf() {
5818
+ return this.comment.getConf();
5819
+ }
5820
+ vote(type) {
5821
+ const actionBtn = type === "up" ? this.comment.getRender().voteBtnUp : this.comment.getRender().voteBtnDown;
5822
+ this.ctx.getApi().vote(this.data.id, `comment_${type}`).then((v) => {
5823
+ var _a, _b;
5824
+ this.data.vote_up = v.up;
5825
+ this.data.vote_down = v.down;
5826
+ (_a = this.comment.getRender().voteBtnUp) == null ? void 0 : _a.updateText();
5827
+ (_b = this.comment.getRender().voteBtnDown) == null ? void 0 : _b.updateText();
5828
+ }).catch((err) => {
5829
+ actionBtn == null ? void 0 : actionBtn.setError(this.ctx.$t("voteFail"));
5830
+ console.log(err);
5831
+ });
5832
+ }
5833
+ adminEdit(type, btnElem) {
5834
+ if (btnElem.isLoading)
5835
+ return;
5836
+ btnElem.setLoading(true, `${this.ctx.$t("editing")}...`);
5837
+ const modify = __spreadValues({}, this.data);
5838
+ if (type === "collapsed") {
5839
+ modify.is_collapsed = !modify.is_collapsed;
5840
+ } else if (type === "pending") {
5841
+ modify.is_pending = !modify.is_pending;
5842
+ } else if (type === "pinned") {
5843
+ modify.is_pinned = !modify.is_pinned;
5844
+ }
5845
+ this.ctx.getApi().commentEdit(modify).then((data) => {
5846
+ btnElem.setLoading(false);
5847
+ this.comment.setData(data);
5848
+ this.ctx.listRefreshUI();
5849
+ }).catch((err) => {
5850
+ console.error(err);
5851
+ btnElem.setError(this.ctx.$t("editFail"));
5852
+ });
5853
+ }
5854
+ adminDelete(btnElem) {
5855
+ if (btnElem.isLoading)
5856
+ return;
5857
+ btnElem.setLoading(true, `${this.ctx.$t("deleting")}...`);
5858
+ this.ctx.getApi().commentDel(this.data.id, this.data.site_name).then(() => {
5859
+ btnElem.setLoading(false);
5860
+ if (this.cConf.onDelete)
5861
+ this.cConf.onDelete(this.comment);
5862
+ }).catch((e) => {
5863
+ console.error(e);
5864
+ btnElem.setError(this.ctx.$t("deleteFail"));
5018
5865
  });
5019
5866
  }
5020
- refreshUI() {
5021
- const originalEl = this.$el;
5022
- const newEl = this.render();
5023
- originalEl.replaceWith(newEl);
5024
- this.playFadeInAnim();
5025
- this.eachComment(this.children, (child) => {
5026
- var _a;
5027
- (_a = child.parent) == null ? void 0 : _a.getChildrenEl().appendChild(child.render());
5028
- child.playFadeInAnim();
5029
- });
5030
- this.ctx.trigger("comments-loaded");
5867
+ goToReplyComment() {
5868
+ const origHash = window.location.hash;
5869
+ const modifyHash = `#atk-comment-${this.data.rid}`;
5870
+ window.location.hash = modifyHash;
5871
+ if (modifyHash === origHash)
5872
+ window.dispatchEvent(new Event("hashchange"));
5873
+ }
5874
+ }
5875
+ class Comment extends Component {
5876
+ constructor(ctx, data, conf) {
5877
+ super(ctx);
5878
+ __publicField(this, "renderInstance");
5879
+ __publicField(this, "actionInstance");
5880
+ __publicField(this, "data");
5881
+ __publicField(this, "cConf");
5882
+ __publicField(this, "parent");
5883
+ __publicField(this, "children", []);
5884
+ __publicField(this, "nestCurt");
5885
+ __publicField(this, "nestMax");
5886
+ this.nestMax = ctx.conf.nestMax || 3;
5887
+ this.cConf = conf;
5888
+ this.data = __spreadValues({}, data);
5889
+ this.data.date = this.data.date.replace(/-/g, "/");
5890
+ this.parent = null;
5891
+ this.nestCurt = 1;
5892
+ this.actionInstance = new CommentActions(this);
5893
+ this.renderInstance = new CommentRender(this);
5894
+ }
5895
+ render() {
5896
+ const newEl = this.renderInstance.render();
5897
+ if (this.$el)
5898
+ this.$el.replaceWith(newEl);
5899
+ this.$el = newEl;
5900
+ if (this.cConf.afterRender)
5901
+ this.cConf.afterRender();
5902
+ }
5903
+ getActions() {
5904
+ return this.actionInstance;
5905
+ }
5906
+ getRender() {
5907
+ return this.renderInstance;
5908
+ }
5909
+ getData() {
5910
+ return this.data;
5911
+ }
5912
+ setData(data) {
5913
+ this.data = data;
5914
+ this.render();
5915
+ this.getRender().playFadeAnimForBody();
5031
5916
  }
5032
- eachComment(commentList, action) {
5033
- if (commentList.length === 0)
5034
- return;
5035
- commentList.every((item) => {
5036
- if (action(item, commentList) === false)
5037
- return false;
5038
- this.eachComment(item.getChildren(), action);
5039
- return true;
5040
- });
5917
+ getParent() {
5918
+ return this.parent;
5919
+ }
5920
+ getChildren() {
5921
+ return this.children;
5922
+ }
5923
+ getNestCurt() {
5924
+ return this.nestCurt;
5041
5925
  }
5042
5926
  getIsRoot() {
5043
5927
  return this.data.rid === 0;
5044
5928
  }
5045
- getChildren() {
5046
- return this.children;
5929
+ getID() {
5930
+ return this.data.id;
5047
5931
  }
5048
5932
  putChild(childC, insertMode = "append") {
5049
5933
  childC.parent = this;
@@ -5054,22 +5938,19 @@ class Comment extends Component {
5054
5938
  $children.append(childC.getEl());
5055
5939
  else if (insertMode === "prepend")
5056
5940
  $children.prepend(childC.getEl());
5057
- childC.playFadeInAnim();
5058
- childC.checkHeightLimitArea("content");
5941
+ childC.getRender().playFadeAnim();
5942
+ childC.getRender().checkHeightLimitArea("content");
5059
5943
  }
5060
5944
  getChildrenEl() {
5061
- if (!this.$children) {
5945
+ let $children = this.getRender().getChildrenWrap();
5946
+ if (!$children) {
5062
5947
  if (this.nestCurt < this.nestMax) {
5063
- this.$children = createElement('<div class="atk-comment-children"></div>');
5064
- this.$main.append(this.$children);
5065
- } else if (this.parent) {
5066
- this.$children = this.parent.getChildrenEl();
5948
+ $children = this.getRender().renderChildrenWrap();
5949
+ } else {
5950
+ $children = this.parent.getChildrenEl();
5067
5951
  }
5068
5952
  }
5069
- return this.$children;
5070
- }
5071
- getParent() {
5072
- return this.parent;
5953
+ return $children;
5073
5954
  }
5074
5955
  getParents() {
5075
5956
  const parents = [];
@@ -5085,17 +5966,14 @@ class Comment extends Component {
5085
5966
  getEl() {
5086
5967
  return this.$el;
5087
5968
  }
5088
- getData() {
5089
- return this.data;
5090
- }
5091
- getGravatarUrl() {
5969
+ getGravatarURL() {
5092
5970
  return getGravatarURL(this.ctx, this.data.email_encrypted);
5093
5971
  }
5094
5972
  getContentMarked() {
5095
5973
  return marked(this.ctx, this.data.content);
5096
5974
  }
5097
5975
  getDateFormatted() {
5098
- return timeAgo(new Date(this.data.date));
5976
+ return timeAgo(new Date(this.data.date), this.ctx);
5099
5977
  }
5100
5978
  getUserUaBrowser() {
5101
5979
  const info = Detect(this.data.ua);
@@ -5105,143 +5983,8 @@ class Comment extends Component {
5105
5983
  const info = Detect(this.data.ua);
5106
5984
  return `${info.os} ${info.osVersion}`;
5107
5985
  }
5108
- playFadeInAnim() {
5109
- playFadeInAnim(this.$el);
5110
- }
5111
- vote(type) {
5112
- const actionBtn = type === "up" ? this.voteBtnUp : this.voteBtnDown;
5113
- new Api(this.ctx).vote(this.data.id, `comment_${type}`).then((v) => {
5114
- var _a, _b;
5115
- this.data.vote_up = v.up;
5116
- this.data.vote_down = v.down;
5117
- (_a = this.voteBtnUp) == null ? void 0 : _a.updateText();
5118
- (_b = this.voteBtnDown) == null ? void 0 : _b.updateText();
5119
- }).catch((err) => {
5120
- actionBtn == null ? void 0 : actionBtn.setError(`\u6295\u7968\u5931\u8D25`);
5121
- console.log(err);
5122
- });
5123
- }
5124
- adminEdit(type, btnElem) {
5125
- if (btnElem.isLoading)
5126
- return;
5127
- btnElem.setLoading(true, "\u4FEE\u6539\u4E2D...");
5128
- const modify = __spreadValues({}, this.data);
5129
- if (type === "collapsed") {
5130
- modify.is_collapsed = !modify.is_collapsed;
5131
- } else if (type === "pending") {
5132
- modify.is_pending = !modify.is_pending;
5133
- } else if (type === "pinned") {
5134
- modify.is_pinned = !modify.is_pinned;
5135
- }
5136
- new Api(this.ctx).commentEdit(modify).then((comment2) => {
5137
- btnElem.setLoading(false);
5138
- this.data = comment2;
5139
- this.refreshUI();
5140
- playFadeInAnim(this.$body);
5141
- this.ctx.trigger("list-refresh-ui");
5142
- }).catch((err) => {
5143
- console.error(err);
5144
- btnElem.setError("\u4FEE\u6539\u5931\u8D25");
5145
- });
5146
- }
5147
- adminDelete(btnElem) {
5148
- if (btnElem.isLoading)
5149
- return;
5150
- btnElem.setLoading(true, "\u5220\u9664\u4E2D...");
5151
- new Api(this.ctx).commentDel(this.data.id, this.data.site_name).then(() => {
5152
- btnElem.setLoading(false);
5153
- if (this.onDelete)
5154
- this.onDelete(this);
5155
- }).catch((e) => {
5156
- console.error(e);
5157
- btnElem.setError("\u5220\u9664\u5931\u8D25");
5158
- });
5159
- }
5160
- setUnread(val) {
5161
- this.unread = val;
5162
- if (this.unread)
5163
- this.$el.classList.add("atk-unread");
5164
- else
5165
- this.$el.classList.remove("atk-unread");
5166
- }
5167
- setOpenURL(url) {
5168
- if (!url) {
5169
- this.openable = false;
5170
- this.$el.classList.remove("atk-openable");
5171
- }
5172
- this.openable = true;
5173
- this.openURL = url;
5174
- this.$el.classList.add("atk-openable");
5175
- }
5176
- checkHeightLimit() {
5177
- this.checkHeightLimitArea("content");
5178
- this.checkHeightLimitArea("children");
5179
- }
5180
- checkHeightLimitArea(area) {
5181
- var _a, _b;
5182
- const childrenMaxH = (_a = this.ctx.conf.heightLimit) == null ? void 0 : _a.children;
5183
- const contentMaxH = (_b = this.ctx.conf.heightLimit) == null ? void 0 : _b.content;
5184
- if (area === "children" && !childrenMaxH)
5185
- return;
5186
- if (area === "content" && !contentMaxH)
5187
- return;
5188
- let maxHeight;
5189
- if (area === "children")
5190
- maxHeight = childrenMaxH;
5191
- if (area === "content")
5192
- maxHeight = contentMaxH;
5193
- const checkEl = ($el) => {
5194
- if (!$el)
5195
- return;
5196
- if (getHeight($el) > maxHeight) {
5197
- this.heightLimitAdd($el, maxHeight);
5198
- }
5199
- };
5200
- if (area === "children") {
5201
- checkEl(this.$children);
5202
- } else if (area === "content") {
5203
- checkEl(this.$content);
5204
- checkEl(this.$replyTo);
5205
- onImagesLoaded(this.$content, () => {
5206
- checkEl(this.$content);
5207
- });
5208
- if (this.$replyTo) {
5209
- onImagesLoaded(this.$replyTo, () => {
5210
- checkEl(this.$replyTo);
5211
- });
5212
- }
5213
- }
5214
- }
5215
- heightLimitRemove($el) {
5216
- if (!$el)
5217
- return;
5218
- if (!$el.classList.contains("atk-height-limit"))
5219
- return;
5220
- $el.classList.remove("atk-height-limit");
5221
- Array.from($el.children).forEach((e) => {
5222
- if (e.classList.contains("atk-height-limit-btn"))
5223
- e.remove();
5224
- });
5225
- $el.style.height = "";
5226
- $el.style.overflow = "";
5227
- }
5228
- heightLimitAdd($el, maxHeight) {
5229
- if (!$el)
5230
- return;
5231
- if ($el.classList.contains("atk-height-limit"))
5232
- return;
5233
- $el.classList.add("atk-height-limit");
5234
- $el.style.height = `${maxHeight}px`;
5235
- $el.style.overflow = "hidden";
5236
- const $hideMoreOpenBtn = createElement(`<div class="atk-height-limit-btn">\u9605\u8BFB\u66F4\u591A</span>`);
5237
- $hideMoreOpenBtn.onclick = (e) => {
5238
- e.stopPropagation();
5239
- this.heightLimitRemove($el);
5240
- const children = this.getChildren();
5241
- if (children.length === 1)
5242
- children[0].heightLimitRemove(children[0].$content);
5243
- };
5244
- $el.append($hideMoreOpenBtn);
5986
+ getConf() {
5987
+ return this.cConf;
5245
5988
  }
5246
5989
  }
5247
5990
  var pagination = "";
@@ -5387,11 +6130,13 @@ class ReadMoreBtn {
5387
6130
  __publicField(this, "$text");
5388
6131
  __publicField(this, "offset", 0);
5389
6132
  __publicField(this, "total", 0);
6133
+ __publicField(this, "origText", "Load More");
5390
6134
  this.conf = conf;
6135
+ this.origText = this.conf.text || this.origText;
5391
6136
  this.$el = createElement(`<div class="atk-list-read-more" style="display: none;">
5392
6137
  <div class="atk-list-read-more-inner">
5393
6138
  <div class="atk-loading-icon" style="display: none;"></div>
5394
- <span class="atk-text">\u52A0\u8F7D\u66F4\u591A</span>
6139
+ <span class="atk-text">${this.origText}</span>
5395
6140
  </div>
5396
6141
  </div>`);
5397
6142
  this.$loading = this.$el.querySelector(".atk-loading-icon");
@@ -5423,7 +6168,7 @@ class ReadMoreBtn {
5423
6168
  this.$text.innerText = errMsg;
5424
6169
  this.$el.classList.add("atk-err");
5425
6170
  window.setTimeout(() => {
5426
- this.$text.innerText = "\u67E5\u770B\u66F4\u591A";
6171
+ this.$text.innerText = this.origText;
5427
6172
  this.$el.classList.remove("atk-err");
5428
6173
  }, 2e3);
5429
6174
  }
@@ -5490,15 +6235,14 @@ function makeNestCommentNodeList(srcData, sortBy = "DATE_DESC", nestMax = 2) {
5490
6235
  })(nodeList);
5491
6236
  return nodeList;
5492
6237
  }
5493
- const backendMinVersion = "2.1.4";
6238
+ const backendMinVersion = "2.1.7";
5494
6239
  class ListLite extends Component {
5495
6240
  constructor(ctx) {
5496
6241
  super(ctx);
5497
6242
  __publicField(this, "$commentsWrap");
5498
- __publicField(this, "commentList", []);
5499
6243
  __publicField(this, "data");
5500
6244
  __publicField(this, "isLoading", false);
5501
- __publicField(this, "noCommentText", "\u65E0\u5185\u5BB9");
6245
+ __publicField(this, "noCommentText");
5502
6246
  __publicField(this, "flatMode", false);
5503
6247
  __publicField(this, "nestSortBy");
5504
6248
  __publicField(this, "pageMode", "pagination");
@@ -5517,19 +6261,23 @@ class ListLite extends Component {
5517
6261
  <div class="atk-list-comments-wrap"></div>
5518
6262
  </div>`);
5519
6263
  this.$commentsWrap = this.$el.querySelector(".atk-list-comments-wrap");
5520
- if (ctx.conf.noComment)
5521
- this.noCommentText = ctx.conf.noComment;
6264
+ this.noCommentText = ctx.conf.noComment || ctx.$t("noComment");
5522
6265
  this.nestSortBy = this.ctx.conf.nestSort || "DATE_ASC";
5523
6266
  window.setInterval(() => {
5524
6267
  this.$el.querySelectorAll("[data-atk-comment-date]").forEach((el) => {
5525
6268
  const date = el.getAttribute("data-atk-comment-date");
5526
- el.innerText = timeAgo(new Date(Number(date)));
6269
+ el.innerText = timeAgo(new Date(Number(date)), this.ctx);
5527
6270
  });
5528
6271
  }, 30 * 1e3);
5529
- this.ctx.on("unread-update", (data) => this.updateUnread(data.notifies));
5530
6272
  }
5531
- get commentDataList() {
5532
- return this.commentList.map((c) => c.data);
6273
+ getData() {
6274
+ return this.data;
6275
+ }
6276
+ clearData() {
6277
+ this.data = void 0;
6278
+ }
6279
+ getCommentsWrapEl() {
6280
+ return this.$commentsWrap;
5533
6281
  }
5534
6282
  fetchComments(offset) {
5535
6283
  return __async(this, null, function* () {
@@ -5554,13 +6302,13 @@ class ListLite extends Component {
5554
6302
  this.pagination.setLoading(false);
5555
6303
  };
5556
6304
  showLoading$1();
5557
- this.ctx.trigger("comments-load");
6305
+ this.ctx.trigger("list-load");
5558
6306
  if (this.pageMode === "read-more" && offset === 0) {
5559
- this.clearAllComments();
6307
+ this.ctx.clearAllComments();
5560
6308
  }
5561
6309
  let listData;
5562
6310
  try {
5563
- listData = yield new Api(this.ctx).get(offset, this.pageSize, this.flatMode, this.paramsEditor);
6311
+ listData = yield this.ctx.getApi().get(offset, this.pageSize, this.flatMode, this.paramsEditor);
5564
6312
  } catch (e) {
5565
6313
  this.onError(e.msg || String(e), offset, e.data);
5566
6314
  throw e;
@@ -5581,13 +6329,13 @@ class ListLite extends Component {
5581
6329
  onLoad(data, offset) {
5582
6330
  var _a, _b;
5583
6331
  if (this.pageMode === "pagination") {
5584
- this.clearAllComments();
6332
+ this.ctx.clearAllComments();
5585
6333
  }
5586
6334
  this.data = data;
5587
6335
  const feMinVersion = ((_a = data.api_version) == null ? void 0 : _a.fe_min_version) || "0.0.0";
5588
- if (this.ctx.conf.versionCheck && this.versionCheck("\u524D\u7AEF", feMinVersion, "2.2.11"))
6336
+ if (this.ctx.conf.versionCheck && this.versionCheck("frontend", feMinVersion, "2.3.1"))
5589
6337
  return;
5590
- if (this.ctx.conf.versionCheck && this.versionCheck("\u540E\u7AEF", backendMinVersion, (_b = data.api_version) == null ? void 0 : _b.version))
6338
+ if (this.ctx.conf.versionCheck && this.versionCheck("backend", backendMinVersion, (_b = data.api_version) == null ? void 0 : _b.version))
5591
6339
  return;
5592
6340
  if (data.conf && typeof data.conf.img_upload === "boolean") {
5593
6341
  this.ctx.conf.imgUpload = data.conf.img_upload;
@@ -5595,8 +6343,8 @@ class ListLite extends Component {
5595
6343
  this.importComments(data.comments);
5596
6344
  this.refreshPagination(offset, this.flatMode ? data.total : data.total_roots);
5597
6345
  this.refreshUI();
5598
- this.ctx.trigger("unread-update", { notifies: data.unread || [] });
5599
- this.ctx.trigger("comments-loaded");
6346
+ this.ctx.updateNotifies(data.unread || []);
6347
+ this.ctx.trigger("list-loaded");
5600
6348
  this.ctx.trigger("conf-updated");
5601
6349
  if (this.onAfterLoad)
5602
6350
  this.onAfterLoad(data);
@@ -5614,16 +6362,16 @@ class ListLite extends Component {
5614
6362
  this.readMoreBtn.update(offset, total);
5615
6363
  }
5616
6364
  initPagination() {
5617
- var _a;
5618
6365
  if (this.pageMode === "read-more") {
5619
6366
  this.readMoreBtn = new ReadMoreBtn({
5620
6367
  pageSize: this.pageSize,
5621
6368
  onClick: (o) => __async(this, null, function* () {
5622
6369
  yield this.fetchComments(o);
5623
- })
6370
+ }),
6371
+ text: this.ctx.$t("loadMore")
5624
6372
  });
5625
6373
  this.$el.append(this.readMoreBtn.$el);
5626
- if ((_a = this.conf.pagination) == null ? void 0 : _a.autoLoad) {
6374
+ if (this.conf.pagination.autoLoad) {
5627
6375
  const at = this.scrollListenerAt || document;
5628
6376
  if (this.autoLoadScrollEvent)
5629
6377
  at.removeEventListener("scroll", this.autoLoadScrollEvent);
@@ -5651,7 +6399,7 @@ class ListLite extends Component {
5651
6399
  pageSize: this.pageSize,
5652
6400
  onChange: (o) => __async(this, null, function* () {
5653
6401
  if (this.ctx.conf.editorTravel === true) {
5654
- this.ctx.trigger("editor-travel-back");
6402
+ this.ctx.editorTravelBack();
5655
6403
  }
5656
6404
  yield this.fetchComments(o);
5657
6405
  if (this.repositionAt) {
@@ -5671,11 +6419,11 @@ class ListLite extends Component {
5671
6419
  msg = String(msg);
5672
6420
  console.error(msg);
5673
6421
  if (offset !== 0 && this.pageMode === "read-more") {
5674
- (_a = this.readMoreBtn) == null ? void 0 : _a.showErr(`\u83B7\u53D6\u5931\u8D25`);
6422
+ (_a = this.readMoreBtn) == null ? void 0 : _a.showErr(this.$t("loadFail"));
5675
6423
  return;
5676
6424
  }
5677
- const $err = createElement(`<span>${msg}\uFF0C\u65E0\u6CD5\u83B7\u53D6\u8BC4\u8BBA\u5217\u8868\u6570\u636E<br/></span>`);
5678
- const $retryBtn = createElement('<span style="cursor:pointer;">\u70B9\u51FB\u91CD\u65B0\u83B7\u53D6</span>');
6425
+ const $err = createElement(`<span>${msg}\uFF0C${this.$t("listLoadFailMsg")}<br/></span>`);
6426
+ const $retryBtn = createElement(`<span style="cursor:pointer;">${this.$t("listRetry")}</span>`);
5679
6427
  $retryBtn.onclick = () => this.fetchComments(0);
5680
6428
  $err.appendChild($retryBtn);
5681
6429
  const adminBtn = createElement('<span atk-only-admin-show> | <span style="cursor:pointer;">\u6253\u5F00\u63A7\u5236\u53F0</span></span>');
@@ -5690,13 +6438,13 @@ class ListLite extends Component {
5690
6438
  };
5691
6439
  sidebarView = `sites|${JSON.stringify(viewLoadParam)}`;
5692
6440
  }
5693
- adminBtn.onclick = () => this.ctx.trigger("sidebar-show", {
6441
+ adminBtn.onclick = () => this.ctx.showSidebar({
5694
6442
  view: sidebarView
5695
6443
  });
5696
6444
  setError(this.$el, $err);
5697
6445
  }
5698
6446
  refreshUI() {
5699
- const isNoComment = this.commentList.length <= 0;
6447
+ const isNoComment = this.ctx.getCommentList().length <= 0;
5700
6448
  let $noComment = this.$commentsWrap.querySelector(".atk-list-no-comment");
5701
6449
  if (isNoComment) {
5702
6450
  if (!$noComment) {
@@ -5707,22 +6455,28 @@ class ListLite extends Component {
5707
6455
  } else {
5708
6456
  $noComment == null ? void 0 : $noComment.remove();
5709
6457
  }
5710
- this.ctx.trigger("check-admin-show-el");
6458
+ this.ctx.checkAdminShowEl();
6459
+ }
6460
+ reload() {
6461
+ this.fetchComments(0);
5711
6462
  }
5712
6463
  createComment(cData, ctxData) {
5713
6464
  if (!ctxData)
5714
- ctxData = this.commentDataList;
5715
- const comment2 = new Comment(this.ctx, cData);
5716
- comment2.flatMode = this.flatMode;
5717
- comment2.afterRender = () => {
5718
- if (this.renderComment)
5719
- this.renderComment(comment2);
5720
- };
5721
- comment2.onDelete = (c) => {
5722
- this.deleteComment(c);
5723
- this.refreshUI();
5724
- };
5725
- comment2.replyTo = cData.rid ? ctxData.find((c) => c.id === cData.rid) : void 0;
6465
+ ctxData = this.ctx.getCommentDataList();
6466
+ const comment2 = new Comment(this.ctx, cData, {
6467
+ isFlatMode: this.flatMode,
6468
+ afterRender: () => {
6469
+ if (this.renderComment)
6470
+ this.renderComment(comment2);
6471
+ },
6472
+ onDelete: (c) => {
6473
+ this.ctx.deleteComment(c);
6474
+ this.refreshUI();
6475
+ },
6476
+ replyTo: cData.rid ? ctxData.find((c) => c.id === cData.rid) : void 0
6477
+ });
6478
+ comment2.render();
6479
+ this.ctx.getCommentList().push(comment2);
5726
6480
  return comment2;
5727
6481
  }
5728
6482
  importComments(srcData) {
@@ -5738,109 +6492,75 @@ class ListLite extends Component {
5738
6492
  const rootNodes = makeNestCommentNodeList(srcData, this.nestSortBy, this.conf.nestMax);
5739
6493
  rootNodes.forEach((rootNode) => {
5740
6494
  const rootC = this.createComment(rootNode.comment, srcData);
5741
- rootC.render();
5742
6495
  this.$commentsWrap.appendChild(rootC.getEl());
5743
- rootC.playFadeInAnim();
5744
- this.commentList.push(rootC);
6496
+ rootC.getRender().playFadeAnim();
5745
6497
  const that = this;
5746
6498
  (function loadChildren(parentC, parentNode) {
5747
6499
  parentNode.children.forEach((node) => {
5748
6500
  const childD = node.comment;
5749
6501
  const childC = that.createComment(childD, srcData);
5750
- childC.render();
5751
6502
  parentC.putChild(childC);
5752
- that.commentList.push(childC);
5753
6503
  loadChildren(childC, node);
5754
6504
  });
5755
6505
  })(rootC, rootNode);
5756
- rootC.checkHeightLimit();
6506
+ rootC.getRender().checkHeightLimit();
5757
6507
  });
5758
6508
  }
5759
6509
  putCommentFlatMode(cData, ctxData, insertMode) {
5760
6510
  if (cData.is_collapsed)
5761
6511
  cData.is_allow_reply = false;
5762
6512
  const comment2 = this.createComment(cData, ctxData);
5763
- comment2.render();
5764
- this.commentList.push(comment2);
5765
6513
  if (cData.visible) {
5766
6514
  if (insertMode === "append")
5767
6515
  this.$commentsWrap.append(comment2.getEl());
5768
6516
  if (insertMode === "prepend")
5769
6517
  this.$commentsWrap.prepend(comment2.getEl());
5770
- comment2.playFadeInAnim();
6518
+ comment2.getRender().playFadeAnim();
5771
6519
  }
5772
- comment2.checkHeightLimit();
6520
+ comment2.getRender().checkHeightLimit();
5773
6521
  return comment2;
5774
6522
  }
5775
6523
  insertComment(commentData) {
5776
6524
  if (!this.flatMode) {
5777
6525
  const comment2 = this.createComment(commentData);
5778
6526
  if (commentData.rid === 0) {
5779
- comment2.render();
5780
6527
  this.$commentsWrap.prepend(comment2.getEl());
5781
- this.commentList.push(comment2);
5782
6528
  } else {
5783
- const parent = this.findComment(commentData.rid);
6529
+ const parent = this.ctx.findComment(commentData.rid);
5784
6530
  if (parent) {
5785
- comment2.render();
5786
6531
  parent.putChild(comment2, this.nestSortBy === "DATE_ASC" ? "append" : "prepend");
5787
6532
  comment2.getParents().forEach((p) => {
5788
- if (p.$children)
5789
- p.heightLimitRemove(p.$children);
6533
+ p.getRender().heightLimitRemoveForChildren();
5790
6534
  });
5791
6535
  }
5792
6536
  }
5793
- comment2.checkHeightLimit();
6537
+ comment2.getRender().checkHeightLimit();
5794
6538
  scrollIntoView(comment2.getEl());
5795
- comment2.playFadeInAnim();
6539
+ comment2.getRender().playFadeAnim();
5796
6540
  } else {
5797
- const comment2 = this.putCommentFlatMode(commentData, this.commentDataList, "prepend");
6541
+ const comment2 = this.putCommentFlatMode(commentData, this.ctx.getCommentDataList(), "prepend");
5798
6542
  scrollIntoView(comment2.getEl());
5799
6543
  }
5800
6544
  if (this.data)
5801
6545
  this.data.total += 1;
5802
6546
  this.refreshUI();
5803
- this.ctx.trigger("comments-loaded");
5804
- }
5805
- findComment(id) {
5806
- return this.commentList.find((c) => c.data.id === id);
5807
- }
5808
- deleteComment(_comment) {
5809
- let comment2;
5810
- if (typeof _comment === "number") {
5811
- const findComment = this.findComment(_comment);
5812
- if (!findComment)
5813
- throw Error(`\u672A\u627E\u5230\u8BC4\u8BBA ${_comment}`);
5814
- comment2 = findComment;
5815
- } else
5816
- comment2 = _comment;
5817
- comment2.getEl().remove();
5818
- this.commentList.splice(this.commentList.indexOf(comment2), 1);
5819
- if (this.data)
5820
- this.data.total -= 1;
5821
- this.refreshUI();
5822
- }
5823
- clearAllComments() {
5824
- this.$commentsWrap.innerHTML = "";
5825
- this.data = void 0;
5826
- this.commentList = [];
6547
+ this.ctx.trigger("list-loaded");
6548
+ this.ctx.trigger("list-inserted", commentData);
5827
6549
  }
5828
6550
  updateUnread(notifies) {
5829
6551
  this.unread = notifies;
5830
6552
  if (this.unreadHighlight === true) {
5831
- this.commentList.forEach((comment2) => {
5832
- const notify = this.unread.find((o) => o.comment_id === comment2.data.id);
6553
+ this.ctx.getCommentList().forEach((comment2) => {
6554
+ const notify = this.unread.find((o) => o.comment_id === comment2.getID());
5833
6555
  if (notify) {
5834
- comment2.setUnread(true);
5835
- comment2.setOpenURL(notify.read_link);
5836
- comment2.openEvt = () => {
5837
- this.unread = this.unread.filter((o) => o.comment_id !== comment2.data.id);
5838
- this.ctx.trigger("unread-update", {
5839
- notifies: this.unread
5840
- });
5841
- };
6556
+ comment2.getRender().setUnread(true);
6557
+ comment2.getRender().setOpenAction(() => {
6558
+ window.open(notify.read_link);
6559
+ this.unread = this.unread.filter((o) => o.comment_id !== comment2.getID());
6560
+ this.ctx.updateNotifies(this.unread);
6561
+ });
5842
6562
  } else {
5843
- comment2.setUnread(false);
6563
+ comment2.getRender().setUnread(false);
5844
6564
  }
5845
6565
  });
5846
6566
  }
@@ -5848,7 +6568,7 @@ class ListLite extends Component {
5848
6568
  versionCheck(name, needVersion, curtVersion) {
5849
6569
  const needUpdate = versionCompare(needVersion, curtVersion) === 1;
5850
6570
  if (needUpdate) {
5851
- const errEl = createElement(`<div>Artalk ${name}\u7248\u672C\u5DF2\u8FC7\u65F6\uFF0C\u8BF7\u66F4\u65B0\u4EE5\u83B7\u5F97\u5B8C\u6574\u4F53\u9A8C<br/>\u5982\u679C\u4F60\u662F\u7BA1\u7406\u5458\uFF0C\u8BF7\u524D\u5F80 \u201C<a href="https://artalk.js.org/" target="_blank">\u5B98\u65B9\u6587\u6863</a>\u201D \u83B7\u5F97\u5E2E\u52A9<br/><br/><span style="color: var(--at-color-meta);">\u5F53\u524D${name}\u7248\u672C ${curtVersion}\uFF0C\u9700\u6C42\u7248\u672C >= ${needVersion}</span><br/><br/></div>`);
6571
+ const errEl = createElement(`<div>Artalk ${this.$t(name)}\u7248\u672C\u5DF2\u8FC7\u65F6\uFF0C\u8BF7\u66F4\u65B0\u4EE5\u83B7\u5F97\u5B8C\u6574\u4F53\u9A8C<br/>\u5982\u679C\u4F60\u662F\u7BA1\u7406\u5458\uFF0C\u8BF7\u524D\u5F80 \u201C<a href="https://artalk.js.org/" target="_blank">\u5B98\u65B9\u6587\u6863</a>\u201D \u83B7\u5F97\u5E2E\u52A9<br/><br/><span style="color: var(--at-color-meta);">\u5F53\u524D${this.$t(name)}\u7248\u672C ${curtVersion}\uFF0C\u9700\u6C42\u7248\u672C >= ${needVersion}</span><br/><br/></div>`);
5852
6572
  const ignoreBtn = createElement('<span style="cursor:pointer;">\u5FFD\u7565</span>');
5853
6573
  ignoreBtn.onclick = () => {
5854
6574
  setError(this.$el.parentElement, null);
@@ -5864,55 +6584,46 @@ class ListLite extends Component {
5864
6584
  }
5865
6585
  class List extends ListLite {
5866
6586
  constructor(ctx) {
5867
- var _a, _b;
5868
6587
  const el = createElement(ListHTML);
5869
6588
  super(ctx);
5870
6589
  __publicField(this, "$closeCommentBtn");
5871
6590
  __publicField(this, "$openSidebarBtn");
5872
6591
  __publicField(this, "$unreadBadge");
5873
6592
  __publicField(this, "$commentCount");
6593
+ __publicField(this, "$commentCountNum");
5874
6594
  __publicField(this, "$dropdownWrap");
5875
6595
  __publicField(this, "goToCommentFounded", false);
5876
6596
  __publicField(this, "goToCommentDelay", true);
5877
6597
  el.querySelector(".atk-list-body").append(this.$el);
5878
6598
  this.$el = el;
5879
- let flatMode = false;
5880
- if (this.ctx.conf.flatMode === "auto") {
6599
+ if (this.ctx.conf.flatMode === true) {
6600
+ this.flatMode = true;
6601
+ } else if (this.conf.nestMax && this.conf.nestMax <= 1) {
6602
+ this.flatMode = true;
6603
+ } else if (this.ctx.conf.flatMode === "auto") {
5881
6604
  if (window.matchMedia("(max-width: 768px)").matches)
5882
- flatMode = true;
5883
- } else if (this.ctx.conf.flatMode === true) {
5884
- flatMode = true;
6605
+ this.flatMode = true;
5885
6606
  }
5886
- this.flatMode = flatMode;
5887
- this.pageMode = ((_a = this.conf.pagination) == null ? void 0 : _a.readMore) ? "read-more" : "pagination";
5888
- this.pageSize = ((_b = this.conf.pagination) == null ? void 0 : _b.pageSize) || 20;
6607
+ this.pageMode = this.conf.pagination.readMore ? "read-more" : "pagination";
6608
+ this.pageSize = this.conf.pagination.pageSize || 20;
5889
6609
  this.repositionAt = this.$el;
5890
6610
  this.initListActionBtn();
5891
6611
  this.$commentCount = this.$el.querySelector(".atk-comment-count");
6612
+ this.$commentCount.innerHTML = this.$t("counter", {
6613
+ count: '<span class="atk-comment-count-num">0</span>'
6614
+ });
6615
+ this.$commentCountNum = this.$commentCount.querySelector(".atk-comment-count-num");
5892
6616
  if (this.ctx.conf.listSort) {
5893
6617
  this.initDropdown();
5894
6618
  }
5895
- this.$el.querySelector(".atk-copyright").innerHTML = `Powered By <a href="https://artalk.js.org" target="_blank" title="Artalk v${"2.2.11"}">Artalk</a>`;
5896
- this.ctx.on("list-reload", () => this.fetchComments(0));
5897
- this.ctx.on("list-refresh-ui", () => this.refreshUI());
5898
- this.ctx.on("list-import", (data) => this.importComments(data));
5899
- this.ctx.on("list-insert", (data) => this.insertComment(data));
5900
- this.ctx.on("list-delete", (comment2) => this.deleteComment(comment2.id));
5901
- this.ctx.on("list-update", (updateData) => {
5902
- updateData(this.data);
5903
- this.refreshUI();
5904
- });
5905
- this.ctx.on("unread-update", (data) => {
5906
- var _a2;
5907
- return this.showUnreadBadge(((_a2 = data.notifies) == null ? void 0 : _a2.length) || 0);
5908
- });
6619
+ this.$el.querySelector(".atk-copyright").innerHTML = `Powered By <a href="https://artalk.js.org" target="_blank" title="Artalk v${"2.3.1"}">Artalk</a>`;
5909
6620
  }
5910
6621
  initListActionBtn() {
5911
6622
  this.$openSidebarBtn = this.$el.querySelector('[data-action="open-sidebar"]');
5912
6623
  this.$closeCommentBtn = this.$el.querySelector('[data-action="admin-close-comment"]');
5913
6624
  this.$unreadBadge = this.$el.querySelector(".atk-unread-badge");
5914
6625
  this.$openSidebarBtn.addEventListener("click", () => {
5915
- this.ctx.trigger("sidebar-show");
6626
+ this.ctx.showSidebar();
5916
6627
  });
5917
6628
  this.$closeCommentBtn.addEventListener("click", () => {
5918
6629
  if (!this.data)
@@ -5924,20 +6635,20 @@ class List extends ListLite {
5924
6635
  refreshUI() {
5925
6636
  var _a;
5926
6637
  super.refreshUI();
5927
- this.$el.querySelector(".atk-comment-count-num").innerText = String(Number((_a = this.data) == null ? void 0 : _a.total) || 0);
6638
+ this.$commentCountNum.innerText = String(Number((_a = this.data) == null ? void 0 : _a.total) || 0);
5928
6639
  if (!!this.ctx.user.data.nick && !!this.ctx.user.data.email) {
5929
6640
  this.$openSidebarBtn.classList.remove("atk-hide");
5930
6641
  } else {
5931
6642
  this.$openSidebarBtn.classList.add("atk-hide");
5932
6643
  }
5933
- this.ctx.trigger("check-admin-show-el");
5934
- this.$openSidebarBtn.querySelector(".atk-text").innerText = !this.ctx.user.data.isAdmin ? "\u901A\u77E5\u4E2D\u5FC3" : "\u63A7\u5236\u4E2D\u5FC3";
6644
+ this.ctx.checkAdminShowEl();
6645
+ this.$openSidebarBtn.querySelector(".atk-text").innerText = !this.ctx.user.data.isAdmin ? this.$t("msgCenter") : this.$t("ctrlCenter");
5935
6646
  if (!!this.data && !!this.data.page && this.data.page.admin_only === true) {
5936
- this.ctx.trigger("editor-close");
5937
- this.$closeCommentBtn.innerHTML = "\u6253\u5F00\u8BC4\u8BBA";
6647
+ this.ctx.editorClose();
6648
+ this.$closeCommentBtn.innerHTML = this.$t("openComment");
5938
6649
  } else {
5939
- this.ctx.trigger("editor-open");
5940
- this.$closeCommentBtn.innerHTML = "\u5173\u95ED\u8BC4\u8BBA";
6650
+ this.ctx.editorOpen();
6651
+ this.$closeCommentBtn.innerHTML = this.$t("closeComment");
5941
6652
  }
5942
6653
  }
5943
6654
  onLoad(data, offset) {
@@ -5945,7 +6656,7 @@ class List extends ListLite {
5945
6656
  if (!this.goToCommentFounded)
5946
6657
  this.checkGoToCommentByUrlHash();
5947
6658
  if (this.ctx.conf.editorTravel === true) {
5948
- this.ctx.trigger("editor-travel-back");
6659
+ this.ctx.editorTravelBack();
5949
6660
  }
5950
6661
  }
5951
6662
  checkGoToCommentByUrlHash() {
@@ -5958,7 +6669,7 @@ class List extends ListLite {
5958
6669
  }
5959
6670
  if (!commentId)
5960
6671
  return;
5961
- const comment2 = this.findComment(commentId);
6672
+ const comment2 = this.ctx.findComment(commentId);
5962
6673
  if (!comment2) {
5963
6674
  if (this.readMoreBtn)
5964
6675
  this.readMoreBtn.click();
@@ -5968,16 +6679,13 @@ class List extends ListLite {
5968
6679
  }
5969
6680
  const notifyKey = getQueryParam("atk_notify_key");
5970
6681
  if (notifyKey) {
5971
- new Api(this.ctx).markRead(notifyKey).then(() => {
6682
+ this.ctx.getApi().markRead(notifyKey).then(() => {
5972
6683
  this.unread = this.unread.filter((o) => o.comment_id !== commentId);
5973
- this.ctx.trigger("unread-update", {
5974
- notifies: this.unread
5975
- });
6684
+ this.updateUnread(this.unread);
5976
6685
  });
5977
6686
  }
5978
6687
  comment2.getParents().forEach((p) => {
5979
- if (p.$children)
5980
- p.heightLimitRemove(p.$children);
6688
+ p.getRender().heightLimitRemoveForChildren();
5981
6689
  });
5982
6690
  const goTo = () => {
5983
6691
  scrollIntoView(comment2.getEl(), false);
@@ -5995,15 +6703,15 @@ class List extends ListLite {
5995
6703
  adminPageEditSave() {
5996
6704
  if (!this.data || !this.data.page)
5997
6705
  return;
5998
- this.ctx.trigger("editor-show-loading");
5999
- new Api(this.ctx).pageEdit(this.data.page).then((page) => {
6706
+ this.ctx.editorShowLoading();
6707
+ this.ctx.getApi().pageEdit(this.data.page).then((page) => {
6000
6708
  if (this.data)
6001
6709
  this.data.page = __spreadValues({}, page);
6002
6710
  this.refreshUI();
6003
6711
  }).catch((err) => {
6004
- this.ctx.trigger("editor-notify", { msg: `\u4FEE\u6539\u9875\u9762\u6570\u636E\u5931\u8D25\uFF1A${err.msg || String(err)}`, type: "e" });
6712
+ this.ctx.editorShowNotify(`${this.$t("editFail")}: ${err.msg || String(err)}`, "e");
6005
6713
  }).finally(() => {
6006
- this.ctx.trigger("editor-hide-loading");
6714
+ this.ctx.editorHideLoading();
6007
6715
  });
6008
6716
  }
6009
6717
  showUnreadBadge(count) {
@@ -6025,22 +6733,22 @@ class List extends ListLite {
6025
6733
  this.fetchComments(0);
6026
6734
  };
6027
6735
  const dropdownList = [
6028
- ["\u6700\u65B0", () => {
6736
+ [this.$t("sortLatest"), () => {
6029
6737
  reloadUseParamsEditor((p) => {
6030
6738
  p.sort_by = "date_desc";
6031
6739
  });
6032
6740
  }],
6033
- ["\u6700\u70ED", () => {
6741
+ [this.$t("sortBest"), () => {
6034
6742
  reloadUseParamsEditor((p) => {
6035
6743
  p.sort_by = "vote";
6036
6744
  });
6037
6745
  }],
6038
- ["\u6700\u65E9", () => {
6746
+ [this.$t("sortOldest"), () => {
6039
6747
  reloadUseParamsEditor((p) => {
6040
6748
  p.sort_by = "date_asc";
6041
6749
  });
6042
6750
  }],
6043
- ["\u4F5C\u8005", () => {
6751
+ [this.$t("sortAuthor"), () => {
6044
6752
  reloadUseParamsEditor((p) => {
6045
6753
  p.view_only_admin = true;
6046
6754
  });
@@ -6075,6 +6783,10 @@ class List extends ListLite {
6075
6783
  });
6076
6784
  this.$dropdownWrap.append($dropdown);
6077
6785
  }
6786
+ updateUnread(notifies) {
6787
+ super.updateUnread(notifies);
6788
+ this.showUnreadBadge((notifies == null ? void 0 : notifies.length) || 0);
6789
+ }
6078
6790
  }
6079
6791
  var sidebarLayer = "";
6080
6792
  var 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';
@@ -6087,7 +6799,6 @@ class SidebarLayer extends Component {
6087
6799
  __publicField(this, "$iframeWrap");
6088
6800
  __publicField(this, "$iframe");
6089
6801
  __publicField(this, "firstShow", true);
6090
- __publicField(this, "loadingTimer", null);
6091
6802
  this.$el = createElement(SidebarHTML);
6092
6803
  this.$header = this.$el.querySelector(".atk-sidebar-header");
6093
6804
  this.$closeBtn = this.$header.querySelector(".atk-sidebar-close");
@@ -6095,20 +6806,18 @@ class SidebarLayer extends Component {
6095
6806
  this.$closeBtn.onclick = () => {
6096
6807
  this.hide();
6097
6808
  };
6098
- this.ctx.on("sidebar-show", (conf) => this.show(conf || {}));
6099
- this.ctx.on("sidebar-hide", () => this.hide());
6100
6809
  this.ctx.on("user-changed", () => {
6101
6810
  this.firstShow = true;
6102
6811
  });
6103
6812
  }
6104
- show(conf) {
6105
- return __async(this, null, function* () {
6813
+ show() {
6814
+ return __async(this, arguments, function* (conf = {}) {
6106
6815
  this.$el.style.transform = "";
6107
6816
  if (this.layer == null) {
6108
6817
  this.layer = new Layer(this.ctx, "sidebar", this.$el);
6109
6818
  this.layer.afterHide = () => {
6110
6819
  if (this.ctx.conf.editorTravel === true) {
6111
- this.ctx.trigger("editor-travel-back");
6820
+ this.ctx.editorTravelBack();
6112
6821
  }
6113
6822
  };
6114
6823
  }
@@ -6118,11 +6827,11 @@ class SidebarLayer extends Component {
6118
6827
  }, 20);
6119
6828
  (() => __async(this, null, function* () {
6120
6829
  var _a;
6121
- const resp = yield new Api(this.ctx).loginStatus();
6830
+ const resp = yield this.ctx.getApi().loginStatus();
6122
6831
  if (resp.is_admin && !resp.is_login) {
6123
6832
  (_a = this.layer) == null ? void 0 : _a.hide();
6124
6833
  this.firstShow = true;
6125
- this.ctx.trigger("checker-admin", {
6834
+ this.ctx.checkAdmin({
6126
6835
  onSuccess: () => {
6127
6836
  setTimeout(() => {
6128
6837
  this.show(conf);
@@ -6133,7 +6842,7 @@ class SidebarLayer extends Component {
6133
6842
  });
6134
6843
  }
6135
6844
  }))();
6136
- this.ctx.trigger("unread-update", { notifies: [] });
6845
+ this.ctx.updateNotifies([]);
6137
6846
  if (this.firstShow) {
6138
6847
  this.$iframeWrap.innerHTML = "";
6139
6848
  this.$iframe = createElement("<iframe></iframe>");
@@ -6159,12 +6868,14 @@ class SidebarLayer extends Component {
6159
6868
  if (!this.conf.darkMode && isIframeSrcDarkMode)
6160
6869
  this.iframeLoad(this.$iframe.src.replace("&darkMode=1", ""));
6161
6870
  }
6871
+ this.ctx.trigger("sidebar-show");
6162
6872
  });
6163
6873
  }
6164
6874
  hide() {
6165
6875
  var _a;
6166
6876
  this.$el.style.transform = "";
6167
6877
  (_a = this.layer) == null ? void 0 : _a.hide();
6878
+ this.ctx.trigger("sidebar-hide");
6168
6879
  }
6169
6880
  iframeLoad(src) {
6170
6881
  if (!this.$iframe)
@@ -6175,94 +6886,112 @@ class SidebarLayer extends Component {
6175
6886
  hideLoading(this.$iframeWrap);
6176
6887
  };
6177
6888
  }
6178
- checkReqStatus(url) {
6179
- return __async(this, null, function* () {
6180
- if (this.loadingTimer !== null)
6181
- window.clearTimeout(this.loadingTimer);
6182
- this.loadingTimer = window.setTimeout(() => __async(this, null, function* () {
6183
- try {
6184
- yield fetch(url);
6185
- } catch (err) {
6186
- console.log(err);
6187
- const $errAlert = createElement(`<div class="atk-err-alert"> <div class="atk-title">\u4FA7\u8FB9\u680F\u4F3C\u4E4E\u6253\u5F00\u5931\u8D25</div> <div class="atk-text"><span id="AtkReload">\u91CD\u65B0\u52A0\u8F7D</span> / <span id="AtkCancel">\u53D6\u6D88</span></div></div>`);
6188
- const $reloadBtn = $errAlert.querySelector("#AtkReload");
6189
- const $cancelBtn = $errAlert.querySelector("#AtkCancel");
6190
- $reloadBtn.onclick = () => {
6191
- this.iframeLoad(url);
6192
- $errAlert.remove();
6193
- };
6194
- $cancelBtn.onclick = () => {
6195
- $errAlert.remove();
6196
- };
6197
- this.$iframeWrap.append($errAlert);
6198
- }
6199
- }), 2e3);
6889
+ }
6890
+ const PvCountWidget = (ctx) => {
6891
+ initCountWidget({ ctx, pvAdd: true });
6892
+ };
6893
+ function initCountWidget(p) {
6894
+ return __async(this, null, function* () {
6895
+ const countEl = p.ctx.conf.countEl;
6896
+ if (countEl && document.querySelector(countEl)) {
6897
+ handleStatCount(p, { api: "page_comment", countEl });
6898
+ }
6899
+ const curtPagePvNum = p.pvAdd ? yield p.ctx.getApi().pv() : void 0;
6900
+ const pvEl = p.ctx.conf.pvEl;
6901
+ if (pvEl && document.querySelector(pvEl)) {
6902
+ handleStatCount(p, {
6903
+ api: "page_pv",
6904
+ countEl: pvEl,
6905
+ curtPageCount: curtPagePvNum
6906
+ });
6907
+ }
6908
+ });
6909
+ }
6910
+ function handleStatCount(p, args) {
6911
+ return __async(this, null, function* () {
6912
+ let pageCounts = {};
6913
+ const curtPageKey = p.ctx.conf.pageKey;
6914
+ if (args.curtPageCount)
6915
+ pageCounts[curtPageKey] = args.curtPageCount;
6916
+ let queryPageKeys = Array.from(document.querySelectorAll(args.countEl)).map((e) => e.getAttribute("data-page-key") || curtPageKey).filter((pageKey) => pageCounts[pageKey] === void 0);
6917
+ queryPageKeys = [...new Set(queryPageKeys)];
6918
+ if (queryPageKeys.length > 0) {
6919
+ const counts = yield p.ctx.getApi().stat(args.api, queryPageKeys);
6920
+ pageCounts = __spreadValues(__spreadValues({}, pageCounts), counts);
6921
+ }
6922
+ document.querySelectorAll(args.countEl).forEach((el) => {
6923
+ const pageKey = el.getAttribute("data-page-key") || curtPageKey;
6924
+ el.innerHTML = `${Number(pageCounts[pageKey] || 0)}`;
6200
6925
  });
6201
- }
6926
+ });
6202
6927
  }
6203
6928
  const _Artalk = class {
6204
6929
  constructor(customConf) {
6205
- __publicField(this, "ctx");
6206
6930
  __publicField(this, "conf");
6931
+ __publicField(this, "ctx");
6207
6932
  __publicField(this, "$root");
6208
6933
  __publicField(this, "checkerLauncher");
6209
6934
  __publicField(this, "editor");
6210
6935
  __publicField(this, "list");
6211
6936
  __publicField(this, "sidebarLayer");
6212
- this.conf = mergeDeep(_Artalk.defaults, customConf);
6213
- this.conf.server = this.conf.server.replace(/\/$/, "").replace(/\/api\/?$/, "");
6214
- if (!this.conf.pageKey) {
6215
- this.conf.pageKey = `${window.location.pathname}`;
6216
- }
6217
- if (!this.conf.pageTitle) {
6218
- this.conf.pageTitle = `${document.title}`;
6219
- }
6220
- if (this.conf.nestMax && this.conf.nestMax <= 1) {
6221
- this.conf.flatMode = true;
6222
- }
6223
- if (!!this.conf.el && this.conf.el instanceof HTMLElement) {
6937
+ this.conf = _Artalk.HandelBaseConf(customConf);
6938
+ if (this.conf.el instanceof HTMLElement)
6224
6939
  this.$root = this.conf.el;
6225
- } else {
6226
- try {
6227
- const $root = document.querySelector(this.conf.el);
6228
- if (!$root)
6229
- throw Error(`Sorry, target element "${this.conf.el}" was not found.`);
6230
- this.$root = $root;
6231
- } catch (e) {
6232
- console.error(e);
6233
- throw new Error("Please check your Artalk `el` config.");
6234
- }
6235
- }
6236
- this.ctx = new Context(this.$root, this.conf);
6237
- this.$root.classList.add("artalk");
6238
- this.$root.innerHTML = "";
6239
- if (this.conf.useBackendConf) {
6240
- return (() => __async(this, null, function* () {
6241
- yield this.loadConfRemote();
6242
- this.initCore();
6243
- return this;
6244
- }))();
6245
- }
6246
- this.initCore();
6940
+ this.ctx = new Context(this.conf, this.$root);
6941
+ if (this.conf.useBackendConf)
6942
+ return this.loadConfRemoteAndInitComponents();
6943
+ this.initComponents();
6247
6944
  }
6248
- initCore() {
6945
+ initComponents() {
6946
+ this.initLocale();
6249
6947
  this.initLayer();
6250
6948
  this.initDarkMode();
6251
- this.checkerLauncher = new CheckerLauncher(this.ctx);
6252
6949
  initMarked(this.ctx);
6950
+ this.checkerLauncher = new CheckerLauncher(this.ctx);
6951
+ this.ctx.setCheckerLauncher(this.checkerLauncher);
6253
6952
  this.editor = new Editor(this.ctx);
6953
+ this.ctx.setEditor(this.editor);
6254
6954
  this.$root.appendChild(this.editor.$el);
6255
6955
  this.list = new List(this.ctx);
6956
+ this.ctx.setList(this.list);
6256
6957
  this.$root.appendChild(this.list.$el);
6257
6958
  this.sidebarLayer = new SidebarLayer(this.ctx);
6959
+ this.ctx.setSidebarLayer(this.sidebarLayer);
6258
6960
  this.$root.appendChild(this.sidebarLayer.$el);
6259
6961
  this.list.fetchComments(0);
6260
6962
  this.initEventBind();
6261
- this.initPV();
6262
6963
  _Artalk.Plugins.forEach((plugin) => {
6263
- if (typeof plugin === "function") {
6964
+ if (typeof plugin === "function")
6264
6965
  plugin(this.ctx);
6966
+ });
6967
+ }
6968
+ static HandelBaseConf(customConf) {
6969
+ const conf = mergeDeep(_Artalk.defaults, customConf);
6970
+ if (typeof conf.el === "string" && !!conf.el) {
6971
+ try {
6972
+ const findEl = document.querySelector(conf.el);
6973
+ if (!findEl)
6974
+ throw Error(`Target element "${conf.el}" was not found.`);
6975
+ conf.el = findEl;
6976
+ } catch (e) {
6977
+ console.error(e);
6978
+ throw new Error("Please check your Artalk `el` config.");
6265
6979
  }
6980
+ }
6981
+ conf.server = conf.server.replace(/\/$/, "").replace(/\/api\/?$/, "");
6982
+ if (!conf.pageKey) {
6983
+ conf.pageKey = `${window.location.pathname}`;
6984
+ }
6985
+ if (!conf.pageTitle) {
6986
+ conf.pageTitle = `${document.title}`;
6987
+ }
6988
+ return conf;
6989
+ }
6990
+ loadConfRemoteAndInitComponents() {
6991
+ return __async(this, null, function* () {
6992
+ yield this.loadConfRemote();
6993
+ this.initComponents();
6994
+ return this;
6266
6995
  });
6267
6996
  }
6268
6997
  loadConfRemote() {
@@ -6270,9 +6999,9 @@ const _Artalk = class {
6270
6999
  showLoading(this.$root);
6271
7000
  let backendConf = {};
6272
7001
  try {
6273
- backendConf = yield new Api(this.ctx).conf();
7002
+ backendConf = yield this.ctx.getApi().conf();
6274
7003
  } catch (err) {
6275
- console.error("\u914D\u7F6E\u8FDC\u7A0B\u83B7\u53D6\u5931\u8D25", err);
7004
+ console.error("Load config from remote err", err);
6276
7005
  }
6277
7006
  this.ctx.conf = mergeDeep(this.ctx.conf, backendConf);
6278
7007
  hideLoading(this.$root);
@@ -6283,36 +7012,42 @@ const _Artalk = class {
6283
7012
  this.list.goToCommentDelay = false;
6284
7013
  this.list.checkGoToCommentByUrlHash();
6285
7014
  });
6286
- this.ctx.on("check-admin-show-el", () => {
6287
- const items = [];
6288
- this.$root.querySelectorAll(`[atk-only-admin-show]`).forEach((item) => items.push(item));
6289
- const { $wrap: $layerWrap } = GetLayerWrap(this.ctx);
6290
- if ($layerWrap)
6291
- $layerWrap.querySelectorAll(`[atk-only-admin-show]`).forEach((item) => items.push(item));
6292
- const $sidebarEl = document.querySelector(".atk-sidebar");
6293
- if ($sidebarEl)
6294
- $sidebarEl.querySelectorAll(`[atk-only-admin-show]`).forEach((item) => items.push(item));
6295
- items.forEach(($item) => {
6296
- if (this.ctx.user.data.isAdmin)
6297
- $item.classList.remove("atk-hide");
6298
- else
6299
- $item.classList.add("atk-hide");
6300
- });
6301
- });
6302
7015
  this.ctx.on("user-changed", () => {
6303
- this.ctx.trigger("check-admin-show-el");
6304
- this.ctx.trigger("list-refresh-ui");
7016
+ this.ctx.checkAdminShowEl();
7017
+ this.ctx.listRefreshUI();
6305
7018
  });
6306
7019
  }
6307
- reload() {
6308
- this.list.fetchComments(0);
7020
+ initLocale() {
7021
+ if (typeof this.conf.locale === "string") {
7022
+ if (this.conf.locale === "auto") {
7023
+ this.conf.locale = navigator.languages ? navigator.languages[0] : navigator.language;
7024
+ }
7025
+ this.conf.locale = this.conf.locale.replace(/^([a-zA-Z]+)(-[a-zA-Z]+)?$/, (_, p1, p2) => p1.toLowerCase() + (p2 || "").toUpperCase());
7026
+ if (!internal[this.conf.locale]) {
7027
+ console.log(`Locale "${this.conf.locale}" not found.`);
7028
+ this.conf.locale = "en";
7029
+ }
7030
+ }
6309
7031
  }
6310
7032
  initLayer() {
6311
7033
  Layer.BodyOrgOverflow = document.body.style.overflow;
6312
7034
  Layer.BodyOrgPaddingRight = document.body.style.paddingRight;
6313
7035
  }
6314
7036
  initDarkMode() {
7037
+ if (this.conf.darkMode === "auto") {
7038
+ const darkModeMedia = window.matchMedia("(prefers-color-scheme: dark)");
7039
+ darkModeMedia.addEventListener("change", (e) => {
7040
+ this.setDarkMode(e.matches);
7041
+ });
7042
+ this.setDarkMode(darkModeMedia.matches);
7043
+ } else {
7044
+ this.setDarkMode(this.conf.darkMode || false);
7045
+ }
7046
+ }
7047
+ setDarkMode(darkMode) {
6315
7048
  const darkModeClassName = "atk-dark-mode";
7049
+ this.ctx.conf.darkMode = darkMode;
7050
+ this.ctx.trigger("conf-updated");
6316
7051
  if (this.conf.darkMode) {
6317
7052
  this.$root.classList.add(darkModeClassName);
6318
7053
  } else {
@@ -6327,22 +7062,6 @@ const _Artalk = class {
6327
7062
  }
6328
7063
  }
6329
7064
  }
6330
- setDarkMode(darkMode) {
6331
- this.ctx.conf.darkMode = darkMode;
6332
- this.ctx.trigger("conf-updated");
6333
- this.initDarkMode();
6334
- }
6335
- initPV() {
6336
- return __async(this, null, function* () {
6337
- const pvNum = yield new Api(this.ctx).pv();
6338
- if (Number.isNaN(Number(pvNum)))
6339
- return;
6340
- if (!this.conf.pvEl || !document.querySelector(this.conf.pvEl))
6341
- return;
6342
- const $pv = document.querySelector(this.conf.pvEl);
6343
- $pv.innerText = String(pvNum);
6344
- });
6345
- }
6346
7065
  on(name, handler) {
6347
7066
  this.ctx.on(name, handler, "external");
6348
7067
  }
@@ -6352,11 +7071,21 @@ const _Artalk = class {
6352
7071
  trigger(name, payload) {
6353
7072
  this.ctx.trigger(name, payload, "external");
6354
7073
  }
7074
+ reload() {
7075
+ this.ctx.listReload();
7076
+ }
6355
7077
  static Use(plugin) {
6356
7078
  this.Plugins.push(plugin);
6357
7079
  }
7080
+ static LoadCountWidget(customConf) {
7081
+ const conf = this.HandelBaseConf(customConf);
7082
+ const ctx = new Context(conf);
7083
+ initCountWidget({ ctx, pvAdd: false });
7084
+ }
6358
7085
  };
6359
7086
  let Artalk = _Artalk;
6360
- __publicField(Artalk, "defaults", defaults$3);
6361
- __publicField(Artalk, "Plugins", []);
7087
+ __publicField(Artalk, "defaults", defaults);
7088
+ __publicField(Artalk, "Plugins", [
7089
+ PvCountWidget
7090
+ ]);
6362
7091
  export { Artalk as default };