artalk 2.1.8 → 2.2.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.
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,
@@ -2655,37 +2657,36 @@ function versionCompare(a, b) {
2655
2657
  }
2656
2658
  return 0;
2657
2659
  }
2658
- 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
+ }
2659
2688
  function marked(ctx, src) {
2660
- if (!markedInstance) {
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
- markedInstance = nMarked;
2687
- }
2688
- return markedInstance.parse(src);
2689
+ return ctx.markedInstance.parse(src);
2689
2690
  }
2690
2691
  function getCorrectUserAgent() {
2691
2692
  return __async(this, null, function* () {
@@ -2711,7 +2712,19 @@ function getCorrectUserAgent() {
2711
2712
  return uaRaw;
2712
2713
  });
2713
2714
  }
2714
- function showLoading(parentElem) {
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
+ }
2727
+ function showLoading(parentElem, conf) {
2715
2728
  if (parentElem instanceof Context)
2716
2729
  parentElem = parentElem.$root;
2717
2730
  let $loading = parentElem.querySelector(".atk-loading");
@@ -2721,6 +2734,8 @@ function showLoading(parentElem) {
2721
2734
  <svg viewBox="25 25 50 50"><circle cx="50" cy="50" r="20" fill="none" stroke-width="2" stroke-miterlimit="10"></circle></svg>
2722
2735
  </div>
2723
2736
  </div>`);
2737
+ if (conf == null ? void 0 : conf.transparentBg)
2738
+ $loading.style.background = "transparent";
2724
2739
  parentElem.appendChild($loading);
2725
2740
  }
2726
2741
  $loading.style.display = "";
@@ -2887,11 +2902,7 @@ const _Layer = class extends Component {
2887
2902
  if (this.maskClickHideEnable)
2888
2903
  this.hide();
2889
2904
  };
2890
- this.bodyStyleOrgOverflow = document.body.style.overflow;
2891
- this.bodyStyleOrgPaddingRight = document.body.style.paddingRight;
2892
- document.body.style.overflow = "hidden";
2893
- const bpr = parseInt(window.getComputedStyle(document.body, null).getPropertyValue("padding-right"), 10);
2894
- document.body.style.paddingRight = `${getScrollBarWidth() + bpr || 0}px`;
2905
+ this.pageBodyScrollBarHide();
2895
2906
  }
2896
2907
  hide() {
2897
2908
  if (this.afterHide)
@@ -2900,8 +2911,7 @@ const _Layer = class extends Component {
2900
2911
  this.$el.style.display = "none";
2901
2912
  this.newActionTimer(() => {
2902
2913
  this.$wrap.style.display = "none";
2903
- document.body.style.overflow = this.bodyStyleOrgOverflow;
2904
- document.body.style.paddingRight = this.bodyStyleOrgPaddingRight;
2914
+ this.pageBodyScrollBarShow();
2905
2915
  this.checkCleanLayer();
2906
2916
  }, 450);
2907
2917
  this.newActionTimer(() => {
@@ -2912,6 +2922,17 @@ const _Layer = class extends Component {
2912
2922
  setMaskClickHide(enable) {
2913
2923
  this.maskClickHideEnable = enable;
2914
2924
  }
2925
+ pageBodyScrollBarHide() {
2926
+ this.bodyStyleOrgOverflow = document.body.style.overflow;
2927
+ this.bodyStyleOrgPaddingRight = document.body.style.paddingRight;
2928
+ document.body.style.overflow = "hidden";
2929
+ const bpr = parseInt(window.getComputedStyle(document.body, null).getPropertyValue("padding-right"), 10);
2930
+ document.body.style.paddingRight = `${getScrollBarWidth() + bpr || 0}px`;
2931
+ }
2932
+ pageBodyScrollBarShow() {
2933
+ document.body.style.overflow = this.bodyStyleOrgOverflow;
2934
+ document.body.style.paddingRight = this.bodyStyleOrgPaddingRight;
2935
+ }
2915
2936
  newActionTimer(func, delay) {
2916
2937
  const act = () => {
2917
2938
  func();
@@ -2929,6 +2950,7 @@ const _Layer = class extends Component {
2929
2950
  disposeNow() {
2930
2951
  document.body.style.overflow = "";
2931
2952
  this.$el.remove();
2953
+ this.pageBodyScrollBarShow();
2932
2954
  this.checkCleanLayer();
2933
2955
  }
2934
2956
  dispose() {
@@ -3019,6 +3041,7 @@ function Fetch(ctx, input, init, timeout) {
3019
3041
  json = yield new Promise((resolve, reject) => {
3020
3042
  ctx.trigger("checker-captcha", {
3021
3043
  imgData: json.data.img_data,
3044
+ iframe: json.data.iframe,
3022
3045
  onSuccess: () => {
3023
3046
  recall(resolve, reject);
3024
3047
  },
@@ -3061,14 +3084,6 @@ function POST(ctx, url, data) {
3061
3084
  return json.data || {};
3062
3085
  });
3063
3086
  }
3064
- function GET(ctx, url, data) {
3065
- return __async(this, null, function* () {
3066
- const json = yield Fetch(ctx, url + (data ? `?${new URLSearchParams(data)}` : ""), {
3067
- method: "GET"
3068
- });
3069
- return json.data || {};
3070
- });
3071
- }
3072
3087
  function ToFormData(object) {
3073
3088
  const formData = new FormData();
3074
3089
  Object.keys(object).forEach((key) => formData.append(key, String(object[key])));
@@ -3183,6 +3198,12 @@ class Api {
3183
3198
  }
3184
3199
  };
3185
3200
  }
3201
+ loginStatus() {
3202
+ return __async(this, null, function* () {
3203
+ const data = yield POST(this.ctx, `${this.baseURL}/login-status`);
3204
+ return data || { is_login: false };
3205
+ });
3206
+ }
3186
3207
  pageGet(siteName, offset, limit) {
3187
3208
  return __async(this, null, function* () {
3188
3209
  const params = {
@@ -3322,23 +3343,74 @@ class Api {
3322
3343
  }
3323
3344
  captchaGet() {
3324
3345
  return __async(this, null, function* () {
3325
- const data = yield GET(this.ctx, `${this.baseURL}/captcha/refresh`);
3346
+ const data = yield POST(this.ctx, `${this.baseURL}/captcha/refresh`);
3326
3347
  return data.img_data || "";
3327
3348
  });
3328
3349
  }
3329
3350
  captchaCheck(value) {
3330
3351
  return __async(this, null, function* () {
3331
- const data = yield GET(this.ctx, `${this.baseURL}/captcha/check`, { value });
3352
+ const data = yield POST(this.ctx, `${this.baseURL}/captcha/check`, { value });
3332
3353
  return data.img_data || "";
3333
3354
  });
3334
3355
  }
3356
+ captchaStatus() {
3357
+ return __async(this, null, function* () {
3358
+ const data = yield POST(this.ctx, `${this.baseURL}/captcha/status`);
3359
+ return data || { is_pass: false };
3360
+ });
3361
+ }
3335
3362
  }
3336
3363
  const CaptchaChecker = {
3337
- request(that, inputVal) {
3364
+ request(that, ctx, inputVal) {
3338
3365
  return new Api(that.ctx).captchaCheck(inputVal);
3339
3366
  },
3340
- body(that) {
3341
- const elem = createElement(`<span><img class="atk-captcha-img" src="${that.submitCaptchaImgData || ""}" alt="\u9A8C\u8BC1\u7801">\u6572\u5165\u9A8C\u8BC1\u7801\u7EE7\u7EED\uFF1A</span>`);
3367
+ body(that, ctx) {
3368
+ if (that.captchaConf.iframe) {
3369
+ const $iframeWrap = createElement(`<div class="atk-checker-iframe-wrap"></div>`);
3370
+ const $iframe = createElement(`<iframe class="atk-fade-in"></iframe>`);
3371
+ $iframe.style.display = "none";
3372
+ showLoading($iframeWrap, { transparentBg: true });
3373
+ $iframe.src = `${that.ctx.conf.server}/captcha/get`;
3374
+ $iframe.onload = () => {
3375
+ $iframe.style.display = "";
3376
+ hideLoading($iframeWrap);
3377
+ };
3378
+ $iframeWrap.append($iframe);
3379
+ const $closeBtn = createElement(`<div class="atk-close-btn"><i class="atk-icon atk-icon-close"></i></div>`);
3380
+ $iframeWrap.append($closeBtn);
3381
+ ctx.hideInteractInput();
3382
+ let stop = false;
3383
+ const sleep = (ms) => new Promise((resolve) => {
3384
+ window.setTimeout(() => {
3385
+ resolve(null);
3386
+ }, ms);
3387
+ });
3388
+ (function queryStatus() {
3389
+ return __async(this, null, function* () {
3390
+ yield sleep(1e3);
3391
+ if (stop)
3392
+ return;
3393
+ let isPass = false;
3394
+ try {
3395
+ const resp = yield new Api(that.ctx).captchaStatus();
3396
+ isPass = resp.is_pass;
3397
+ } catch (e) {
3398
+ isPass = false;
3399
+ }
3400
+ if (isPass) {
3401
+ ctx.triggerSuccess();
3402
+ } else {
3403
+ queryStatus();
3404
+ }
3405
+ });
3406
+ })();
3407
+ $closeBtn.onclick = () => {
3408
+ stop = true;
3409
+ ctx.cancel();
3410
+ };
3411
+ return $iframeWrap;
3412
+ }
3413
+ 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>`);
3342
3414
  elem.querySelector(".atk-captcha-img").onclick = () => {
3343
3415
  const imgEl = elem.querySelector(".atk-captcha-img");
3344
3416
  new Api(that.ctx).captchaGet().then((imgData) => {
@@ -3349,16 +3421,16 @@ const CaptchaChecker = {
3349
3421
  };
3350
3422
  return elem;
3351
3423
  },
3352
- onSuccess(that, data, inputVal, formEl) {
3353
- that.submitCaptchaVal = inputVal;
3424
+ onSuccess(that, ctx, data, inputVal, formEl) {
3425
+ that.captchaConf.val = inputVal;
3354
3426
  },
3355
- onError(that, err, inputVal, formEl) {
3427
+ onError(that, ctx, err, inputVal, formEl) {
3356
3428
  formEl.querySelector(".atk-captcha-img").click();
3357
3429
  }
3358
3430
  };
3359
3431
  const AdminChecker = {
3360
3432
  inputType: "password",
3361
- request(that, inputVal) {
3433
+ request(that, ctx, inputVal) {
3362
3434
  const data = {
3363
3435
  name: that.ctx.user.data.nick,
3364
3436
  email: that.ctx.user.data.email,
@@ -3366,33 +3438,33 @@ const AdminChecker = {
3366
3438
  };
3367
3439
  return new Api(that.ctx).login(data.name, data.email, data.password);
3368
3440
  },
3369
- body() {
3441
+ body(that, ctx) {
3370
3442
  return createElement("<span>\u6572\u5165\u5BC6\u7801\u6765\u9A8C\u8BC1\u7BA1\u7406\u5458\u8EAB\u4EFD\uFF1A</span>");
3371
3443
  },
3372
- onSuccess(that, userToken, inputVal, formEl) {
3444
+ onSuccess(that, ctx, userToken, inputVal, formEl) {
3373
3445
  that.ctx.user.data.isAdmin = true;
3374
3446
  that.ctx.user.data.token = userToken;
3375
3447
  that.ctx.user.save();
3376
3448
  that.ctx.trigger("user-changed", that.ctx.user.data);
3377
3449
  that.ctx.trigger("list-reload");
3378
3450
  },
3379
- onError(that, err, inputVal, formEl) {
3451
+ onError(that, ctx, err, inputVal, formEl) {
3380
3452
  }
3381
3453
  };
3382
3454
  class CheckerLauncher {
3383
3455
  constructor(ctx) {
3384
3456
  __publicField(this, "ctx");
3385
3457
  __publicField(this, "launched", []);
3386
- __publicField(this, "submitCaptchaVal");
3387
- __publicField(this, "submitCaptchaImgData");
3458
+ __publicField(this, "captchaConf", {});
3388
3459
  this.ctx = ctx;
3389
3460
  this.initEventBind();
3390
3461
  }
3391
3462
  initEventBind() {
3392
3463
  this.ctx.on("checker-captcha", (conf) => {
3393
- if (conf.imgData) {
3394
- this.submitCaptchaImgData = conf.imgData;
3395
- }
3464
+ if (conf.imgData)
3465
+ this.captchaConf.imgData = conf.imgData;
3466
+ if (conf.iframe)
3467
+ this.captchaConf.iframe = conf.iframe;
3396
3468
  this.fire(CaptchaChecker, conf);
3397
3469
  });
3398
3470
  this.ctx.on("checker-admin", (conf) => {
@@ -3406,12 +3478,31 @@ class CheckerLauncher {
3406
3478
  const layer = new Layer(this.ctx, `checker-${new Date().getTime()}`);
3407
3479
  layer.setMaskClickHide(false);
3408
3480
  layer.show();
3481
+ let hideInteractInput = false;
3482
+ const checkerCtx = {
3483
+ getLayer: () => layer,
3484
+ hideInteractInput: () => {
3485
+ hideInteractInput = true;
3486
+ },
3487
+ triggerSuccess: () => {
3488
+ this.close(checker, layer);
3489
+ if (checker.onSuccess)
3490
+ checker.onSuccess(this, checkerCtx, "", "", formEl);
3491
+ if (payload.onSuccess)
3492
+ payload.onSuccess("", dialog.$el);
3493
+ },
3494
+ cancel: () => {
3495
+ this.close(checker, layer);
3496
+ if (payload.onCancel)
3497
+ payload.onCancel();
3498
+ }
3499
+ };
3409
3500
  const formEl = createElement();
3410
- formEl.appendChild(checker.body(this));
3411
- const input = createElement(`<input id="check" type="${checker.inputType || "text"}" autocomplete="off" required placeholder="">`);
3412
- formEl.appendChild(input);
3413
- setTimeout(() => input.focus(), 80);
3414
- input.onkeyup = (evt) => {
3501
+ formEl.appendChild(checker.body(this, checkerCtx));
3502
+ const $input = createElement(`<input id="check" type="${checker.inputType || "text"}" autocomplete="off" required placeholder="">`);
3503
+ formEl.appendChild($input);
3504
+ setTimeout(() => $input.focus(), 80);
3505
+ $input.onkeyup = (evt) => {
3415
3506
  if (evt.key === "Enter" || evt.keyCode === 13) {
3416
3507
  evt.preventDefault();
3417
3508
  layer.getEl().querySelector('button[data-action="confirm"]').click();
@@ -3420,7 +3511,7 @@ class CheckerLauncher {
3420
3511
  let btnTextOrg;
3421
3512
  const dialog = new Dialog(formEl);
3422
3513
  dialog.setYes((btnEl) => {
3423
- const inputVal = input.value.trim();
3514
+ const inputVal = $input.value.trim();
3424
3515
  if (!btnTextOrg)
3425
3516
  btnTextOrg = btnEl.innerText;
3426
3517
  const btnTextSet = (btnText) => {
@@ -3432,18 +3523,18 @@ class CheckerLauncher {
3432
3523
  btnEl.classList.remove("error");
3433
3524
  };
3434
3525
  btnEl.innerText = "\u52A0\u8F7D\u4E2D...";
3435
- checker.request(this, inputVal).then((data) => {
3436
- this.done(checker, layer);
3526
+ checker.request(this, checkerCtx, inputVal).then((data) => {
3527
+ this.close(checker, layer);
3437
3528
  if (checker.onSuccess)
3438
- checker.onSuccess(this, data, inputVal, formEl);
3529
+ checker.onSuccess(this, checkerCtx, data, inputVal, formEl);
3439
3530
  if (payload.onSuccess)
3440
3531
  payload.onSuccess(inputVal, dialog.$el);
3441
3532
  }).catch((err) => {
3442
3533
  btnTextSet(String(err.msg || String(err)));
3443
3534
  if (checker.onError)
3444
- checker.onError(this, err, inputVal, formEl);
3535
+ checker.onError(this, checkerCtx, err, inputVal, formEl);
3445
3536
  const tf = setTimeout(() => btnTextRestore(), 3e3);
3446
- input.onfocus = () => {
3537
+ $input.onfocus = () => {
3447
3538
  btnTextRestore();
3448
3539
  clearTimeout(tf);
3449
3540
  };
@@ -3451,16 +3542,20 @@ class CheckerLauncher {
3451
3542
  return false;
3452
3543
  });
3453
3544
  dialog.setNo(() => {
3454
- this.done(checker, layer);
3545
+ this.close(checker, layer);
3455
3546
  if (payload.onCancel)
3456
3547
  payload.onCancel();
3457
3548
  return false;
3458
3549
  });
3550
+ if (hideInteractInput) {
3551
+ $input.style.display = "none";
3552
+ dialog.$el.querySelector(".atk-layer-dialog-actions").style.display = "none";
3553
+ }
3459
3554
  layer.getEl().append(dialog.$el);
3460
3555
  if (payload.onMount)
3461
3556
  payload.onMount(dialog.$el);
3462
3557
  }
3463
- done(checker, layer) {
3558
+ close(checker, layer) {
3464
3559
  layer.disposeNow();
3465
3560
  this.launched = this.launched.filter((c) => c !== checker);
3466
3561
  }
@@ -3913,14 +4008,14 @@ class Editor extends Component {
3913
4008
  btnElem.classList.add("active");
3914
4009
  });
3915
4010
  });
3916
- this.initImgUploadBtn();
4011
+ this.initImgUpload();
3917
4012
  }
3918
4013
  closePlug() {
3919
4014
  this.$plugWrap.innerHTML = "";
3920
4015
  this.$plugWrap.style.display = "none";
3921
4016
  this.openedPlugName = null;
3922
4017
  }
3923
- initImgUploadBtn() {
4018
+ initImgUpload() {
3924
4019
  this.$imgUploadBtn = createElement(`<span class="atk-plug-btn">\u56FE\u7247</span>`);
3925
4020
  this.$plugBtnWrap.querySelector('[data-plug-name="preview"]').before(this.$imgUploadBtn);
3926
4021
  this.$imgUploadBtn.onclick = () => {
@@ -3937,18 +4032,32 @@ class Editor extends Component {
3937
4032
  };
3938
4033
  $input.click();
3939
4034
  };
4035
+ const uploadFromFileList = (files) => {
4036
+ if (!files)
4037
+ return;
4038
+ for (let i = 0; i < files.length; i++) {
4039
+ const file = files[i];
4040
+ this.uploadImg(file);
4041
+ }
4042
+ };
3940
4043
  this.$textarea.addEventListener("dragover", (evt) => {
3941
4044
  evt.stopPropagation();
3942
4045
  evt.preventDefault();
3943
4046
  });
3944
4047
  this.$textarea.addEventListener("drop", (evt) => {
3945
4048
  var _a;
3946
- if ((_a = evt.dataTransfer) == null ? void 0 : _a.files) {
4049
+ const files = (_a = evt.dataTransfer) == null ? void 0 : _a.files;
4050
+ if (files == null ? void 0 : files.length) {
3947
4051
  evt.preventDefault();
3948
- for (let i = 0; i < evt.dataTransfer.files.length; i++) {
3949
- const file = evt.dataTransfer.files[i];
3950
- this.uploadImg(file);
3951
- }
4052
+ uploadFromFileList(files);
4053
+ }
4054
+ });
4055
+ this.$textarea.addEventListener("paste", (evt) => {
4056
+ var _a;
4057
+ const files = (_a = evt.clipboardData) == null ? void 0 : _a.files;
4058
+ if (files == null ? void 0 : files.length) {
4059
+ evt.preventDefault();
4060
+ uploadFromFileList(files);
3952
4061
  }
3953
4062
  });
3954
4063
  }
@@ -3965,8 +4074,14 @@ class Editor extends Component {
3965
4074
  const fileExt = /[^.]+$/.exec(file.name);
3966
4075
  if (!fileExt || !this.allowImgExts.includes(fileExt[0]))
3967
4076
  return;
3968
- const uploadPlaceholderTxt = `
3969
- ![](Uploading ${file.name}...)`;
4077
+ if (!this.ctx.user.checkHasBasicUserInfo()) {
4078
+ this.showNotify("\u586B\u5165\u4F60\u7684\u540D\u5B57\u90AE\u7BB1\u624D\u80FD\u4E0A\u4F20\u54E6", "w");
4079
+ return;
4080
+ }
4081
+ let insertPrefix = "\n";
4082
+ if (this.$textarea.value.trim() === "")
4083
+ insertPrefix = "";
4084
+ const uploadPlaceholderTxt = `${insertPrefix}![](Uploading ${file.name}...)`;
3970
4085
  this.insertContent(uploadPlaceholderTxt);
3971
4086
  let resp;
3972
4087
  try {
@@ -3977,15 +4092,12 @@ class Editor extends Component {
3977
4092
  }
3978
4093
  if (!!resp && resp.img_url) {
3979
4094
  let imgURL = resp.img_url;
3980
- if (imgURL.startsWith(".") || imgURL.startsWith("/") && !imgURL.startsWith("//")) {
3981
- imgURL = `${this.ctx.conf.server.replace(/\/api\/?$/, "")}/${imgURL.replace(/^\//, "")}`;
3982
- }
3983
- this.$textarea.value = this.$textarea.value.replace(uploadPlaceholderTxt, `
3984
- ![](${imgURL})`);
4095
+ if (!isValidURL(imgURL))
4096
+ imgURL = getURLBasedOnApi(this.ctx, imgURL);
4097
+ this.setContent(this.$textarea.value.replace(uploadPlaceholderTxt, `${insertPrefix}![](${imgURL})`));
3985
4098
  } else {
3986
- this.$textarea.value = this.$textarea.value.replace(uploadPlaceholderTxt, "");
4099
+ this.setContent(this.$textarea.value.replace(uploadPlaceholderTxt, ""));
3987
4100
  }
3988
- this.saveContent();
3989
4101
  });
3990
4102
  }
3991
4103
  insertContent(val) {
@@ -4019,7 +4131,7 @@ class Editor extends Component {
4019
4131
  this.setContent("");
4020
4132
  this.cancelReply();
4021
4133
  }
4022
- getContent() {
4134
+ getFinalContent() {
4023
4135
  let content = this.getContentOriginal();
4024
4136
  if (this.plugList && this.plugList.emoticons) {
4025
4137
  const emoticonsPlug2 = this.plugList.emoticons;
@@ -4031,7 +4143,7 @@ class Editor extends Component {
4031
4143
  return this.$textarea.value || "";
4032
4144
  }
4033
4145
  getContentMarked() {
4034
- return marked(this.ctx, this.getContent());
4146
+ return marked(this.ctx, this.getFinalContent());
4035
4147
  }
4036
4148
  initBottomPart() {
4037
4149
  this.initReply();
@@ -4080,7 +4192,7 @@ class Editor extends Component {
4080
4192
  }
4081
4193
  submit() {
4082
4194
  return __async(this, null, function* () {
4083
- if (this.getContent().trim() === "") {
4195
+ if (this.getFinalContent().trim() === "") {
4084
4196
  this.$textarea.focus();
4085
4197
  return;
4086
4198
  }
@@ -4088,7 +4200,7 @@ class Editor extends Component {
4088
4200
  showLoading(this.$el);
4089
4201
  try {
4090
4202
  const nComment = yield new Api(this.ctx).add({
4091
- content: this.getContent(),
4203
+ content: this.getFinalContent(),
4092
4204
  nick: this.user.data.nick,
4093
4205
  email: this.user.data.email,
4094
4206
  link: this.user.data.link,
@@ -5163,6 +5275,7 @@ class ReadMoreBtn {
5163
5275
  this.hide();
5164
5276
  }
5165
5277
  }
5278
+ const backendMinVersion = "2.1.1";
5166
5279
  class ListLite extends Component {
5167
5280
  constructor(ctx) {
5168
5281
  super(ctx);
@@ -5244,11 +5357,15 @@ class ListLite extends Component {
5244
5357
  });
5245
5358
  }
5246
5359
  onLoad(data, offset) {
5360
+ var _a, _b;
5247
5361
  if (this.pageMode === "pagination") {
5248
5362
  this.clearAllComments();
5249
5363
  }
5250
5364
  this.data = data;
5251
- if (this.ctx.conf.versionCheck && this.versionCheck(data.api_version))
5365
+ const feMinVersion = ((_a = data.api_version) == null ? void 0 : _a.fe_min_version) || "0.0.0";
5366
+ if (this.ctx.conf.versionCheck && this.versionCheck("\u524D\u7AEF", feMinVersion, "2.2.1"))
5367
+ return;
5368
+ if (this.ctx.conf.versionCheck && this.versionCheck("\u540E\u7AEF", backendMinVersion, (_b = data.api_version) == null ? void 0 : _b.version))
5252
5369
  return;
5253
5370
  if (data.conf && typeof data.conf.img_upload === "boolean") {
5254
5371
  this.ctx.conf.imgUpload = data.conf.img_upload;
@@ -5523,20 +5640,19 @@ class ListLite extends Component {
5523
5640
  });
5524
5641
  }
5525
5642
  }
5526
- versionCheck(versionData) {
5527
- const needVersion = (versionData == null ? void 0 : versionData.fe_min_version) || "0.0.0";
5528
- const needUpdate = versionCompare(needVersion, "2.1.8") === 1;
5643
+ versionCheck(name, needVersion, curtVersion) {
5644
+ const needUpdate = versionCompare(needVersion, curtVersion) === 1;
5529
5645
  if (needUpdate) {
5530
- 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.8"}\uFF0C\u9700\u6C42\u7248\u672C >= ${needVersion}</span><br/><br/></div>`);
5646
+ 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>`);
5531
5647
  const ignoreBtn = createElement('<span style="cursor:pointer;">\u5FFD\u7565</span>');
5532
5648
  ignoreBtn.onclick = () => {
5533
- setError(this.ctx, null);
5649
+ setError(this.$el.parentElement, null);
5534
5650
  this.ctx.conf.versionCheck = false;
5535
5651
  this.ctx.trigger("conf-updated");
5536
5652
  this.fetchComments(0);
5537
5653
  };
5538
5654
  errEl.append(ignoreBtn);
5539
- setError(this.ctx, errEl, '<span class="atk-warn-title">Artalk Warn</span>');
5655
+ setError(this.$el.parentElement, errEl, '<span class="atk-warn-title">Artalk Warn</span>');
5540
5656
  }
5541
5657
  return needUpdate;
5542
5658
  }
@@ -5566,8 +5682,10 @@ class List extends ListLite {
5566
5682
  this.repositionAt = this.$el;
5567
5683
  this.initListActionBtn();
5568
5684
  this.$commentCount = this.$el.querySelector(".atk-comment-count");
5569
- this.initDropdown();
5570
- this.$el.querySelector(".atk-copyright").innerHTML = `Powered By <a href="https://artalk.js.org" target="_blank" title="Artalk v${"2.1.8"}">Artalk</a>`;
5685
+ if (this.ctx.conf.listSort) {
5686
+ this.initDropdown();
5687
+ }
5688
+ this.$el.querySelector(".atk-copyright").innerHTML = `Powered By <a href="https://artalk.js.org" target="_blank" title="Artalk v${"2.2.1"}">Artalk</a>`;
5571
5689
  this.ctx.on("list-reload", () => this.fetchComments(0));
5572
5690
  this.ctx.on("list-refresh-ui", () => this.refreshUI());
5573
5691
  this.ctx.on("list-import", (data) => this.importComments(data));
@@ -5773,11 +5891,31 @@ class SidebarLayer extends Component {
5773
5891
  this.$el.style.transform = "translate(0, 0)";
5774
5892
  }, 20);
5775
5893
  if (this.firstShow) {
5894
+ if (this.ctx.user.data.isAdmin) {
5895
+ const resp = yield new Api(this.ctx).loginStatus();
5896
+ if (!resp.is_login) {
5897
+ yield new Promise((resolve, reject) => {
5898
+ this.ctx.trigger("checker-admin", {
5899
+ onSuccess: () => {
5900
+ resolve(null);
5901
+ setTimeout(() => {
5902
+ this.show();
5903
+ }, 500);
5904
+ },
5905
+ onCancel: () => {
5906
+ var _a;
5907
+ (_a = this.layer) == null ? void 0 : _a.hide();
5908
+ }
5909
+ });
5910
+ });
5911
+ }
5912
+ }
5776
5913
  this.$iframeWrap.innerHTML = "";
5777
5914
  this.$iframe = createElement("<iframe></iframe>");
5778
- const baseURL = `${this.conf.server.replace(/\/$/, "")}/../sidebar/`;
5915
+ const baseURL = getURLBasedOnApi(this.ctx, "sidebar/");
5779
5916
  const userData = encodeURIComponent(JSON.stringify(this.ctx.user.data));
5780
- this.iframeLoad(`${baseURL}?pageKey=${encodeURIComponent(this.conf.pageKey)}&site=${encodeURIComponent(this.conf.site || "")}&user=${userData}${this.conf.darkMode ? `&darkMode=1` : ``}`);
5917
+ const location = window.location;
5918
+ 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` : ``}`);
5781
5919
  this.$iframeWrap.append(this.$iframe);
5782
5920
  this.firstShow = false;
5783
5921
  } else {
@@ -5857,6 +5995,7 @@ const _Artalk = class {
5857
5995
  this.$root.innerHTML = "";
5858
5996
  this.initDarkMode();
5859
5997
  this.checkerLauncher = new CheckerLauncher(this.ctx);
5998
+ initMarked(this.ctx);
5860
5999
  this.editor = new Editor(this.ctx);
5861
6000
  this.$root.appendChild(this.editor.$el);
5862
6001
  this.list = new List(this.ctx);
@@ -5866,6 +6005,11 @@ const _Artalk = class {
5866
6005
  this.list.fetchComments(0);
5867
6006
  this.initEventBind();
5868
6007
  this.initPV();
6008
+ _Artalk.Plugins.forEach((plugin) => {
6009
+ if (typeof plugin === "function") {
6010
+ plugin(this.ctx);
6011
+ }
6012
+ });
5869
6013
  }
5870
6014
  initEventBind() {
5871
6015
  window.addEventListener("hashchange", () => {
@@ -5936,7 +6080,11 @@ const _Artalk = class {
5936
6080
  trigger(name, payload) {
5937
6081
  this.ctx.trigger(name, payload, "external");
5938
6082
  }
6083
+ static Use(plugin) {
6084
+ this.Plugins.push(plugin);
6085
+ }
5939
6086
  };
5940
6087
  let Artalk = _Artalk;
5941
6088
  __publicField(Artalk, "defaults", defaults$3);
6089
+ __publicField(Artalk, "Plugins", []);
5942
6090
  export { Artalk as default };