artalk 2.1.6 → 2.1.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
@@ -68,6 +68,7 @@ class Context {
68
68
  __publicField(this, "conf");
69
69
  __publicField(this, "user");
70
70
  __publicField(this, "eventList", []);
71
+ __publicField(this, "markedInstance");
71
72
  this.cid = +new Date();
72
73
  this.$root = rootEl;
73
74
  this.conf = conf;
@@ -102,6 +103,7 @@ const defaults$3 = {
102
103
  vote: true,
103
104
  voteDown: false,
104
105
  uaBadge: true,
106
+ listSort: true,
105
107
  pvEl: "#ArtalkPV",
106
108
  flatMode: "auto",
107
109
  maxNesting: 3,
@@ -118,6 +120,7 @@ const defaults$3 = {
118
120
  content: 300,
119
121
  children: 400
120
122
  },
123
+ imgUpload: true,
121
124
  reqTimeout: 15e3,
122
125
  versionCheck: true
123
126
  };
@@ -2654,37 +2657,36 @@ function versionCompare(a, b) {
2654
2657
  }
2655
2658
  return 0;
2656
2659
  }
2657
- let markedInstance;
2660
+ function initMarked(ctx) {
2661
+ const renderer = new marked$1.Renderer();
2662
+ const linkRenderer = renderer.link;
2663
+ renderer.link = (href, title, text) => {
2664
+ const localLink = href == null ? void 0 : href.startsWith(`${window.location.protocol}//${window.location.hostname}`);
2665
+ const html = linkRenderer.call(renderer, href, title, text);
2666
+ return html.replace(/^<a /, `<a target="_blank" ${!localLink ? `rel="noreferrer noopener nofollow"` : ""} `);
2667
+ };
2668
+ const nMarked = marked$1;
2669
+ marked$1.setOptions({
2670
+ renderer,
2671
+ highlight: (code) => hanabi(code),
2672
+ pedantic: false,
2673
+ gfm: true,
2674
+ breaks: true,
2675
+ smartLists: true,
2676
+ smartypants: true,
2677
+ xhtml: false,
2678
+ sanitize: true,
2679
+ sanitizer: (html) => insane_1(html, __spreadProps(__spreadValues({}, insane_1.defaults), {
2680
+ allowedAttributes: __spreadProps(__spreadValues({}, insane_1.defaults.allowedAttributes), {
2681
+ img: ["src", "atk-emoticon"]
2682
+ })
2683
+ })),
2684
+ silent: true
2685
+ });
2686
+ ctx.markedInstance = nMarked;
2687
+ }
2658
2688
  function marked(ctx, src) {
2659
- if (!markedInstance) {
2660
- const renderer = new marked$1.Renderer();
2661
- const linkRenderer = renderer.link;
2662
- renderer.link = (href, title, text) => {
2663
- const localLink = href == null ? void 0 : href.startsWith(`${window.location.protocol}//${window.location.hostname}`);
2664
- const html = linkRenderer.call(renderer, href, title, text);
2665
- return html.replace(/^<a /, `<a target="_blank" ${!localLink ? `rel="noreferrer noopener nofollow"` : ""} `);
2666
- };
2667
- const nMarked = marked$1;
2668
- marked$1.setOptions({
2669
- renderer,
2670
- highlight: (code) => hanabi(code),
2671
- pedantic: false,
2672
- gfm: true,
2673
- breaks: true,
2674
- smartLists: true,
2675
- smartypants: true,
2676
- xhtml: false,
2677
- sanitize: true,
2678
- sanitizer: (html) => insane_1(html, __spreadProps(__spreadValues({}, insane_1.defaults), {
2679
- allowedAttributes: __spreadProps(__spreadValues({}, insane_1.defaults.allowedAttributes), {
2680
- img: ["src", "atk-emoticon"]
2681
- })
2682
- })),
2683
- silent: true
2684
- });
2685
- markedInstance = nMarked;
2686
- }
2687
- return markedInstance.parse(src);
2689
+ return ctx.markedInstance.parse(src);
2688
2690
  }
2689
2691
  function getCorrectUserAgent() {
2690
2692
  return __async(this, null, function* () {
@@ -2710,6 +2712,18 @@ function getCorrectUserAgent() {
2710
2712
  return uaRaw;
2711
2713
  });
2712
2714
  }
2715
+ function isValidURL(urlRaw) {
2716
+ let url;
2717
+ try {
2718
+ url = new URL(urlRaw);
2719
+ } catch (_) {
2720
+ return false;
2721
+ }
2722
+ return url.protocol === "http:" || url.protocol === "https:";
2723
+ }
2724
+ function getURLBasedOnApi(ctx, path) {
2725
+ return `${ctx.conf.server.replace(/\/api\/?$/, "")}/${path.replace(/^\//, "")}`;
2726
+ }
2713
2727
  function showLoading(parentElem) {
2714
2728
  if (parentElem instanceof Context)
2715
2729
  parentElem = parentElem.$root;
@@ -3300,6 +3314,25 @@ class Api {
3300
3314
  return p.pv;
3301
3315
  });
3302
3316
  }
3317
+ imgUpload(file) {
3318
+ return __async(this, null, function* () {
3319
+ const params = {
3320
+ name: this.ctx.user.data.nick,
3321
+ email: this.ctx.user.data.email,
3322
+ page_key: this.ctx.conf.pageKey
3323
+ };
3324
+ if (this.ctx.conf.site)
3325
+ params.site_name = this.ctx.conf.site;
3326
+ const form = ToFormData(params);
3327
+ form.set("file", file);
3328
+ const init = {
3329
+ method: "POST",
3330
+ body: form
3331
+ };
3332
+ const json = yield Fetch(this.ctx, `${this.baseURL}/img-upload`, init);
3333
+ return json.data || {};
3334
+ });
3335
+ }
3303
3336
  captchaGet() {
3304
3337
  return __async(this, null, function* () {
3305
3338
  const data = yield GET(this.ctx, `${this.baseURL}/captcha/refresh`);
@@ -3723,6 +3756,7 @@ class Editor extends Component {
3723
3756
  __publicField(this, "$plugWrap");
3724
3757
  __publicField(this, "$bottom");
3725
3758
  __publicField(this, "$plugBtnWrap");
3759
+ __publicField(this, "$imgUploadBtn");
3726
3760
  __publicField(this, "$submitBtn");
3727
3761
  __publicField(this, "$notifyWrap");
3728
3762
  __publicField(this, "replyComment", null);
@@ -3733,6 +3767,7 @@ class Editor extends Component {
3733
3767
  abortFunc: null
3734
3768
  });
3735
3769
  __publicField(this, "openedPlugName", null);
3770
+ __publicField(this, "allowImgExts", ["png", "jpg", "jpeg", "gif", "bmp", "svg", "webp"]);
3736
3771
  this.$el = createElement(EditorHTML);
3737
3772
  this.$header = this.$el.querySelector(".atk-header");
3738
3773
  this.$textareaWrap = this.$el.querySelector(".atk-textarea-wrap");
@@ -3756,6 +3791,7 @@ class Editor extends Component {
3756
3791
  this.ctx.on("editor-notify", (f) => this.showNotify(f.msg, f.type));
3757
3792
  this.ctx.on("editor-travel", ($el) => this.travel($el));
3758
3793
  this.ctx.on("editor-travel-back", () => this.travelBack());
3794
+ this.ctx.on("conf-updated", () => this.refreshUploadBtn());
3759
3795
  }
3760
3796
  get user() {
3761
3797
  return this.ctx.user;
@@ -3854,7 +3890,7 @@ class Editor extends Component {
3854
3890
  this.openedPlugName = null;
3855
3891
  this.$plugBtnWrap.innerHTML = "";
3856
3892
  this.LOADABLE_PLUG_LIST.forEach((PlugObj) => {
3857
- const btnElem = createElement(`<span class="atk-plug-btn">${PlugObj.BtnHTML}</span>`);
3893
+ const btnElem = createElement(`<span class="atk-plug-btn" data-plug-name="${PlugObj.Name}">${PlugObj.BtnHTML}</span>`);
3858
3894
  this.$plugBtnWrap.appendChild(btnElem);
3859
3895
  btnElem.addEventListener("click", () => {
3860
3896
  let plug = this.plugList[PlugObj.Name];
@@ -3890,12 +3926,98 @@ class Editor extends Component {
3890
3926
  btnElem.classList.add("active");
3891
3927
  });
3892
3928
  });
3929
+ this.initImgUpload();
3893
3930
  }
3894
3931
  closePlug() {
3895
3932
  this.$plugWrap.innerHTML = "";
3896
3933
  this.$plugWrap.style.display = "none";
3897
3934
  this.openedPlugName = null;
3898
3935
  }
3936
+ initImgUpload() {
3937
+ this.$imgUploadBtn = createElement(`<span class="atk-plug-btn">\u56FE\u7247</span>`);
3938
+ this.$plugBtnWrap.querySelector('[data-plug-name="preview"]').before(this.$imgUploadBtn);
3939
+ this.$imgUploadBtn.onclick = () => {
3940
+ const $input = document.createElement("input");
3941
+ $input.type = "file";
3942
+ $input.accept = this.allowImgExts.map((o) => `.${o}`).join(",");
3943
+ $input.onchange = () => {
3944
+ (() => __async(this, null, function* () {
3945
+ if (!$input.files || $input.files.length === 0)
3946
+ return;
3947
+ const file = $input.files[0];
3948
+ this.uploadImg(file);
3949
+ }))();
3950
+ };
3951
+ $input.click();
3952
+ };
3953
+ const uploadFromFileList = (files) => {
3954
+ if (!files)
3955
+ return;
3956
+ for (let i = 0; i < files.length; i++) {
3957
+ const file = files[i];
3958
+ this.uploadImg(file);
3959
+ }
3960
+ };
3961
+ this.$textarea.addEventListener("dragover", (evt) => {
3962
+ evt.stopPropagation();
3963
+ evt.preventDefault();
3964
+ });
3965
+ this.$textarea.addEventListener("drop", (evt) => {
3966
+ var _a;
3967
+ const files = (_a = evt.dataTransfer) == null ? void 0 : _a.files;
3968
+ if (files == null ? void 0 : files.length) {
3969
+ evt.preventDefault();
3970
+ uploadFromFileList(files);
3971
+ }
3972
+ });
3973
+ this.$textarea.addEventListener("paste", (evt) => {
3974
+ var _a;
3975
+ const files = (_a = evt.clipboardData) == null ? void 0 : _a.files;
3976
+ if (files == null ? void 0 : files.length) {
3977
+ evt.preventDefault();
3978
+ uploadFromFileList(files);
3979
+ }
3980
+ });
3981
+ }
3982
+ refreshUploadBtn() {
3983
+ if (!this.$imgUploadBtn)
3984
+ return;
3985
+ if (!this.ctx.conf.imgUpload) {
3986
+ this.$imgUploadBtn.setAttribute("atk-only-admin-show", "");
3987
+ this.ctx.trigger("check-admin-show-el");
3988
+ }
3989
+ }
3990
+ uploadImg(file) {
3991
+ return __async(this, null, function* () {
3992
+ const fileExt = /[^.]+$/.exec(file.name);
3993
+ if (!fileExt || !this.allowImgExts.includes(fileExt[0]))
3994
+ return;
3995
+ if (!this.ctx.user.checkHasBasicUserInfo()) {
3996
+ this.showNotify("\u586B\u5165\u4F60\u7684\u540D\u5B57\u90AE\u7BB1\u624D\u80FD\u4E0A\u4F20\u54E6", "w");
3997
+ return;
3998
+ }
3999
+ let insertPrefix = "\n";
4000
+ if (this.$textarea.value.trim() === "")
4001
+ insertPrefix = "";
4002
+ const uploadPlaceholderTxt = `${insertPrefix}![](Uploading ${file.name}...)`;
4003
+ this.insertContent(uploadPlaceholderTxt);
4004
+ let resp;
4005
+ try {
4006
+ resp = yield new Api(this.ctx).imgUpload(file);
4007
+ } catch (err) {
4008
+ console.error(err);
4009
+ this.showNotify(`\u56FE\u7247\u4E0A\u4F20\u5931\u8D25\uFF0C${err.msg}`, "e");
4010
+ }
4011
+ if (!!resp && resp.img_url) {
4012
+ let imgURL = resp.img_url;
4013
+ if (!isValidURL(imgURL))
4014
+ imgURL = getURLBasedOnApi(this.ctx, imgURL);
4015
+ this.setContent(this.$textarea.value.replace(uploadPlaceholderTxt, `${insertPrefix}![](${imgURL})`));
4016
+ } else {
4017
+ this.setContent(this.$textarea.value.replace(uploadPlaceholderTxt, ""));
4018
+ }
4019
+ });
4020
+ }
3899
4021
  insertContent(val) {
3900
4022
  if (document.selection) {
3901
4023
  this.$textarea.focus();
@@ -3927,7 +4049,7 @@ class Editor extends Component {
3927
4049
  this.setContent("");
3928
4050
  this.cancelReply();
3929
4051
  }
3930
- getContent() {
4052
+ getFinalContent() {
3931
4053
  let content = this.getContentOriginal();
3932
4054
  if (this.plugList && this.plugList.emoticons) {
3933
4055
  const emoticonsPlug2 = this.plugList.emoticons;
@@ -3939,7 +4061,7 @@ class Editor extends Component {
3939
4061
  return this.$textarea.value || "";
3940
4062
  }
3941
4063
  getContentMarked() {
3942
- return marked(this.ctx, this.getContent());
4064
+ return marked(this.ctx, this.getFinalContent());
3943
4065
  }
3944
4066
  initBottomPart() {
3945
4067
  this.initReply();
@@ -3988,7 +4110,7 @@ class Editor extends Component {
3988
4110
  }
3989
4111
  submit() {
3990
4112
  return __async(this, null, function* () {
3991
- if (this.getContent().trim() === "") {
4113
+ if (this.getFinalContent().trim() === "") {
3992
4114
  this.$textarea.focus();
3993
4115
  return;
3994
4116
  }
@@ -3996,7 +4118,7 @@ class Editor extends Component {
3996
4118
  showLoading(this.$el);
3997
4119
  try {
3998
4120
  const nComment = yield new Api(this.ctx).add({
3999
- content: this.getContent(),
4121
+ content: this.getFinalContent(),
4000
4122
  nick: this.user.data.nick,
4001
4123
  email: this.user.data.email,
4002
4124
  link: this.user.data.link,
@@ -4061,7 +4183,7 @@ class Editor extends Component {
4061
4183
  }
4062
4184
  }
4063
4185
  var list = "";
4064
- var ListHTML = '<div class="atk-list">\n <div class="atk-list-header">\n <div class="atk-comment-count">\n <span class="atk-comment-count-num">0</span>\n \u6761\u8BC4\u8BBA\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';
4186
+ 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';
4065
4187
  var comment = "";
4066
4188
  var win = window || {};
4067
4189
  var nav = navigator || {};
@@ -4527,6 +4649,10 @@ class Comment extends Component {
4527
4649
  } else {
4528
4650
  $badge.remove();
4529
4651
  }
4652
+ if (this.data.is_pinned) {
4653
+ const $pinnedBadge = createElement(`<span class="atk-item atk-pinned-badge">\u7F6E\u9876</span>`);
4654
+ $nick.insertAdjacentElement("afterend", $pinnedBadge);
4655
+ }
4530
4656
  const $date = this.$el.querySelector(".atk-date");
4531
4657
  $date.innerText = this.getDateFormatted();
4532
4658
  $date.setAttribute("data-atk-comment-date", String(+new Date(this.data.date)));
@@ -4640,6 +4766,14 @@ class Comment extends Component {
4640
4766
  delBtn.setClick(() => {
4641
4767
  this.adminDelete(delBtn);
4642
4768
  });
4769
+ const pinnedBtn = new ActionBtn({
4770
+ text: () => this.data.is_pinned ? "\u53D6\u6D88\u7F6E\u9876" : "\u7F6E\u9876",
4771
+ adminOnly: true
4772
+ });
4773
+ pinnedBtn.appendTo(this.$actions);
4774
+ pinnedBtn.setClick(() => {
4775
+ this.adminEdit("pinned", pendingBtn);
4776
+ });
4643
4777
  }
4644
4778
  refreshUI() {
4645
4779
  const originalEl = this.$el;
@@ -4750,6 +4884,8 @@ class Comment extends Component {
4750
4884
  modify.is_collapsed = !modify.is_collapsed;
4751
4885
  } else if (type === "pending") {
4752
4886
  modify.is_pending = !modify.is_pending;
4887
+ } else if (type === "pinned") {
4888
+ modify.is_pinned = !modify.is_pinned;
4753
4889
  }
4754
4890
  new Api(this.ctx).commentEdit(modify).then((comment2) => {
4755
4891
  btnElem.setLoading(false);
@@ -5144,11 +5280,15 @@ class ListLite extends Component {
5144
5280
  this.data = data;
5145
5281
  if (this.ctx.conf.versionCheck && this.versionCheck(data.api_version))
5146
5282
  return;
5283
+ if (data.conf && typeof data.conf.img_upload === "boolean") {
5284
+ this.ctx.conf.imgUpload = data.conf.img_upload;
5285
+ }
5147
5286
  this.importComments(data.comments);
5148
5287
  this.refreshPagination(offset, this.flatMode ? data.total : data.total_roots);
5149
5288
  this.refreshUI();
5150
5289
  this.ctx.trigger("unread-update", { notifies: data.unread || [] });
5151
5290
  this.ctx.trigger("comments-loaded");
5291
+ this.ctx.trigger("conf-updated");
5152
5292
  if (this.onAfterLoad)
5153
5293
  this.onAfterLoad(data);
5154
5294
  }
@@ -5415,13 +5555,14 @@ class ListLite extends Component {
5415
5555
  }
5416
5556
  versionCheck(versionData) {
5417
5557
  const needVersion = (versionData == null ? void 0 : versionData.fe_min_version) || "0.0.0";
5418
- const needUpdate = versionCompare(needVersion, "2.1.6") === 1;
5558
+ const needUpdate = versionCompare(needVersion, "2.1.9") === 1;
5419
5559
  if (needUpdate) {
5420
- const errEl = createElement(`<div>\u524D\u7AEF Artalk \u7248\u672C\u5DF2\u8FC7\u65F6\uFF0C\u8BF7\u66F4\u65B0\u4EE5\u83B7\u5F97\u5B8C\u6574\u4F53\u9A8C<br/>\u82E5\u60A8\u662F\u7AD9\u70B9\u7BA1\u7406\u5458\uFF0C\u8BF7\u524D\u5F80 \u201C<a href="https://artalk.js.org/" target="_blank">\u5B98\u65B9\u6587\u6863</a>\u201D \u83B7\u53D6\u5E2E\u52A9<br/><br/><span style="color: var(--at-color-meta);">\u524D\u7AEF\u7248\u672C ${"2.1.6"}\uFF0C\u9700\u6C42\u7248\u672C >= ${needVersion}</span><br/><br/></div>`);
5560
+ const errEl = createElement(`<div>\u524D\u7AEF Artalk \u7248\u672C\u5DF2\u8FC7\u65F6\uFF0C\u8BF7\u66F4\u65B0\u4EE5\u83B7\u5F97\u5B8C\u6574\u4F53\u9A8C<br/>\u82E5\u60A8\u662F\u7AD9\u70B9\u7BA1\u7406\u5458\uFF0C\u8BF7\u524D\u5F80 \u201C<a href="https://artalk.js.org/" target="_blank">\u5B98\u65B9\u6587\u6863</a>\u201D \u83B7\u53D6\u5E2E\u52A9<br/><br/><span style="color: var(--at-color-meta);">\u524D\u7AEF\u7248\u672C ${"2.1.9"}\uFF0C\u9700\u6C42\u7248\u672C >= ${needVersion}</span><br/><br/></div>`);
5421
5561
  const ignoreBtn = createElement('<span style="cursor:pointer;">\u5FFD\u7565</span>');
5422
5562
  ignoreBtn.onclick = () => {
5423
5563
  setError(this.ctx, null);
5424
5564
  this.ctx.conf.versionCheck = false;
5565
+ this.ctx.trigger("conf-updated");
5425
5566
  this.fetchComments(0);
5426
5567
  };
5427
5568
  errEl.append(ignoreBtn);
@@ -5438,6 +5579,8 @@ class List extends ListLite {
5438
5579
  __publicField(this, "$closeCommentBtn");
5439
5580
  __publicField(this, "$openSidebarBtn");
5440
5581
  __publicField(this, "$unreadBadge");
5582
+ __publicField(this, "$commentCount");
5583
+ __publicField(this, "$dropdownWrap");
5441
5584
  el.querySelector(".atk-list-body").append(this.$el);
5442
5585
  this.$el = el;
5443
5586
  let flatMode = false;
@@ -5452,7 +5595,11 @@ class List extends ListLite {
5452
5595
  this.pageSize = ((_b = this.conf.pagination) == null ? void 0 : _b.pageSize) || 20;
5453
5596
  this.repositionAt = this.$el;
5454
5597
  this.initListActionBtn();
5455
- this.$el.querySelector(".atk-copyright").innerHTML = `Powered By <a href="https://artalk.js.org" target="_blank" title="Artalk v${"2.1.6"}">Artalk</a>`;
5598
+ this.$commentCount = this.$el.querySelector(".atk-comment-count");
5599
+ if (this.ctx.conf.listSort) {
5600
+ this.initDropdown();
5601
+ }
5602
+ this.$el.querySelector(".atk-copyright").innerHTML = `Powered By <a href="https://artalk.js.org" target="_blank" title="Artalk v${"2.1.9"}">Artalk</a>`;
5456
5603
  this.ctx.on("list-reload", () => this.fetchComments(0));
5457
5604
  this.ctx.on("list-refresh-ui", () => this.refreshUI());
5458
5605
  this.ctx.on("list-import", (data) => this.importComments(data));
@@ -5555,6 +5702,67 @@ class List extends ListLite {
5555
5702
  this.$unreadBadge.style.display = "none";
5556
5703
  }
5557
5704
  }
5705
+ initDropdown() {
5706
+ this.$dropdownWrap = this.$commentCount;
5707
+ this.$commentCount.classList.add("atk-dropdown-wrap");
5708
+ this.$dropdownWrap.append(createElement(`<span class="atk-arrow-down-icon"></span>`));
5709
+ const reloadUseParamsEditor = (func) => {
5710
+ this.paramsEditor = (p) => {
5711
+ func(p);
5712
+ };
5713
+ this.fetchComments(0);
5714
+ };
5715
+ const dropdownList = [
5716
+ ["\u6700\u65B0", () => {
5717
+ reloadUseParamsEditor((p) => {
5718
+ p.sort_by = "date_desc";
5719
+ });
5720
+ }],
5721
+ ["\u6700\u70ED", () => {
5722
+ reloadUseParamsEditor((p) => {
5723
+ p.sort_by = "vote";
5724
+ });
5725
+ }],
5726
+ ["\u6700\u65E9", () => {
5727
+ reloadUseParamsEditor((p) => {
5728
+ p.sort_by = "date_asc";
5729
+ });
5730
+ }],
5731
+ ["\u4F5C\u8005", () => {
5732
+ reloadUseParamsEditor((p) => {
5733
+ p.view_only_admin = true;
5734
+ });
5735
+ }]
5736
+ ];
5737
+ let curtActive = 0;
5738
+ const onItemClick = (i, $item, name, action) => {
5739
+ action();
5740
+ curtActive = i;
5741
+ $dropdown.querySelectorAll(".active").forEach((e) => {
5742
+ e.classList.remove("active");
5743
+ });
5744
+ $item.classList.add("active");
5745
+ $dropdown.style.display = "none";
5746
+ setTimeout(() => {
5747
+ $dropdown.style.display = "";
5748
+ }, 80);
5749
+ };
5750
+ const $dropdown = createElement(`<ul class="atk-dropdown atk-fade-in"></ul>`);
5751
+ dropdownList.forEach((item, i) => {
5752
+ const name = item[0];
5753
+ const action = item[1];
5754
+ const $item = createElement(`<li class="atk-dropdown-item"><span></span></li>`);
5755
+ const $link = $item.querySelector("span");
5756
+ $link.innerText = name;
5757
+ $link.onclick = () => {
5758
+ onItemClick(i, $item, name, action);
5759
+ };
5760
+ $dropdown.append($item);
5761
+ if (i === curtActive)
5762
+ $item.classList.add("active");
5763
+ });
5764
+ this.$dropdownWrap.append($dropdown);
5765
+ }
5558
5766
  }
5559
5767
  var sidebarLayer = "";
5560
5768
  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';
@@ -5599,9 +5807,10 @@ class SidebarLayer extends Component {
5599
5807
  if (this.firstShow) {
5600
5808
  this.$iframeWrap.innerHTML = "";
5601
5809
  this.$iframe = createElement("<iframe></iframe>");
5602
- const baseURL = `${this.conf.server.replace(/\/$/, "")}/../sidebar/`;
5810
+ const baseURL = getURLBasedOnApi(this.ctx, "sidebar/");
5603
5811
  const userData = encodeURIComponent(JSON.stringify(this.ctx.user.data));
5604
- this.iframeLoad(`${baseURL}?pageKey=${encodeURIComponent(this.conf.pageKey)}&site=${encodeURIComponent(this.conf.site || "")}&user=${userData}${this.conf.darkMode ? `&darkMode=1` : ``}`);
5812
+ const location = window.location;
5813
+ this.iframeLoad(`${baseURL}?pageKey=${encodeURIComponent(this.conf.pageKey)}&site=${encodeURIComponent(this.conf.site || "")}&user=${userData}&referer=${encodeURIComponent(`${location.protocol}//${location.host}${location.pathname}`)}${this.conf.darkMode ? `&darkMode=1` : ``}`);
5605
5814
  this.$iframeWrap.append(this.$iframe);
5606
5815
  this.firstShow = false;
5607
5816
  } else {
@@ -5681,6 +5890,7 @@ const _Artalk = class {
5681
5890
  this.$root.innerHTML = "";
5682
5891
  this.initDarkMode();
5683
5892
  this.checkerLauncher = new CheckerLauncher(this.ctx);
5893
+ initMarked(this.ctx);
5684
5894
  this.editor = new Editor(this.ctx);
5685
5895
  this.$root.appendChild(this.editor.$el);
5686
5896
  this.list = new List(this.ctx);
@@ -5690,6 +5900,11 @@ const _Artalk = class {
5690
5900
  this.list.fetchComments(0);
5691
5901
  this.initEventBind();
5692
5902
  this.initPV();
5903
+ _Artalk.Plugins.forEach((plugin) => {
5904
+ if (typeof plugin === "function") {
5905
+ plugin(this.ctx);
5906
+ }
5907
+ });
5693
5908
  }
5694
5909
  initEventBind() {
5695
5910
  window.addEventListener("hashchange", () => {
@@ -5737,6 +5952,7 @@ const _Artalk = class {
5737
5952
  }
5738
5953
  setDarkMode(darkMode) {
5739
5954
  this.ctx.conf.darkMode = darkMode;
5955
+ this.ctx.trigger("conf-updated");
5740
5956
  this.initDarkMode();
5741
5957
  }
5742
5958
  initPV() {
@@ -5759,7 +5975,11 @@ const _Artalk = class {
5759
5975
  trigger(name, payload) {
5760
5976
  this.ctx.trigger(name, payload, "external");
5761
5977
  }
5978
+ static Use(plugin) {
5979
+ this.Plugins.push(plugin);
5980
+ }
5762
5981
  };
5763
5982
  let Artalk = _Artalk;
5764
5983
  __publicField(Artalk, "defaults", defaults$3);
5984
+ __publicField(Artalk, "Plugins", []);
5765
5985
  export { Artalk as default };