artalk 2.2.6 → 2.2.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/Artalk.es.js CHANGED
@@ -104,7 +104,7 @@ const defaults$3 = {
104
104
  listSort: true,
105
105
  pvEl: "#ArtalkPV",
106
106
  flatMode: "auto",
107
- maxNesting: 3,
107
+ nestMax: 3,
108
108
  gravatar: {
109
109
  default: "mp",
110
110
  mirror: "https://sdn.geekzu.org/avatar/"
@@ -120,7 +120,8 @@ const defaults$3 = {
120
120
  },
121
121
  imgUpload: true,
122
122
  reqTimeout: 15e3,
123
- versionCheck: true
123
+ versionCheck: true,
124
+ useBackendConf: false
124
125
  };
125
126
  class Component {
126
127
  constructor(ctx) {
@@ -1123,7 +1124,7 @@ function mangle(text) {
1123
1124
  class Lexer {
1124
1125
  constructor(options) {
1125
1126
  this.tokens = [];
1126
- this.tokens.links = Object.create(null);
1127
+ this.tokens.links = /* @__PURE__ */ Object.create(null);
1127
1128
  this.options = options || defaults$2;
1128
1129
  this.options.tokenizer = this.options.tokenizer || new Tokenizer();
1129
1130
  this.tokenizer = this.options.tokenizer;
@@ -2813,6 +2814,24 @@ function getURLBasedOnApi(ctx, path) {
2813
2814
  function getURLBasedOn(baseURL, path) {
2814
2815
  return `${baseURL.replace(/\/$/, "")}/${path.replace(/^\//, "")}`;
2815
2816
  }
2817
+ function mergeDeep(target, source) {
2818
+ const isObject = (obj) => obj && typeof obj === "object";
2819
+ if (!isObject(target) || !isObject(source)) {
2820
+ return source;
2821
+ }
2822
+ Object.keys(source).forEach((key) => {
2823
+ const targetValue = target[key];
2824
+ const sourceValue = source[key];
2825
+ if (Array.isArray(targetValue) && Array.isArray(sourceValue)) {
2826
+ target[key] = targetValue.concat(sourceValue);
2827
+ } else if (isObject(targetValue) && isObject(sourceValue)) {
2828
+ target[key] = mergeDeep(__spreadValues({}, targetValue), sourceValue);
2829
+ } else {
2830
+ target[key] = sourceValue;
2831
+ }
2832
+ });
2833
+ return target;
2834
+ }
2816
2835
  function showLoading(parentElem, conf) {
2817
2836
  if (parentElem instanceof Context)
2818
2837
  parentElem = parentElem.$root;
@@ -3434,6 +3453,19 @@ class Api {
3434
3453
  return json.data || {};
3435
3454
  });
3436
3455
  }
3456
+ conf() {
3457
+ return __async(this, null, function* () {
3458
+ const data = yield POST(this.ctx, `${this.baseURL}/conf`);
3459
+ const conf = data.frontend_conf || {};
3460
+ if (conf.emoticons && typeof conf.emoticons === "string") {
3461
+ conf.emoticons = conf.emoticons.trim();
3462
+ if (conf.emoticons.startsWith("[") || conf.emoticons.startsWith("{")) {
3463
+ conf.emoticons = JSON.parse(conf.emoticons);
3464
+ }
3465
+ }
3466
+ return conf;
3467
+ });
3468
+ }
3437
3469
  captchaGet() {
3438
3470
  return __async(this, null, function* () {
3439
3471
  const data = yield POST(this.ctx, `${this.baseURL}/captcha/refresh`);
@@ -3452,6 +3484,14 @@ class Api {
3452
3484
  return data || { is_pass: false };
3453
3485
  });
3454
3486
  }
3487
+ cacheFlushAll() {
3488
+ const params = { flush_all: true };
3489
+ return POST(this.ctx, `${this.baseURL}/admin/cache-flush`, params);
3490
+ }
3491
+ cacheWarmUp() {
3492
+ const params = {};
3493
+ return POST(this.ctx, `${this.baseURL}/admin/cache-warm`, params);
3494
+ }
3455
3495
  }
3456
3496
  const CaptchaChecker = {
3457
3497
  request(that, ctx, inputVal) {
@@ -4005,15 +4045,26 @@ class Editor extends Component {
4005
4045
  const inputEl = this.getInputEl(field);
4006
4046
  if (inputEl && inputEl instanceof HTMLInputElement) {
4007
4047
  inputEl.value = this.user.data[field] || "";
4008
- inputEl.addEventListener("input", () => this.onHeaderInputChanged(field, inputEl));
4048
+ inputEl.addEventListener("input", () => this.onHeaderInput(field, inputEl));
4009
4049
  }
4010
4050
  });
4051
+ const $linkInput = this.getInputEl("link");
4052
+ if ($linkInput) {
4053
+ $linkInput.addEventListener("change", () => {
4054
+ const link = $linkInput.value.trim();
4055
+ if (!!link && !/^(http|https):\/\//.test(link)) {
4056
+ $linkInput.value = `https://${link}`;
4057
+ this.user.data.link = $linkInput.value;
4058
+ this.saveUser();
4059
+ }
4060
+ });
4061
+ }
4011
4062
  }
4012
4063
  getInputEl(field) {
4013
4064
  const inputEl = this.$header.querySelector(`[name="${field}"]`);
4014
4065
  return inputEl;
4015
4066
  }
4016
- onHeaderInputChanged(field, inputEl) {
4067
+ onHeaderInput(field, inputEl) {
4017
4068
  this.user.data[field] = inputEl.value.trim();
4018
4069
  if (field === "nick" || field === "email") {
4019
4070
  this.user.data.token = "";
@@ -4707,6 +4758,7 @@ class Comment extends Component {
4707
4758
  __publicField(this, "data");
4708
4759
  __publicField(this, "$main");
4709
4760
  __publicField(this, "$header");
4761
+ __publicField(this, "$headerNick");
4710
4762
  __publicField(this, "$body");
4711
4763
  __publicField(this, "$content");
4712
4764
  __publicField(this, "$children");
@@ -4714,11 +4766,13 @@ class Comment extends Component {
4714
4766
  __publicField(this, "voteBtnUp");
4715
4767
  __publicField(this, "voteBtnDown");
4716
4768
  __publicField(this, "parent");
4717
- __publicField(this, "nestedNum");
4718
- __publicField(this, "maxNestingNum");
4769
+ __publicField(this, "nestCurt");
4770
+ __publicField(this, "nestMax");
4719
4771
  __publicField(this, "children", []);
4772
+ __publicField(this, "flatMode", false);
4720
4773
  __publicField(this, "replyTo");
4721
4774
  __publicField(this, "$replyTo");
4775
+ __publicField(this, "$replyAt");
4722
4776
  __publicField(this, "afterRender");
4723
4777
  __publicField(this, "unread", false);
4724
4778
  __publicField(this, "openable", false);
@@ -4726,11 +4780,11 @@ class Comment extends Component {
4726
4780
  __publicField(this, "openEvt");
4727
4781
  __publicField(this, "onReplyBtnClick");
4728
4782
  __publicField(this, "onDelete");
4729
- this.maxNestingNum = ctx.conf.maxNesting || 3;
4783
+ this.nestMax = ctx.conf.nestMax || 3;
4730
4784
  this.data = __spreadValues({}, data);
4731
4785
  this.data.date = this.data.date.replace(/-/g, "/");
4732
4786
  this.parent = null;
4733
- this.nestedNum = 1;
4787
+ this.nestCurt = 1;
4734
4788
  }
4735
4789
  render() {
4736
4790
  this.$el = createElement(CommentHTML);
@@ -4746,6 +4800,7 @@ class Comment extends Component {
4746
4800
  this.renderAvatar();
4747
4801
  this.renderHeader();
4748
4802
  this.renderContent();
4803
+ this.renderReplyAt();
4749
4804
  this.renderReplyTo();
4750
4805
  this.renderPending();
4751
4806
  this.renderActionBtn();
@@ -4788,14 +4843,14 @@ class Comment extends Component {
4788
4843
  }
4789
4844
  }
4790
4845
  renderHeader() {
4791
- const $nick = this.$el.querySelector(".atk-nick");
4846
+ this.$headerNick = this.$el.querySelector(".atk-nick");
4792
4847
  if (this.data.link) {
4793
4848
  const $nickA = createElement('<a target="_blank" rel="noreferrer noopener nofollow"></a>');
4794
4849
  $nickA.innerText = this.data.nick;
4795
4850
  $nickA.href = this.data.link;
4796
- $nick.append($nickA);
4851
+ this.$headerNick.append($nickA);
4797
4852
  } else {
4798
- $nick.innerText = this.data.nick;
4853
+ this.$headerNick.innerText = this.data.nick;
4799
4854
  }
4800
4855
  const $badge = this.$el.querySelector(".atk-badge");
4801
4856
  if (this.data.badge_name) {
@@ -4807,7 +4862,7 @@ class Comment extends Component {
4807
4862
  }
4808
4863
  if (this.data.is_pinned) {
4809
4864
  const $pinnedBadge = createElement(`<span class="atk-item atk-pinned-badge">\u7F6E\u9876</span>`);
4810
- $nick.insertAdjacentElement("afterend", $pinnedBadge);
4865
+ this.$headerNick.insertAdjacentElement("afterend", $pinnedBadge);
4811
4866
  }
4812
4867
  const $date = this.$el.querySelector(".atk-date");
4813
4868
  $date.innerText = this.getDateFormatted();
@@ -4850,7 +4905,23 @@ class Comment extends Component {
4850
4905
  }
4851
4906
  });
4852
4907
  }
4908
+ renderReplyAt() {
4909
+ if (this.flatMode || this.data.rid === 0)
4910
+ return;
4911
+ if (this.$replyAt)
4912
+ return;
4913
+ if (!this.replyTo)
4914
+ return;
4915
+ this.$replyAt = createElement(`<span class="atk-item atk-reply-at"><span class="atk-arrow"></span><span class="atk-nick"></span></span>`);
4916
+ this.$replyAt.querySelector(".atk-nick").innerText = `${this.replyTo.nick}`;
4917
+ this.$replyAt.onclick = () => {
4918
+ this.goToReplyComment();
4919
+ };
4920
+ this.$headerNick.insertAdjacentElement("afterend", this.$replyAt);
4921
+ }
4853
4922
  renderReplyTo() {
4923
+ if (!this.flatMode)
4924
+ return;
4854
4925
  if (!this.replyTo)
4855
4926
  return;
4856
4927
  this.$replyTo = createElement(`
@@ -4858,13 +4929,24 @@ class Comment extends Component {
4858
4929
  <div class="atk-meta">\u56DE\u590D <span class="atk-nick"></span>:</div>
4859
4930
  <div class="atk-content"></div>
4860
4931
  </div>`);
4861
- this.$replyTo.querySelector(".atk-nick").innerText = `@${this.replyTo.nick}`;
4932
+ const $nick = this.$replyTo.querySelector(".atk-nick");
4933
+ $nick.innerText = `@${this.replyTo.nick}`;
4934
+ $nick.onclick = () => {
4935
+ this.goToReplyComment();
4936
+ };
4862
4937
  let replyContent = marked(this.ctx, this.replyTo.content);
4863
4938
  if (this.replyTo.is_collapsed)
4864
4939
  replyContent = "[\u5DF2\u6298\u53E0]";
4865
4940
  this.$replyTo.querySelector(".atk-content").innerHTML = replyContent;
4866
4941
  this.$body.prepend(this.$replyTo);
4867
4942
  }
4943
+ goToReplyComment() {
4944
+ const origHash = window.location.hash;
4945
+ const modifyHash = `#atk-comment-${this.data.rid}`;
4946
+ window.location.hash = modifyHash;
4947
+ if (modifyHash === origHash)
4948
+ window.dispatchEvent(new Event("hashchange"));
4949
+ }
4868
4950
  renderPending() {
4869
4951
  if (!this.data.is_pending)
4870
4952
  return;
@@ -4959,19 +5041,23 @@ class Comment extends Component {
4959
5041
  getChildren() {
4960
5042
  return this.children;
4961
5043
  }
4962
- putChild(childC) {
5044
+ putChild(childC, insertMode = "append") {
4963
5045
  childC.parent = this;
4964
- childC.nestedNum = this.nestedNum + 1;
5046
+ childC.nestCurt = this.nestCurt + 1;
4965
5047
  this.children.push(childC);
4966
- this.getChildrenEl().appendChild(childC.getEl());
5048
+ const $children = this.getChildrenEl();
5049
+ if (insertMode === "append")
5050
+ $children.append(childC.getEl());
5051
+ else if (insertMode === "prepend")
5052
+ $children.prepend(childC.getEl());
4967
5053
  childC.playFadeInAnim();
4968
5054
  childC.checkHeightLimitArea("content");
4969
5055
  }
4970
5056
  getChildrenEl() {
4971
- if (this.$children === null) {
4972
- if (this.nestedNum < this.maxNestingNum) {
5057
+ if (!this.$children) {
5058
+ if (this.nestCurt < this.nestMax) {
4973
5059
  this.$children = createElement('<div class="atk-comment-children"></div>');
4974
- this.$main.appendChild(this.$children);
5060
+ this.$main.append(this.$children);
4975
5061
  } else if (this.parent) {
4976
5062
  this.$children = this.parent.getChildrenEl();
4977
5063
  }
@@ -5170,7 +5256,7 @@ class Pagination {
5170
5256
  this.$el = createElement(`<div class="atk-pagination-wrap">
5171
5257
  <div class="atk-pagination">
5172
5258
  <div class="atk-btn atk-btn-prev">Prev</div>
5173
- <input type="text" class="atk-input" />
5259
+ <input type="text" class="atk-input" aria-label="Enter the number of page" />
5174
5260
  <div class="atk-btn atk-btn-next">Next</div>
5175
5261
  </div>
5176
5262
  </div>`);
@@ -5349,16 +5435,68 @@ class ReadMoreBtn {
5349
5435
  this.hide();
5350
5436
  }
5351
5437
  }
5352
- const backendMinVersion = "2.1.2";
5438
+ function makeNestCommentNodeList(srcData, sortBy = "DATE_DESC", nestMax = 2) {
5439
+ const nodeList = [];
5440
+ const roots = srcData.filter((o) => o.rid === 0);
5441
+ roots.forEach((root) => {
5442
+ const rootNode = {
5443
+ id: root.id,
5444
+ comment: root,
5445
+ children: [],
5446
+ level: 1
5447
+ };
5448
+ rootNode.parent = rootNode;
5449
+ nodeList.push(rootNode);
5450
+ (function loadChildren(parentNode) {
5451
+ const children = srcData.filter((o) => o.rid === parentNode.id);
5452
+ if (children.length === 0)
5453
+ return;
5454
+ if (parentNode.level >= nestMax)
5455
+ parentNode = parentNode.parent;
5456
+ children.forEach((child) => {
5457
+ const childNode = {
5458
+ id: child.id,
5459
+ comment: child,
5460
+ children: [],
5461
+ parent: parentNode,
5462
+ level: parentNode.level + 1
5463
+ };
5464
+ parentNode.children.push(childNode);
5465
+ loadChildren(childNode);
5466
+ });
5467
+ })(rootNode);
5468
+ });
5469
+ const sortFunc = (a, b) => {
5470
+ let v = a.id - b.id;
5471
+ if (sortBy === "DATE_ASC")
5472
+ v = +new Date(a.comment.date) - +new Date(b.comment.date);
5473
+ else if (sortBy === "DATE_DESC")
5474
+ v = +new Date(b.comment.date) - +new Date(a.comment.date);
5475
+ else if (sortBy === "SRC_INDEX")
5476
+ v = srcData.indexOf(a.comment) - srcData.indexOf(b.comment);
5477
+ else if (sortBy === "VOTE_UP_DESC")
5478
+ v = b.comment.vote_up - a.comment.vote_up;
5479
+ return v;
5480
+ };
5481
+ (function sortLevels(nodes) {
5482
+ nodes.forEach((node) => {
5483
+ node.children = node.children.sort(sortFunc);
5484
+ sortLevels(node.children);
5485
+ });
5486
+ })(nodeList);
5487
+ return nodeList;
5488
+ }
5489
+ const backendMinVersion = "2.1.4";
5353
5490
  class ListLite extends Component {
5354
5491
  constructor(ctx) {
5355
5492
  super(ctx);
5356
5493
  __publicField(this, "$commentsWrap");
5357
- __publicField(this, "comments", []);
5494
+ __publicField(this, "commentList", []);
5358
5495
  __publicField(this, "data");
5359
5496
  __publicField(this, "isLoading", false);
5360
5497
  __publicField(this, "noCommentText", "\u65E0\u5185\u5BB9");
5361
5498
  __publicField(this, "flatMode", false);
5499
+ __publicField(this, "nestSortBy", "DATE_DESC");
5362
5500
  __publicField(this, "pageMode", "pagination");
5363
5501
  __publicField(this, "pageSize", 20);
5364
5502
  __publicField(this, "scrollListenerAt");
@@ -5375,6 +5513,8 @@ class ListLite extends Component {
5375
5513
  <div class="atk-list-comments-wrap"></div>
5376
5514
  </div>`);
5377
5515
  this.$commentsWrap = this.$el.querySelector(".atk-list-comments-wrap");
5516
+ if (ctx.conf.noComment)
5517
+ this.noCommentText = ctx.conf.noComment;
5378
5518
  window.setInterval(() => {
5379
5519
  this.$el.querySelectorAll("[data-atk-comment-date]").forEach((el) => {
5380
5520
  const date = el.getAttribute("data-atk-comment-date");
@@ -5383,6 +5523,9 @@ class ListLite extends Component {
5383
5523
  }, 30 * 1e3);
5384
5524
  this.ctx.on("unread-update", (data) => this.updateUnread(data.notifies));
5385
5525
  }
5526
+ get commentDataList() {
5527
+ return this.commentList.map((c) => c.data);
5528
+ }
5386
5529
  fetchComments(offset) {
5387
5530
  return __async(this, null, function* () {
5388
5531
  if (this.isLoading)
@@ -5437,7 +5580,7 @@ class ListLite extends Component {
5437
5580
  }
5438
5581
  this.data = data;
5439
5582
  const feMinVersion = ((_a = data.api_version) == null ? void 0 : _a.fe_min_version) || "0.0.0";
5440
- if (this.ctx.conf.versionCheck && this.versionCheck("\u524D\u7AEF", feMinVersion, "2.2.6"))
5583
+ if (this.ctx.conf.versionCheck && this.versionCheck("\u524D\u7AEF", feMinVersion, "2.2.9"))
5441
5584
  return;
5442
5585
  if (this.ctx.conf.versionCheck && this.versionCheck("\u540E\u7AEF", backendMinVersion, (_b = data.api_version) == null ? void 0 : _b.version))
5443
5586
  return;
@@ -5548,7 +5691,7 @@ class ListLite extends Component {
5548
5691
  setError(this.$el, $err);
5549
5692
  }
5550
5693
  refreshUI() {
5551
- const isNoComment = this.comments.length <= 0;
5694
+ const isNoComment = this.commentList.length <= 0;
5552
5695
  let $noComment = this.$commentsWrap.querySelector(".atk-list-no-comment");
5553
5696
  if (isNoComment) {
5554
5697
  if (!$noComment) {
@@ -5561,8 +5704,11 @@ class ListLite extends Component {
5561
5704
  }
5562
5705
  this.ctx.trigger("check-admin-show-el");
5563
5706
  }
5564
- createComment(data) {
5565
- const comment2 = new Comment(this.ctx, data);
5707
+ createComment(cData, ctxData) {
5708
+ if (!ctxData)
5709
+ ctxData = this.commentDataList;
5710
+ const comment2 = new Comment(this.ctx, cData);
5711
+ comment2.flatMode = this.flatMode;
5566
5712
  comment2.afterRender = () => {
5567
5713
  if (this.renderComment)
5568
5714
  this.renderComment(comment2);
@@ -5571,6 +5717,7 @@ class ListLite extends Component {
5571
5717
  this.deleteComment(c);
5572
5718
  this.refreshUI();
5573
5719
  };
5720
+ comment2.replyTo = cData.rid ? ctxData.find((c) => c.id === cData.rid) : void 0;
5574
5721
  return comment2;
5575
5722
  }
5576
5723
  importComments(srcData) {
@@ -5579,44 +5726,37 @@ class ListLite extends Component {
5579
5726
  this.putCommentFlatMode(commentData, srcData, "append");
5580
5727
  });
5581
5728
  } else {
5582
- this.importCommentsNesting(srcData);
5729
+ this.importCommentsNest(srcData);
5583
5730
  }
5584
5731
  }
5585
- importCommentsNesting(srcData) {
5586
- const loadChildren = (parentC) => {
5587
- const children = srcData.filter((o) => o.rid === parentC.data.id);
5588
- children.forEach((childData) => {
5589
- const childC = this.createComment(childData);
5590
- childC.render();
5591
- parentC.putChild(childC);
5592
- loadChildren(childC);
5593
- });
5594
- };
5595
- const rootComments = srcData.filter((o) => o.rid === 0);
5596
- rootComments.forEach((rootData) => {
5597
- const rootC = this.createComment(rootData);
5732
+ importCommentsNest(srcData) {
5733
+ const rootNodes = makeNestCommentNodeList(srcData, this.nestSortBy, this.conf.nestMax);
5734
+ rootNodes.forEach((rootNode) => {
5735
+ const rootC = this.createComment(rootNode.comment, srcData);
5598
5736
  rootC.render();
5599
5737
  this.$commentsWrap.appendChild(rootC.getEl());
5600
5738
  rootC.playFadeInAnim();
5601
- this.comments.push(rootC);
5602
- loadChildren(rootC);
5739
+ this.commentList.push(rootC);
5740
+ const that = this;
5741
+ (function loadChildren(parentC, parentNode) {
5742
+ parentNode.children.forEach((node) => {
5743
+ const childD = node.comment;
5744
+ const childC = that.createComment(childD, srcData);
5745
+ childC.render();
5746
+ parentC.putChild(childC);
5747
+ that.commentList.push(childC);
5748
+ loadChildren(childC, node);
5749
+ });
5750
+ })(rootC, rootNode);
5603
5751
  rootC.checkHeightLimit();
5604
5752
  });
5605
5753
  }
5606
- putCommentFlatMode(cData, srcData, insertMode) {
5754
+ putCommentFlatMode(cData, ctxData, insertMode) {
5607
5755
  if (cData.is_collapsed)
5608
5756
  cData.is_allow_reply = false;
5609
- const comment2 = this.createComment(cData);
5610
- if (cData.rid !== 0) {
5611
- const rComment = srcData.find((o) => o.id === cData.rid);
5612
- if (rComment)
5613
- comment2.replyTo = rComment;
5614
- }
5757
+ const comment2 = this.createComment(cData, ctxData);
5615
5758
  comment2.render();
5616
- if (insertMode === "append")
5617
- this.comments.push(comment2);
5618
- if (insertMode === "prepend")
5619
- this.comments.unshift(comment2);
5759
+ this.commentList.push(comment2);
5620
5760
  if (cData.visible) {
5621
5761
  if (insertMode === "append")
5622
5762
  this.$commentsWrap.append(comment2.getEl());
@@ -5630,14 +5770,15 @@ class ListLite extends Component {
5630
5770
  insertComment(commentData) {
5631
5771
  if (!this.flatMode) {
5632
5772
  const comment2 = this.createComment(commentData);
5633
- comment2.render();
5634
5773
  if (commentData.rid === 0) {
5774
+ comment2.render();
5635
5775
  this.$commentsWrap.prepend(comment2.getEl());
5636
- this.comments.unshift(comment2);
5776
+ this.commentList.push(comment2);
5637
5777
  } else {
5638
5778
  const parent = this.findComment(commentData.rid);
5639
5779
  if (parent) {
5640
- parent.putChild(comment2);
5780
+ comment2.render();
5781
+ parent.putChild(comment2, this.nestSortBy === "DATE_ASC" ? "append" : "prepend");
5641
5782
  comment2.getParents().forEach((p) => {
5642
5783
  if (p.$children)
5643
5784
  p.heightLimitRemove(p.$children);
@@ -5648,7 +5789,7 @@ class ListLite extends Component {
5648
5789
  scrollIntoView(comment2.getEl());
5649
5790
  comment2.playFadeInAnim();
5650
5791
  } else {
5651
- const comment2 = this.putCommentFlatMode(commentData, this.comments.map((c) => c.data), "prepend");
5792
+ const comment2 = this.putCommentFlatMode(commentData, this.commentDataList, "prepend");
5652
5793
  scrollIntoView(comment2.getEl());
5653
5794
  }
5654
5795
  if (this.data)
@@ -5656,45 +5797,20 @@ class ListLite extends Component {
5656
5797
  this.refreshUI();
5657
5798
  this.ctx.trigger("comments-loaded");
5658
5799
  }
5659
- eachComment(commentList, action) {
5660
- if (commentList.length === 0)
5661
- return;
5662
- commentList.every((item) => {
5663
- if (action(item, commentList) === false)
5664
- return false;
5665
- this.eachComment(item.getChildren(), action);
5666
- return true;
5667
- });
5668
- }
5669
- findComment(id, src) {
5670
- if (!src)
5671
- src = this.comments;
5672
- let comment2 = null;
5673
- this.eachComment(src, (item) => {
5674
- if (item.data.id === id) {
5675
- comment2 = item;
5676
- return false;
5677
- }
5678
- return true;
5679
- });
5680
- return comment2;
5800
+ findComment(id) {
5801
+ return this.commentList.find((c) => c.data.id === id);
5681
5802
  }
5682
- deleteComment(comment2) {
5683
- let findComment;
5684
- if (typeof comment2 === "number") {
5685
- findComment = this.findComment(comment2);
5803
+ deleteComment(_comment) {
5804
+ let comment2;
5805
+ if (typeof _comment === "number") {
5806
+ const findComment = this.findComment(_comment);
5686
5807
  if (!findComment)
5687
- throw Error(`\u672A\u627E\u5230\u8BC4\u8BBA ${comment2}`);
5808
+ throw Error(`\u672A\u627E\u5230\u8BC4\u8BBA ${_comment}`);
5809
+ comment2 = findComment;
5688
5810
  } else
5689
- findComment = comment2;
5690
- findComment.getEl().remove();
5691
- this.eachComment(this.comments, (item, levelList) => {
5692
- if (item === findComment) {
5693
- levelList.splice(levelList.indexOf(item), 1);
5694
- return false;
5695
- }
5696
- return true;
5697
- });
5811
+ comment2 = _comment;
5812
+ comment2.getEl().remove();
5813
+ this.commentList.splice(this.commentList.indexOf(comment2), 1);
5698
5814
  if (this.data)
5699
5815
  this.data.total -= 1;
5700
5816
  this.refreshUI();
@@ -5702,12 +5818,12 @@ class ListLite extends Component {
5702
5818
  clearAllComments() {
5703
5819
  this.$commentsWrap.innerHTML = "";
5704
5820
  this.data = void 0;
5705
- this.comments = [];
5821
+ this.commentList = [];
5706
5822
  }
5707
5823
  updateUnread(notifies) {
5708
5824
  this.unread = notifies;
5709
5825
  if (this.unreadHighlight === true) {
5710
- this.eachComment(this.comments, (comment2) => {
5826
+ this.commentList.forEach((comment2) => {
5711
5827
  const notify = this.unread.find((o) => o.comment_id === comment2.data.id);
5712
5828
  if (notify) {
5713
5829
  comment2.setUnread(true);
@@ -5751,6 +5867,8 @@ class List extends ListLite {
5751
5867
  __publicField(this, "$unreadBadge");
5752
5868
  __publicField(this, "$commentCount");
5753
5869
  __publicField(this, "$dropdownWrap");
5870
+ __publicField(this, "goToCommentFounded", false);
5871
+ __publicField(this, "goToCommentDelay", true);
5754
5872
  el.querySelector(".atk-list-body").append(this.$el);
5755
5873
  this.$el = el;
5756
5874
  let flatMode = false;
@@ -5769,7 +5887,7 @@ class List extends ListLite {
5769
5887
  if (this.ctx.conf.listSort) {
5770
5888
  this.initDropdown();
5771
5889
  }
5772
- this.$el.querySelector(".atk-copyright").innerHTML = `Powered By <a href="https://artalk.js.org" target="_blank" title="Artalk v${"2.2.6"}">Artalk</a>`;
5890
+ this.$el.querySelector(".atk-copyright").innerHTML = `Powered By <a href="https://artalk.js.org" target="_blank" title="Artalk v${"2.2.9"}">Artalk</a>`;
5773
5891
  this.ctx.on("list-reload", () => this.fetchComments(0));
5774
5892
  this.ctx.on("list-refresh-ui", () => this.refreshUI());
5775
5893
  this.ctx.on("list-import", (data) => this.importComments(data));
@@ -5819,36 +5937,55 @@ class List extends ListLite {
5819
5937
  }
5820
5938
  onLoad(data, offset) {
5821
5939
  super.onLoad(data, offset);
5822
- this.checkGoToCommentByUrlHash();
5940
+ if (!this.goToCommentFounded)
5941
+ this.checkGoToCommentByUrlHash();
5942
+ if (this.ctx.conf.editorTravel === true) {
5943
+ this.ctx.trigger("editor-travel-back");
5944
+ }
5823
5945
  }
5824
5946
  checkGoToCommentByUrlHash() {
5825
- return __async(this, null, function* () {
5826
- let commentId = Number(getQueryParam("atk_comment"));
5827
- if (!commentId) {
5828
- const match = window.location.hash.match(/#atk-comment-([0-9]+)/);
5829
- if (!match || !match[1] || Number.isNaN(Number(match[1])))
5830
- return;
5831
- commentId = Number(match[1]);
5832
- }
5833
- if (!commentId)
5947
+ let commentId = Number(getQueryParam("atk_comment"));
5948
+ if (!commentId) {
5949
+ const match = window.location.hash.match(/#atk-comment-([0-9]+)/);
5950
+ if (!match || !match[1] || Number.isNaN(Number(match[1])))
5834
5951
  return;
5835
- const notifyKey = getQueryParam("atk_notify_key");
5836
- if (notifyKey) {
5837
- new Api(this.ctx).markRead(notifyKey).then(() => {
5838
- this.unread = this.unread.filter((o) => o.comment_id !== commentId);
5839
- this.ctx.trigger("unread-update", {
5840
- notifies: this.unread
5841
- });
5952
+ commentId = Number(match[1]);
5953
+ }
5954
+ if (!commentId)
5955
+ return;
5956
+ const comment2 = this.findComment(commentId);
5957
+ if (!comment2) {
5958
+ if (this.readMoreBtn)
5959
+ this.readMoreBtn.click();
5960
+ else if (this.pagination)
5961
+ this.pagination.next();
5962
+ return;
5963
+ }
5964
+ const notifyKey = getQueryParam("atk_notify_key");
5965
+ if (notifyKey) {
5966
+ new Api(this.ctx).markRead(notifyKey).then(() => {
5967
+ this.unread = this.unread.filter((o) => o.comment_id !== commentId);
5968
+ this.ctx.trigger("unread-update", {
5969
+ notifies: this.unread
5842
5970
  });
5843
- }
5844
- const comment2 = this.findComment(commentId);
5845
- if (!comment2)
5846
- return;
5971
+ });
5972
+ }
5973
+ comment2.getParents().forEach((p) => {
5974
+ if (p.$children)
5975
+ p.heightLimitRemove(p.$children);
5976
+ });
5977
+ const goTo = () => {
5847
5978
  scrollIntoView(comment2.getEl(), false);
5979
+ comment2.getEl().classList.remove("atk-flash-once");
5848
5980
  window.setTimeout(() => {
5849
5981
  comment2.getEl().classList.add("atk-flash-once");
5850
- }, 800);
5851
- });
5982
+ }, 150);
5983
+ };
5984
+ if (!this.goToCommentDelay)
5985
+ goTo();
5986
+ else
5987
+ window.setTimeout(() => goTo(), 350);
5988
+ this.goToCommentFounded = true;
5852
5989
  }
5853
5990
  adminPageEditSave() {
5854
5991
  if (!this.data || !this.data.page)
@@ -6067,7 +6204,7 @@ const _Artalk = class {
6067
6204
  __publicField(this, "editor");
6068
6205
  __publicField(this, "list");
6069
6206
  __publicField(this, "sidebarLayer");
6070
- this.conf = __spreadValues(__spreadValues({}, _Artalk.defaults), customConf);
6207
+ this.conf = mergeDeep(_Artalk.defaults, customConf);
6071
6208
  this.conf.server = this.conf.server.replace(/\/$/, "").replace(/\/api\/?$/, "");
6072
6209
  if (!this.conf.pageKey) {
6073
6210
  this.conf.pageKey = `${window.location.pathname}`;
@@ -6091,6 +6228,16 @@ const _Artalk = class {
6091
6228
  this.ctx = new Context(this.$root, this.conf);
6092
6229
  this.$root.classList.add("artalk");
6093
6230
  this.$root.innerHTML = "";
6231
+ if (this.conf.useBackendConf) {
6232
+ return (() => __async(this, null, function* () {
6233
+ yield this.loadConfRemote();
6234
+ this.initCore();
6235
+ return this;
6236
+ }))();
6237
+ }
6238
+ this.initCore();
6239
+ }
6240
+ initCore() {
6094
6241
  this.initLayer();
6095
6242
  this.initDarkMode();
6096
6243
  this.checkerLauncher = new CheckerLauncher(this.ctx);
@@ -6110,8 +6257,22 @@ const _Artalk = class {
6110
6257
  }
6111
6258
  });
6112
6259
  }
6260
+ loadConfRemote() {
6261
+ return __async(this, null, function* () {
6262
+ showLoading(this.$root);
6263
+ let backendConf = {};
6264
+ try {
6265
+ backendConf = yield new Api(this.ctx).conf();
6266
+ } catch (err) {
6267
+ console.error("\u914D\u7F6E\u8FDC\u7A0B\u83B7\u53D6\u5931\u8D25", err);
6268
+ }
6269
+ this.ctx.conf = mergeDeep(this.ctx.conf, backendConf);
6270
+ hideLoading(this.$root);
6271
+ });
6272
+ }
6113
6273
  initEventBind() {
6114
6274
  window.addEventListener("hashchange", () => {
6275
+ this.list.goToCommentDelay = false;
6115
6276
  this.list.checkGoToCommentByUrlHash();
6116
6277
  });
6117
6278
  this.ctx.on("check-admin-show-el", () => {