@inpageedit/core 0.5.4 → 0.7.0

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 (77) hide show
  1. package/dist/CheckBox-D3rHnX7I.js +13 -0
  2. package/dist/CheckBox-D3rHnX7I.js.map +1 -0
  3. package/dist/IconQuickEdit-YVn1ANbm.js +27 -0
  4. package/dist/IconQuickEdit-YVn1ANbm.js.map +1 -0
  5. package/dist/InPageEdit.d.ts +7 -5
  6. package/dist/InputBox-BV4m05Xs.js +22 -0
  7. package/dist/InputBox-BV4m05Xs.js.map +1 -0
  8. package/dist/RadioBox-nJqWsxW2.js +13 -0
  9. package/dist/RadioBox-nJqWsxW2.js.map +1 -0
  10. package/dist/__test__/utils/constants.d.ts +2 -0
  11. package/dist/components/Icon/IconEdit.d.ts +2 -0
  12. package/dist/components/Icon/IconQuickEdit.d.ts +2 -0
  13. package/dist/components/MwUserLinks.d.ts +2 -0
  14. package/dist/components/index.js +13 -11
  15. package/dist/components/index.js.map +1 -1
  16. package/dist/{index-i-Uf0vuA.js → index-1JtE4urY.js} +490 -374
  17. package/dist/{index-i-Uf0vuA.js.map → index-1JtE4urY.js.map} +1 -1
  18. package/dist/{index-UyiZ7umI.js → index-2AEdgbUL.js} +4 -4
  19. package/dist/index-2AEdgbUL.js.map +1 -0
  20. package/dist/index-2kN4SKmT.js +116 -0
  21. package/dist/index-2kN4SKmT.js.map +1 -0
  22. package/dist/{index-BSjnoNn2.js → index-B3Bsg_nE.js} +5 -3
  23. package/dist/index-B3Bsg_nE.js.map +1 -0
  24. package/dist/index-BCMwmSfQ.js +295 -0
  25. package/dist/index-BCMwmSfQ.js.map +1 -0
  26. package/dist/{index-BedbUMp8.js → index-C0ci6Ll1.js} +14 -12
  27. package/dist/index-C0ci6Ll1.js.map +1 -0
  28. package/dist/index-CZnu6cRK.js +319 -0
  29. package/dist/index-CZnu6cRK.js.map +1 -0
  30. package/dist/{index-xJ2bdsOD.js → index-CheNjwas.js} +5 -5
  31. package/dist/{index-xJ2bdsOD.js.map → index-CheNjwas.js.map} +1 -1
  32. package/dist/{index-DtOC8Ck-.js → index-CrWxZ0yl.js} +66 -63
  33. package/dist/{index-DtOC8Ck-.js.map → index-CrWxZ0yl.js.map} +1 -1
  34. package/dist/{index-DNQjqBV-.js → index-DqfQ7hp6.js} +3359 -3037
  35. package/dist/index-DqfQ7hp6.js.map +1 -0
  36. package/dist/index-lZkYoUca.js +46 -0
  37. package/dist/index-lZkYoUca.js.map +1 -0
  38. package/dist/index-sfkutNHj.js +201 -0
  39. package/dist/index-sfkutNHj.js.map +1 -0
  40. package/dist/index.js +1 -1
  41. package/dist/makeCallable-LDU0xZMJ.js +40 -0
  42. package/dist/makeCallable-LDU0xZMJ.js.map +1 -0
  43. package/dist/models/WikiPage/index.d.ts +2 -2
  44. package/dist/models/WikiTitle/index.d.ts +87 -11
  45. package/dist/models/WikiTitle/index.spec.d.ts +1 -0
  46. package/dist/noop-ClDc6zv4.js +6 -0
  47. package/dist/noop-ClDc6zv4.js.map +1 -0
  48. package/dist/plugins/in-article-links/index.d.ts +33 -7
  49. package/dist/plugins/quick-delete/index.d.ts +47 -0
  50. package/dist/plugins/quick-diff/PluginQuickDiffCore.d.ts +4 -2
  51. package/dist/plugins/quick-diff/components/DiffTable.d.ts +17 -0
  52. package/dist/plugins/quick-preview/index.d.ts +6 -3
  53. package/dist/services/ApiService.d.ts +2 -2
  54. package/dist/services/ModalService/IPEModal.d.ts +1 -1
  55. package/dist/services/SiteMetadataService.d.ts +43 -4
  56. package/dist/services/WikiPageService.d.ts +2 -2
  57. package/dist/services/WikiTitleService.d.ts +14 -0
  58. package/dist/style.css +1 -1
  59. package/dist/types/SiteMetadata.d.ts +1 -1
  60. package/dist/utils/url.d.ts +24 -0
  61. package/lib/index.umd.js +28 -28
  62. package/lib/index.umd.js.map +1 -1
  63. package/lib/style.css +1 -1
  64. package/package.json +10 -1
  65. package/dist/InputBox-FIzJ-rPN.js +0 -30
  66. package/dist/InputBox-FIzJ-rPN.js.map +0 -1
  67. package/dist/RadioBox-CaA8VgLu.js +0 -54
  68. package/dist/RadioBox-CaA8VgLu.js.map +0 -1
  69. package/dist/index-BSjnoNn2.js.map +0 -1
  70. package/dist/index-BedbUMp8.js.map +0 -1
  71. package/dist/index-DNQjqBV-.js.map +0 -1
  72. package/dist/index-UyiZ7umI.js.map +0 -1
  73. package/dist/index-e7eyr1FL.js +0 -96
  74. package/dist/index-e7eyr1FL.js.map +0 -1
  75. package/dist/index-rMDuLpcz.js +0 -458
  76. package/dist/index-rMDuLpcz.js.map +0 -1
  77. package/dist/plugins/quick-edit/PluginQuickEditInArticleLinks.d.ts +0 -14
@@ -0,0 +1,46 @@
1
+ import { j as o } from "./index-CvhkVj_L.js";
2
+ const b = "_mbox_5x43w_1", f = "_title_5x43w_12", u = "_content_5x43w_19", v = "_close_5x43w_27", n = {
3
+ mbox: b,
4
+ title: f,
5
+ content: u,
6
+ close: v
7
+ }, g = (l) => {
8
+ const {
9
+ type: t = "default",
10
+ title: i,
11
+ content: a,
12
+ closeable: r = !0,
13
+ titleProps: m,
14
+ contentProps: p,
15
+ children: x,
16
+ ...d
17
+ } = l;
18
+ let s = i;
19
+ typeof i > "u" && t !== "default" && (s = t[0].toUpperCase() + t.slice(1).toLowerCase());
20
+ const c = async () => {
21
+ if (!e)
22
+ return Promise.resolve();
23
+ const { promise: h, resolve: _ } = Promise.withResolvers();
24
+ return e.animate(
25
+ [
26
+ { opacity: "1", height: e.clientHeight + "px" },
27
+ { opacity: "0", height: "0px", margin: "0px" }
28
+ ],
29
+ {
30
+ duration: 300,
31
+ easing: "ease"
32
+ }
33
+ ).addEventListener("finish", () => {
34
+ e.remove(), _();
35
+ }), h;
36
+ }, e = /* @__PURE__ */ o("div", { className: `theme-ipe ipe-mbox mbox-type-${t || "default"} ${n.mbox}`, ...d, children: [
37
+ s && /* @__PURE__ */ o("div", { className: `ipe-mbox-title ${n.title}`, ...m, children: s }),
38
+ /* @__PURE__ */ o("div", { className: `ipe-mbox-content ${n.content}`, ...p, children: x || a }),
39
+ r && /* @__PURE__ */ o("a", { onClick: c, className: `ipe-mbox-close ${n.close}`, children: "×" })
40
+ ] });
41
+ return e.close = c, e;
42
+ };
43
+ export {
44
+ g as M
45
+ };
46
+ //# sourceMappingURL=index-lZkYoUca.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-lZkYoUca.js","sources":["../src/components/MBox/index.tsx"],"sourcesContent":["import { ReactNode } from 'jsx-dom'\nimport { JSX } from 'jsx-dom/jsx-runtime'\nimport styles from './styles.module.sass'\n\nexport type MBoxProps = {\n type?:\n | ''\n | 'default'\n | 'note'\n | 'info'\n | 'tip'\n | 'success'\n | 'important'\n | 'done'\n | 'warning'\n | 'caution'\n | 'error'\n title?: ReactNode\n content?: ReactNode\n closeable?: boolean\n titleProps?: JSX.IntrinsicElements['div']\n contentProps?: JSX.IntrinsicElements['div']\n} & JSX.IntrinsicElements['div']\n\nexport type MBoxElement = HTMLElement & {\n close: () => Promise<void>\n}\n\nexport const MBox = (props: MBoxProps) => {\n const {\n type = 'default',\n title,\n content,\n closeable = true,\n titleProps,\n contentProps,\n children,\n ...rest\n } = props\n let titleContent = title\n if (typeof title === 'undefined' && type !== 'default') {\n titleContent = type[0].toUpperCase() + type.slice(1).toLowerCase()\n }\n\n const close = async () => {\n if (!box) {\n return Promise.resolve()\n }\n const { promise, resolve } = Promise.withResolvers<void>()\n\n const animation = box.animate(\n [\n { opacity: '1', height: box.clientHeight + 'px' },\n { opacity: '0', height: '0px', margin: '0px' },\n ],\n {\n duration: 300,\n easing: 'ease',\n }\n )\n\n animation.addEventListener('finish', () => {\n box.remove()\n resolve()\n })\n\n return promise\n }\n\n const box = (\n <div className={`theme-ipe ipe-mbox mbox-type-${type || 'default'} ${styles.mbox}`} {...rest}>\n {titleContent && (\n <div className={`ipe-mbox-title ${styles.title}`} {...titleProps}>\n {titleContent}\n </div>\n )}\n <div className={`ipe-mbox-content ${styles.content}`} {...contentProps}>\n {children || content}\n </div>\n {closeable && (\n <a onClick={close} className={`ipe-mbox-close ${styles.close}`}>\n ×\n </a>\n )}\n </div>\n ) as MBoxElement\n box.close = close\n return box\n}\n"],"names":["MBox","props","type","title","content","closeable","titleProps","contentProps","children","rest","titleContent","close","box","promise","resolve","jsxs","styles","jsx"],"mappings":";;;;;;GA4BaA,IAAO,CAACC,MAAqB;AACxC,QAAM;AAAA,IACJ,MAAAC,IAAO;AAAA,IACP,OAAAC;AAAA,IACA,SAAAC;AAAA,IACA,WAAAC,IAAY;AAAA,IACZ,YAAAC;AAAA,IACA,cAAAC;AAAA,IACA,UAAAC;AAAA,IACA,GAAGC;AAAA,EAAA,IACDR;AACJ,MAAIS,IAAeP;AACnB,EAAI,OAAOA,IAAU,OAAeD,MAAS,cAC3CQ,IAAeR,EAAK,CAAC,EAAE,YAAA,IAAgBA,EAAK,MAAM,CAAC,EAAE,YAAA;AAGvD,QAAMS,IAAQ,YAAY;AACxB,QAAI,CAACC;AACH,aAAO,QAAQ,QAAA;AAEjB,UAAM,EAAE,SAAAC,GAAS,SAAAC,MAAY,QAAQ,cAAA;AAarC,WAXkBF,EAAI;AAAA,MACpB;AAAA,QACE,EAAE,SAAS,KAAK,QAAQA,EAAI,eAAe,KAAA;AAAA,QAC3C,EAAE,SAAS,KAAK,QAAQ,OAAO,QAAQ,MAAA;AAAA,MAAM;AAAA,MAE/C;AAAA,QACE,UAAU;AAAA,QACV,QAAQ;AAAA,MAAA;AAAA,IACV,EAGQ,iBAAiB,UAAU,MAAM;AACzC,MAAAA,EAAI,OAAA,GACJE,EAAA;AAAA,IACF,CAAC,GAEMD;AAAA,EACT,GAEMD,IACJG,gBAAAA,EAAC,OAAA,EAAI,WAAW,gCAAgCb,KAAQ,SAAS,IAAIc,EAAO,IAAI,IAAK,GAAGP,GACrF,UAAA;AAAA,IAAAC,KACC,gBAAAO,EAAC,SAAI,WAAW,kBAAkBD,EAAO,KAAK,IAAK,GAAGV,GACnD,UAAAI,EAAA,CACH;AAAA,IAEF,gBAAAO,EAAC,OAAA,EAAI,WAAW,oBAAoBD,EAAO,OAAO,IAAK,GAAGT,GACvD,UAAAC,KAAYJ,EAAA,CACf;AAAA,IACCC,KACC,gBAAAY,EAAC,KAAA,EAAE,SAASN,GAAO,WAAW,kBAAkBK,EAAO,KAAK,IAAI,UAAA,IAAA,CAEhE;AAAA,EAAA,GAEJ;AAEF,SAAAJ,EAAI,QAAQD,GACLC;AACT;"}
@@ -0,0 +1,201 @@
1
+ import { j as A } from "./index-CvhkVj_L.js";
2
+ import { B as q, m as B, I as T, S as g } from "./index-DqfQ7hp6.js";
3
+ import { R } from "./Preferences-Bg3J5Ur9.js";
4
+ import { I as j } from "./IconQuickEdit-YVn1ANbm.js";
5
+ var W = Object.create, v = Object.defineProperty, M = Object.getOwnPropertyDescriptor, I = (i, e) => (e = Symbol[i]) ? e : Symbol.for("Symbol." + i), P = (i) => {
6
+ throw TypeError(i);
7
+ }, U = (i, e, t) => e in i ? v(i, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : i[e] = t, K = (i, e) => v(i, "name", { value: e, configurable: !0 }), C = (i) => [, , , W(i?.[I("metadata")] ?? null)], H = ["class", "method", "getter", "setter", "accessor", "field", "value", "get", "set"], y = (i) => i !== void 0 && typeof i != "function" ? P("Function expected") : i, N = (i, e, t, n, s) => ({ kind: H[i], name: e, metadata: n, addInitializer: (l) => t._ ? P("Already initialized") : s.push(y(l || null)) }), O = (i, e) => U(e, I("metadata"), i[3]), F = (i, e, t, n) => {
8
+ for (var s = 0, l = i[e >> 1], r = l && l.length; s < r; s++) l[s].call(t);
9
+ return n;
10
+ }, Q = (i, e, t, n, s, l) => {
11
+ var r, a, o, d = e & 7, c = !1, f = 0, p = i[f] || (i[f] = []), k = d && (s = s.prototype, d < 5 && (d > 3 || !c) && M(s, t));
12
+ K(s, t);
13
+ for (var h = n.length - 1; h >= 0; h--)
14
+ o = N(d, t, a = {}, i[3], p), r = (0, n[h])(s, o), a._ = 1, y(r) && (s = r);
15
+ return O(i, s), k && v(s, t, k), c ? d ^ 4 ? l : k : s;
16
+ }, x, w, L;
17
+ x = [T(["sitemeta", "wikiTitle", "preferences"]), R(
18
+ g.object({
19
+ "inArticleLinks.enable": g.boolean().description("Whether to enable in-article links").default(!0),
20
+ "inArticleLinks.quickDiff.enable": g.boolean().description("Whether to enable in-article links for quick diff").default(!0),
21
+ "inArticleLinks.quickEdit.enable": g.boolean().description("Whether to enable in-article links for quick edit").default(!0),
22
+ "inArticleLinks.quickEdit.redlinks": g.boolean().description("Whether to show quick edit button for redlinks").default(!0)
23
+ }).description("In-article links preferences").extra("category", "in-article-links")
24
+ )];
25
+ let _ = class E extends (L = q) {
26
+ constructor(e) {
27
+ super(
28
+ e,
29
+ {
30
+ wikiBaseUrl: e.sitemeta.baseUrl,
31
+ wikiArticlePath: e.sitemeta.articlePath.replace("$1", ""),
32
+ wikiArticleBaseUrl: e.sitemeta.articleBaseUrl.replace("$1", ""),
33
+ wikiScriptBaseUrl: e.sitemeta.scriptBaseUrl,
34
+ linkClassName: "ipe__in-article-link"
35
+ },
36
+ "InArticleLinks"
37
+ ), this._cachedAnchorInfo = /* @__PURE__ */ new WeakMap(), this.ctx.set("inArticleLinks", this), this.ctx.preferences.defineCategory({
38
+ label: "In Article Links",
39
+ name: "in-article-links",
40
+ description: "In-article links preferences",
41
+ index: 9
42
+ });
43
+ }
44
+ async start() {
45
+ await this.ctx.preferences.get("inArticleLinks.quickEdit.enable") && this.handleQuickEdit(), await this.ctx.preferences.get("inArticleLinks.quickDiff.enable") && this.handleQuickDiff();
46
+ }
47
+ async stop() {
48
+ }
49
+ isWikiLink(e) {
50
+ return e.startsWith(this.config.wikiArticleBaseUrl) || e.startsWith(this.config.wikiScriptBaseUrl + "/index.php");
51
+ }
52
+ static {
53
+ this.REG_SKIPPED_HREF = /^(#|javascript:|vbscript:|file:)/i;
54
+ }
55
+ validateHrefAttr(e) {
56
+ return typeof e != "string" ? !1 : !E.REG_SKIPPED_HREF.test(e);
57
+ }
58
+ parseAnchor(e) {
59
+ if (!(e instanceof HTMLAnchorElement))
60
+ return null;
61
+ const t = this._cachedAnchorInfo.get(e);
62
+ if (t)
63
+ return t;
64
+ const n = e.getAttribute("href") || "";
65
+ if (!this.validateHrefAttr(n))
66
+ return null;
67
+ const s = e.href || "", l = this.parseLink(s);
68
+ if (!l)
69
+ return null;
70
+ const r = {
71
+ $el: e,
72
+ kind: e.closest('[typeof^="mw:File"]') ? "mw:File" : "normal",
73
+ external: e.classList.contains("external") || !!n.startsWith("http"),
74
+ redlink: e.classList.contains("new") || l.params.has("redlink"),
75
+ ...l
76
+ };
77
+ return this._cachedAnchorInfo.set(e, r), r;
78
+ }
79
+ parseLink(e) {
80
+ if (!e || typeof e == "string" && !this.validateHrefAttr(e))
81
+ return null;
82
+ const t = B(e);
83
+ if (!this.isWikiLink(t.toString()))
84
+ return null;
85
+ const n = t.searchParams, s = t.hash.replace("#", ""), l = n.get("action") || "view", r = t.pathname.endsWith(".php") ? n.get("title") : (() => {
86
+ try {
87
+ return decodeURI(t.pathname.substring(this.config.wikiArticlePath.length));
88
+ } catch (a) {
89
+ return this.logger.error("parseLink", t, a), null;
90
+ }
91
+ })();
92
+ return r ? {
93
+ url: t,
94
+ params: n,
95
+ hash: s,
96
+ action: l,
97
+ title: this.ctx.wikiTitle.create(r)
98
+ } : null;
99
+ }
100
+ scanAnchors(e) {
101
+ const t = e.querySelectorAll("a[href]");
102
+ return Array.from(t).map((n) => this.parseAnchor(n)).filter((n) => n !== null);
103
+ }
104
+ async handleQuickEdit() {
105
+ let e = !1;
106
+ const t = await this.ctx.preferences.get(
107
+ "inArticleLinks.quickEdit.redlinks"
108
+ );
109
+ this.ctx.inject(["quickEdit"], (n) => {
110
+ e = !0, n.on("dispose", () => {
111
+ e = !1;
112
+ }), window?.mw?.hook?.("wikipage.content").add((s) => {
113
+ if (!e)
114
+ return;
115
+ this.scanAnchors(s.get(0)).filter(({ action: r, title: a, redlink: o }) => (["edit", "create"].includes(r) || a.isSpecial("edit")) && // 添加对showButtonOnRedlinks的判断
116
+ (t || !o)).forEach(({ $el: r, title: a, params: o }) => {
117
+ if (r.dataset.ipeEditMounted)
118
+ return;
119
+ if (r.dataset.ipeEditMounted = "1", o.has("preload") || o.has("redo"))
120
+ return this.ctx.logger.debug(r, "Not compatible with quick edit");
121
+ let c;
122
+ if (a.getNamespaceId() === -1) {
123
+ const u = a.getMainDBKey().split("/").slice(1).join("/") || "";
124
+ if (a.isSpecial("edit"))
125
+ c = u;
126
+ else if (a.isSpecial("talkpage")) {
127
+ const m = a.newTitle(u).getTalkPage();
128
+ if (!m)
129
+ return this.ctx.logger.debug(r, "Talk page not found.");
130
+ c = m.getPrefixedDBKey();
131
+ } else if (a.isSpecial("mypage"))
132
+ c = a.newTitle(this.ctx.sitemeta.userInfo.name, 2).getPrefixedDBKey() + (u ? `/${u}` : "");
133
+ else if (a.isSpecial("mytalk"))
134
+ c = a.newTitle(this.ctx.sitemeta.userInfo.name, 3).getPrefixedDBKey() + (u ? `/${u}` : "");
135
+ else
136
+ return this.ctx.logger.debug(r, "Special page cannot be edited");
137
+ } else
138
+ c = a.getPrefixedDBKey();
139
+ const f = o.get("section")?.replace(/^T-/, "") || void 0, p = o.get("oldid"), k = o.has("redlink");
140
+ let h;
141
+ f === "new" ? h = "new" : f && /^\d+$/.test(f) && (h = parseInt(f, 10));
142
+ const S = p ? parseInt(p, 10) : void 0, b = {
143
+ title: c,
144
+ section: h,
145
+ revision: S,
146
+ createOnly: k
147
+ }, D = /* @__PURE__ */ A(
148
+ "a",
149
+ {
150
+ href: "#ipe://quick-edit/",
151
+ dataset: b,
152
+ className: `${this.config.linkClassName} ipe-quick-edit ${k ? "ipe-quick-edit--create-only" : ""}`,
153
+ style: {
154
+ userSelect: "none",
155
+ marginLeft: "0.2em",
156
+ verticalAlign: "middle"
157
+ },
158
+ onClick: (u) => {
159
+ u.preventDefault(), n.quickEdit.showModal(b);
160
+ },
161
+ children: /* @__PURE__ */ A(j, { style: "width: 1em; height: 1em" })
162
+ }
163
+ );
164
+ r.insertAdjacentElement("afterend", D);
165
+ });
166
+ });
167
+ });
168
+ }
169
+ handleQuickDiff() {
170
+ let e = !1;
171
+ const t = (n) => ["prev", "next", "cur"].includes(n);
172
+ this.ctx.inject(["quickDiff"], (n) => {
173
+ e = !0, n.on("dispose", () => {
174
+ e = !1;
175
+ }), window?.mw?.hook?.("wikipage.content").add((s) => {
176
+ if (!e)
177
+ return;
178
+ this.scanAnchors(s.get(0)).filter(({ params: r, title: a }) => r.has("diff") || a.isSpecial("diff")).forEach(({ $el: r, title: a, params: o }) => {
179
+ if (r.dataset.ipeDiffMounted)
180
+ return;
181
+ r.dataset.ipeDiffMounted = "1";
182
+ let d, c;
183
+ if (a.getNamespaceId() === -1 ? [, d, c] = a.getMainDBKey().split("/") : (d = o.get("diff"), c = o.get("oldid")), !d || !c)
184
+ return;
185
+ const f = {};
186
+ t(d) ? (f.fromrev = parseInt(c), f.torelative = d) : (f.fromrev = parseInt(c), f.torev = parseInt(d)), r.addEventListener("click", (p) => {
187
+ p.preventDefault(), n.quickDiff.comparePages(f);
188
+ });
189
+ });
190
+ });
191
+ });
192
+ }
193
+ };
194
+ w = C(L);
195
+ _ = Q(w, 0, "PluginInArticleLinks", x, _);
196
+ F(w, 1, _);
197
+ let V = _;
198
+ export {
199
+ V as PluginInArticleLinks
200
+ };
201
+ //# sourceMappingURL=index-sfkutNHj.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-sfkutNHj.js","sources":["../src/plugins/in-article-links/index.tsx"],"sourcesContent":["import { Inject, InPageEdit, Schema } from '@/InPageEdit'\nimport { IWikiTitle } from '@/models/WikiTitle/index.js'\nimport { CompareApiRequestOptions } from '../quick-diff/PluginQuickDiffCore.js'\nimport { QuickEditOptions } from '../quick-edit/index.js'\n\ndeclare module '@/InPageEdit' {\n interface InPageEdit {\n inArticleLinks: PluginInArticleLinks\n }\n}\n\nexport interface InArticleWikiLinkInfo {\n title: IWikiTitle\n url: URL\n params: URLSearchParams\n hash: string\n action: 'view' | 'edit' | 'create' | 'diff' | string\n}\n\nexport interface InArticleWikiAnchorInfo extends InArticleWikiLinkInfo {\n $el: HTMLAnchorElement\n kind: 'normal' | 'mw:File'\n external: boolean\n redlink: boolean\n}\n\n@Inject(['sitemeta', 'wikiTitle', 'preferences'])\n@RegisterPreferences(\n Schema.object({\n 'inArticleLinks.enable': Schema.boolean()\n .description('Whether to enable in-article links')\n .default(true),\n 'inArticleLinks.quickDiff.enable': Schema.boolean()\n .description('Whether to enable in-article links for quick diff')\n .default(true),\n 'inArticleLinks.quickEdit.enable': Schema.boolean()\n .description('Whether to enable in-article links for quick edit')\n .default(true),\n 'inArticleLinks.quickEdit.redlinks': Schema.boolean()\n .description('Whether to show quick edit button for redlinks')\n .default(true),\n })\n .description('In-article links preferences')\n .extra('category', 'in-article-links')\n)\nexport class PluginInArticleLinks extends BasePlugin<{\n /**\n * @example \"https://example.com\"\n */\n wikiBaseUrl: string\n /**\n * Article path, with trailing slash\n * @example \"/wiki/\" (if wgArticlePath is \"/wiki/$1\")\n */\n wikiArticlePath: string\n /**\n * Article base URL, with trailing slash\n * @example \"https://example.com/wiki/\" (if wgArticlePath is \"/wiki/$1\")\n */\n wikiArticleBaseUrl: string\n /**\n * Script base URL, **without** trailing slash\n * @example \"https://example.com/w\" (if wgScriptPath is \"/w\")\n */\n wikiScriptBaseUrl: string\n linkClassName: string\n}> {\n constructor(ctx: InPageEdit) {\n super(\n ctx,\n {\n wikiBaseUrl: ctx.sitemeta.baseUrl,\n wikiArticlePath: ctx.sitemeta.articlePath.replace('$1', ''),\n wikiArticleBaseUrl: ctx.sitemeta.articleBaseUrl.replace('$1', ''),\n wikiScriptBaseUrl: ctx.sitemeta.scriptBaseUrl,\n linkClassName: 'ipe__in-article-link',\n },\n 'InArticleLinks'\n )\n this.ctx.set('inArticleLinks', this)\n\n this.ctx.preferences.defineCategory({\n label: 'In Article Links',\n name: 'in-article-links',\n description: 'In-article links preferences',\n index: 9,\n })\n }\n\n protected async start() {\n // TODO: 这些都不应该硬编码,暂时先这样\n if (await this.ctx.preferences.get<boolean>('inArticleLinks.quickEdit.enable')) {\n this.handleQuickEdit()\n }\n if (await this.ctx.preferences.get<boolean>('inArticleLinks.quickDiff.enable')) {\n this.handleQuickDiff()\n }\n }\n\n protected async stop() {}\n\n isWikiLink(url: string): boolean {\n return (\n url.startsWith(this.config.wikiArticleBaseUrl) ||\n url.startsWith(this.config.wikiScriptBaseUrl + '/index.php')\n )\n }\n\n static readonly REG_SKIPPED_HREF = /^(#|javascript:|vbscript:|file:)/i\n private validateHrefAttr(href: string | null): boolean {\n if (typeof href !== 'string') {\n return false\n }\n return !PluginInArticleLinks.REG_SKIPPED_HREF.test(href)\n }\n\n private _cachedAnchorInfo = new WeakMap<HTMLAnchorElement, InArticleWikiAnchorInfo>()\n parseAnchor(anchor: HTMLAnchorElement): InArticleWikiAnchorInfo | null {\n // 不是链接元素\n if (!(anchor instanceof HTMLAnchorElement)) {\n return null\n }\n\n const cached = this._cachedAnchorInfo.get(anchor)\n if (cached) {\n return cached\n }\n\n const attrHref = anchor.getAttribute('href') || ''\n if (!this.validateHrefAttr(attrHref)) {\n return null\n }\n const href = anchor.href || ''\n const linkInfo = this.parseLink(href)\n if (!linkInfo) {\n return null\n }\n\n const info: InArticleWikiAnchorInfo = {\n $el: anchor,\n kind: anchor.closest('[typeof^=\"mw:File\"]') ? 'mw:File' : 'normal',\n external: anchor.classList.contains('external') || !!attrHref.startsWith('http'),\n redlink: anchor.classList.contains('new') || linkInfo.params.has('redlink'),\n ...linkInfo,\n }\n this._cachedAnchorInfo.set(anchor, info)\n return info\n }\n\n parseLink(link: string | URL): InArticleWikiLinkInfo | null {\n if (!link) {\n return null\n }\n\n if (typeof link === 'string' && !this.validateHrefAttr(link)) {\n return null\n }\n\n const url = makeURL(link)\n if (!this.isWikiLink(url.toString())) {\n return null\n }\n\n const params = url.searchParams\n const hash = url.hash.replace('#', '')\n const action = params.get('action') || 'view'\n const titleText = url.pathname.endsWith('.php')\n ? params.get('title')\n : (() => {\n try {\n return decodeURI(url.pathname.substring(this.config.wikiArticlePath.length))\n } catch (e) {\n this.logger.error('parseLink', url, e)\n return null\n }\n })()\n\n if (!titleText) {\n return null\n }\n\n return {\n url,\n params,\n hash,\n action,\n title: this.ctx.wikiTitle.create(titleText),\n }\n }\n\n scanAnchors(parent: HTMLElement): InArticleWikiAnchorInfo[] {\n const anchors = parent.querySelectorAll<HTMLAnchorElement>('a[href]')\n return Array.from(anchors)\n .map((anchor) => this.parseAnchor(anchor))\n .filter((anchor) => anchor !== null)\n }\n\n async handleQuickEdit() {\n let enable = false\n const showButtonOnRedlinks = await this.ctx.preferences.get<boolean>(\n 'inArticleLinks.quickEdit.redlinks'\n )\n\n this.ctx.inject(['quickEdit'], (ctx) => {\n enable = true\n ctx.on('dispose', () => {\n enable = false\n })\n\n window?.mw?.hook?.('wikipage.content').add(($content) => {\n if (!enable) {\n return\n }\n const anchors = this.scanAnchors($content.get(0)!).filter(({ action, title, redlink }) => {\n return (\n (['edit', 'create'].includes(action) || title.isSpecial('edit')) &&\n // 添加对showButtonOnRedlinks的判断\n (showButtonOnRedlinks || !redlink)\n )\n })\n anchors.forEach(({ $el, title, params }) => {\n if ($el.dataset.ipeEditMounted) {\n return\n }\n $el.dataset.ipeEditMounted = '1'\n\n const notCompatible = params.has('preload') || params.has('redo')\n if (notCompatible) {\n return this.ctx.logger.debug($el, `Not compatible with quick edit`)\n }\n\n let titleText: string\n if (title.getNamespaceId() === -1) {\n const sub = title.getMainDBKey().split('/').slice(1).join('/') || ''\n if (title.isSpecial('edit')) {\n titleText = sub\n } else if (title.isSpecial('talkpage')) {\n const talkPage = title.newTitle(sub).getTalkPage()\n if (!talkPage) {\n return this.ctx.logger.debug($el, `Talk page not found.`)\n }\n titleText = talkPage.getPrefixedDBKey()\n } else if (title.isSpecial('mypage')) {\n const userPage = title.newTitle(this.ctx.sitemeta.userInfo.name, 2)\n titleText = userPage.getPrefixedDBKey() + (sub ? `/${sub}` : '')\n } else if (title.isSpecial('mytalk')) {\n const userTalkPage = title.newTitle(this.ctx.sitemeta.userInfo.name, 3)\n titleText = userTalkPage.getPrefixedDBKey() + (sub ? `/${sub}` : '')\n } else {\n return this.ctx.logger.debug($el, `Special page cannot be edited`)\n }\n } else {\n titleText = title.getPrefixedDBKey()\n }\n\n const sectionRaw = params.get('section')?.replace(/^T-/, '') || undefined\n const revisionRaw = params.get('oldid')\n const createOnly = params.has('redlink')\n\n let section: 'new' | number | undefined = undefined\n if (sectionRaw === 'new') {\n section = 'new'\n } else if (sectionRaw && /^\\d+$/.test(sectionRaw)) {\n section = parseInt(sectionRaw, 10)\n }\n\n const revision = revisionRaw ? parseInt(revisionRaw, 10) : undefined\n\n const payload: Partial<QuickEditOptions> = {\n title: titleText,\n section,\n revision,\n createOnly,\n }\n\n const link = (\n <a\n href={`#ipe://quick-edit/`}\n dataset={payload as any}\n className={`${this.config.linkClassName} ipe-quick-edit ${createOnly ? 'ipe-quick-edit--create-only' : ''}`}\n style={{\n userSelect: 'none',\n marginLeft: '0.2em',\n verticalAlign: 'middle',\n }}\n onClick={(e) => {\n e.preventDefault()\n ctx.quickEdit.showModal(payload)\n }}\n >\n <IconQuickEdit style=\"width: 1em; height: 1em\" />\n </a>\n )\n\n $el.insertAdjacentElement('afterend', link)\n })\n })\n })\n }\n\n handleQuickDiff() {\n let enable = false\n const isRelative = (str: string): str is 'prev' | 'next' | 'cur' =>\n ['prev', 'next', 'cur'].includes(str)\n\n this.ctx.inject(['quickDiff'], (ctx) => {\n enable = true\n ctx.on('dispose', () => {\n enable = false\n })\n\n window?.mw?.hook?.('wikipage.content').add(($content) => {\n if (!enable) {\n return\n }\n const anchors = this.scanAnchors($content.get(0)!).filter(({ params, title }) => {\n return params.has('diff') || title.isSpecial('diff')\n })\n anchors.forEach(({ $el, title, params }) => {\n if ($el.dataset.ipeDiffMounted) {\n return\n }\n $el.dataset.ipeDiffMounted = '1'\n\n let diff: string | null\n let oldid: string | null\n if (title.getNamespaceId() === -1) {\n // prettier-ignore\n ;[/** special page name */, diff, oldid] = title.getMainDBKey().split('/')\n } else {\n diff = params.get('diff')\n oldid = params.get('oldid')\n }\n if (!diff || !oldid) {\n return\n }\n\n const compare: Partial<CompareApiRequestOptions> = {}\n if (isRelative(diff)) {\n compare.fromrev = parseInt(oldid)\n compare.torelative = diff\n } else {\n compare.fromrev = parseInt(oldid)\n compare.torev = parseInt(diff)\n }\n\n $el.addEventListener('click', (e) => {\n e.preventDefault()\n ctx.quickDiff.comparePages(compare)\n })\n })\n })\n })\n }\n}\n"],"names":["_PluginInArticleLinks_decorators","_init","_a","Inject","RegisterPreferences","Schema","_PluginInArticleLinks","BasePlugin","ctx","url","href","anchor","cached","attrHref","linkInfo","info","link","makeURL","params","hash","action","titleText","e","parent","anchors","enable","showButtonOnRedlinks","$content","title","redlink","$el","sub","talkPage","sectionRaw","revisionRaw","createOnly","section","revision","payload","jsx","IconQuickEdit","isRelative","str","diff","oldid","compare","__decoratorStart","__decorateElement","__runInitializers","PluginInArticleLinks"],"mappings":";;;;;;;;;;;;;;;GAAAA,GAAAC,GAAAC;AA0BAF,IAAA,CAACG,EAAO,CAAC,YAAY,aAAa,aAAa,CAAC,GAC/CC;AAAA,EACCC,EAAO,OAAO;AAAA,IACZ,yBAAyBA,EAAO,QAAA,EAC7B,YAAY,oCAAoC,EAChD,QAAQ,EAAI;AAAA,IACf,mCAAmCA,EAAO,QAAA,EACvC,YAAY,mDAAmD,EAC/D,QAAQ,EAAI;AAAA,IACf,mCAAmCA,EAAO,QAAA,EACvC,YAAY,mDAAmD,EAC/D,QAAQ,EAAI;AAAA,IACf,qCAAqCA,EAAO,QAAA,EACzC,YAAY,gDAAgD,EAC5D,QAAQ,EAAI;AAAA,EAAA,CAChB,EACE,YAAY,8BAA8B,EAC1C,MAAM,YAAY,kBAAkB;AACzC,CAAA;AACO,IAAMC,IAAN,MAAMA,WAA6BJ,IAAAK,GAqBvC;AAAA,EACD,YAAYC,GAAiB;AAC3B;AAAA,MACEA;AAAA,MACA;AAAA,QACE,aAAaA,EAAI,SAAS;AAAA,QAC1B,iBAAiBA,EAAI,SAAS,YAAY,QAAQ,MAAM,EAAE;AAAA,QAC1D,oBAAoBA,EAAI,SAAS,eAAe,QAAQ,MAAM,EAAE;AAAA,QAChE,mBAAmBA,EAAI,SAAS;AAAA,QAChC,eAAe;AAAA,MAAA;AAAA,MAEjB;AAAA,IAAA,GAuCJ,KAAQ,wCAAwB,QAAA,GArC9B,KAAK,IAAI,IAAI,kBAAkB,IAAI,GAEnC,KAAK,IAAI,YAAY,eAAe;AAAA,MAClC,OAAO;AAAA,MACP,MAAM;AAAA,MACN,aAAa;AAAA,MACb,OAAO;AAAA,IAAA,CACR;AAAA,EACH;AAAA,EAEA,MAAgB,QAAQ;AAEtB,IAAI,MAAM,KAAK,IAAI,YAAY,IAAa,iCAAiC,KAC3E,KAAK,gBAAA,GAEH,MAAM,KAAK,IAAI,YAAY,IAAa,iCAAiC,KAC3E,KAAK,gBAAA;AAAA,EAET;AAAA,EAEA,MAAgB,OAAO;AAAA,EAAC;AAAA,EAExB,WAAWC,GAAsB;AAC/B,WACEA,EAAI,WAAW,KAAK,OAAO,kBAAkB,KAC7CA,EAAI,WAAW,KAAK,OAAO,oBAAoB,YAAY;AAAA,EAE/D;AAAA,EAEA,OAAA;AAAA,SAAgB,mBAAmB;AAAA,EAAA;AAAA,EAC3B,iBAAiBC,GAA8B;AACrD,WAAI,OAAOA,KAAS,WACX,KAEF,CAACJ,EAAqB,iBAAiB,KAAKI,CAAI;AAAA,EACzD;AAAA,EAGA,YAAYC,GAA2D;AAErE,QAAI,EAAEA,aAAkB;AACtB,aAAO;AAGT,UAAMC,IAAS,KAAK,kBAAkB,IAAID,CAAM;AAChD,QAAIC;AACF,aAAOA;AAGT,UAAMC,IAAWF,EAAO,aAAa,MAAM,KAAK;AAChD,QAAI,CAAC,KAAK,iBAAiBE,CAAQ;AACjC,aAAO;AAET,UAAMH,IAAOC,EAAO,QAAQ,IACtBG,IAAW,KAAK,UAAUJ,CAAI;AACpC,QAAI,CAACI;AACH,aAAO;AAGT,UAAMC,IAAgC;AAAA,MACpC,KAAKJ;AAAA,MACL,MAAMA,EAAO,QAAQ,qBAAqB,IAAI,YAAY;AAAA,MAC1D,UAAUA,EAAO,UAAU,SAAS,UAAU,KAAK,CAAC,CAACE,EAAS,WAAW,MAAM;AAAA,MAC/E,SAASF,EAAO,UAAU,SAAS,KAAK,KAAKG,EAAS,OAAO,IAAI,SAAS;AAAA,MAC1E,GAAGA;AAAA,IAAA;AAEL,gBAAK,kBAAkB,IAAIH,GAAQI,CAAI,GAChCA;AAAA,EACT;AAAA,EAEA,UAAUC,GAAkD;AAK1D,QAJI,CAACA,KAID,OAAOA,KAAS,YAAY,CAAC,KAAK,iBAAiBA,CAAI;AACzD,aAAO;AAGT,UAAMP,IAAMQ,EAAQD,CAAI;AACxB,QAAI,CAAC,KAAK,WAAWP,EAAI,SAAA,CAAU;AACjC,aAAO;AAGT,UAAMS,IAAST,EAAI,cACbU,IAAOV,EAAI,KAAK,QAAQ,KAAK,EAAE,GAC/BW,IAASF,EAAO,IAAI,QAAQ,KAAK,QACjCG,IAAYZ,EAAI,SAAS,SAAS,MAAM,IAC1CS,EAAO,IAAI,OAAO,KACjB,MAAM;AACL,UAAI;AACF,eAAO,UAAUT,EAAI,SAAS,UAAU,KAAK,OAAO,gBAAgB,MAAM,CAAC;AAAA,MAC7E,SAASa,GAAG;AACV,oBAAK,OAAO,MAAM,aAAab,GAAKa,CAAC,GAC9B;AAAA,MACT;AAAA,IACF,GAAA;AAEJ,WAAKD,IAIE;AAAA,MACL,KAAAZ;AAAA,MACA,QAAAS;AAAA,MACA,MAAAC;AAAA,MACA,QAAAC;AAAA,MACA,OAAO,KAAK,IAAI,UAAU,OAAOC,CAAS;AAAA,IAAA,IARnC;AAAA,EAUX;AAAA,EAEA,YAAYE,GAAgD;AAC1D,UAAMC,IAAUD,EAAO,iBAAoC,SAAS;AACpE,WAAO,MAAM,KAAKC,CAAO,EACtB,IAAI,CAACb,MAAW,KAAK,YAAYA,CAAM,CAAC,EACxC,OAAO,CAACA,MAAWA,MAAW,IAAI;AAAA,EACvC;AAAA,EAEA,MAAM,kBAAkB;AACtB,QAAIc,IAAS;AACb,UAAMC,IAAuB,MAAM,KAAK,IAAI,YAAY;AAAA,MACtD;AAAA,IAAA;AAGF,SAAK,IAAI,OAAO,CAAC,WAAW,GAAG,CAAClB,MAAQ;AACtC,MAAAiB,IAAS,IACTjB,EAAI,GAAG,WAAW,MAAM;AACtB,QAAAiB,IAAS;AAAA,MACX,CAAC,GAED,QAAQ,IAAI,OAAO,kBAAkB,EAAE,IAAI,CAACE,MAAa;AACvD,YAAI,CAACF;AACH;AASF,QAPgB,KAAK,YAAYE,EAAS,IAAI,CAAC,CAAE,EAAE,OAAO,CAAC,EAAE,QAAAP,GAAQ,OAAAQ,GAAO,SAAAC,SAEvE,CAAC,QAAQ,QAAQ,EAAE,SAAST,CAAM,KAAKQ,EAAM,UAAU,MAAM;AAAA,SAE7DF,KAAwB,CAACG,EAE7B,EACO,QAAQ,CAAC,EAAE,KAAAC,GAAK,OAAAF,GAAO,QAAAV,QAAa;AAC1C,cAAIY,EAAI,QAAQ;AACd;AAKF,cAHAA,EAAI,QAAQ,iBAAiB,KAEPZ,EAAO,IAAI,SAAS,KAAKA,EAAO,IAAI,MAAM;AAE9D,mBAAO,KAAK,IAAI,OAAO,MAAMY,GAAK,gCAAgC;AAGpE,cAAIT;AACJ,cAAIO,EAAM,eAAA,MAAqB,IAAI;AACjC,kBAAMG,IAAMH,EAAM,aAAA,EAAe,MAAM,GAAG,EAAE,MAAM,CAAC,EAAE,KAAK,GAAG,KAAK;AAClE,gBAAIA,EAAM,UAAU,MAAM;AACxB,cAAAP,IAAYU;AAAA,qBACHH,EAAM,UAAU,UAAU,GAAG;AACtC,oBAAMI,IAAWJ,EAAM,SAASG,CAAG,EAAE,YAAA;AACrC,kBAAI,CAACC;AACH,uBAAO,KAAK,IAAI,OAAO,MAAMF,GAAK,sBAAsB;AAE1D,cAAAT,IAAYW,EAAS,iBAAA;AAAA,YACvB,WAAWJ,EAAM,UAAU,QAAQ;AAEjC,cAAAP,IADiBO,EAAM,SAAS,KAAK,IAAI,SAAS,SAAS,MAAM,CAAC,EAC7C,sBAAsBG,IAAM,IAAIA,CAAG,KAAK;AAAA,qBACpDH,EAAM,UAAU,QAAQ;AAEjC,cAAAP,IADqBO,EAAM,SAAS,KAAK,IAAI,SAAS,SAAS,MAAM,CAAC,EAC7C,sBAAsBG,IAAM,IAAIA,CAAG,KAAK;AAAA;AAEjE,qBAAO,KAAK,IAAI,OAAO,MAAMD,GAAK,+BAA+B;AAAA,UAErE;AACE,YAAAT,IAAYO,EAAM,iBAAA;AAGpB,gBAAMK,IAAaf,EAAO,IAAI,SAAS,GAAG,QAAQ,OAAO,EAAE,KAAK,QAC1DgB,IAAchB,EAAO,IAAI,OAAO,GAChCiB,IAAajB,EAAO,IAAI,SAAS;AAEvC,cAAIkB;AACJ,UAAIH,MAAe,QACjBG,IAAU,QACDH,KAAc,QAAQ,KAAKA,CAAU,MAC9CG,IAAU,SAASH,GAAY,EAAE;AAGnC,gBAAMI,IAAWH,IAAc,SAASA,GAAa,EAAE,IAAI,QAErDI,IAAqC;AAAA,YACzC,OAAOjB;AAAA,YACP,SAAAe;AAAA,YACA,UAAAC;AAAA,YACA,YAAAF;AAAA,UAAA,GAGInB,IACJ,gBAAAuB;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,MAAM;AAAA,cACN,SAASD;AAAA,cACT,WAAW,GAAG,KAAK,OAAO,aAAa,mBAAmBH,IAAa,gCAAgC,EAAE;AAAA,cACzG,OAAO;AAAA,gBACL,YAAY;AAAA,gBACZ,YAAY;AAAA,gBACZ,eAAe;AAAA,cAAA;AAAA,cAEjB,SAAS,CAACb,MAAM;AACd,gBAAAA,EAAE,eAAA,GACFd,EAAI,UAAU,UAAU8B,CAAO;AAAA,cACjC;AAAA,cAEA,UAAA,gBAAAC,EAACC,GAAA,EAAc,OAAM,0BAAA,CAA0B;AAAA,YAAA;AAAA,UAAA;AAInD,UAAAV,EAAI,sBAAsB,YAAYd,CAAI;AAAA,QAC5C,CAAC;AAAA,MACH,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAAA,EAEA,kBAAkB;AAChB,QAAIS,IAAS;AACb,UAAMgB,IAAa,CAACC,MAClB,CAAC,QAAQ,QAAQ,KAAK,EAAE,SAASA,CAAG;AAEtC,SAAK,IAAI,OAAO,CAAC,WAAW,GAAG,CAAClC,MAAQ;AACtC,MAAAiB,IAAS,IACTjB,EAAI,GAAG,WAAW,MAAM;AACtB,QAAAiB,IAAS;AAAA,MACX,CAAC,GAED,QAAQ,IAAI,OAAO,kBAAkB,EAAE,IAAI,CAACE,MAAa;AACvD,YAAI,CAACF;AACH;AAKF,QAHgB,KAAK,YAAYE,EAAS,IAAI,CAAC,CAAE,EAAE,OAAO,CAAC,EAAE,QAAAT,GAAQ,OAAAU,QAC5DV,EAAO,IAAI,MAAM,KAAKU,EAAM,UAAU,MAAM,CACpD,EACO,QAAQ,CAAC,EAAE,KAAAE,GAAK,OAAAF,GAAO,QAAAV,QAAa;AAC1C,cAAIY,EAAI,QAAQ;AACd;AAEF,UAAAA,EAAI,QAAQ,iBAAiB;AAE7B,cAAIa,GACAC;AAQJ,cAPIhB,EAAM,eAAA,MAAqB,KAE5B,CAAA,EAA2Be,GAAMC,CAAK,IAAIhB,EAAM,aAAA,EAAe,MAAM,GAAG,KAEzEe,IAAOzB,EAAO,IAAI,MAAM,GACxB0B,IAAQ1B,EAAO,IAAI,OAAO,IAExB,CAACyB,KAAQ,CAACC;AACZ;AAGF,gBAAMC,IAA6C,CAAA;AACnD,UAAIJ,EAAWE,CAAI,KACjBE,EAAQ,UAAU,SAASD,CAAK,GAChCC,EAAQ,aAAaF,MAErBE,EAAQ,UAAU,SAASD,CAAK,GAChCC,EAAQ,QAAQ,SAASF,CAAI,IAG/Bb,EAAI,iBAAiB,SAAS,CAACR,MAAM;AACnC,YAAAA,EAAE,eAAA,GACFd,EAAI,UAAU,aAAaqC,CAAO;AAAA,UACpC,CAAC;AAAA,QACH,CAAC;AAAA,MACH,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AACF;AArTO5C,IAAA6C,EAAA5C,CAAA;AAAMI,IAANyC,gCAnBP/C,GAmBaM,CAAA;AAAN0C,EAAA/C,GAAA,GAAMK,CAAA;AAAN,IAAM2C,IAAN3C;"}
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { B as s, I as g, a as r, m as c, $ as o, S as t, b as L, c as i } from "./index-DNQjqBV-.js";
1
+ import { B as s, a as g, I as r, c, $ as o, S as t, b as L, d as i } from "./index-DqfQ7hp6.js";
2
2
  export {
3
3
  s as BasePlugin,
4
4
  g as InPageEdit,
@@ -0,0 +1,40 @@
1
+ const f = Symbol("@@apply"), u = Symbol("@@ctor");
2
+ function c(e, p) {
3
+ if (typeof e != "object" || e === null || Array.isArray(e))
4
+ throw new TypeError("instance is not an object");
5
+ const o = (...t) => {
6
+ const r = e[p];
7
+ if (typeof r != "function")
8
+ throw new TypeError(`Property "${String(p)}" is not a function`);
9
+ return r.apply(e, t);
10
+ };
11
+ o[f] = o, o[u] = e;
12
+ const l = e?.constructor?.name;
13
+ return l && (o[Symbol.toStringTag] = l), new Proxy(o, {
14
+ get(t, r, y) {
15
+ return r === "prototype" ? Reflect.get(o, r, y) : Reflect.get(e, r, e);
16
+ },
17
+ set(t, r, y) {
18
+ return Reflect.set(e, r, y);
19
+ },
20
+ has(t, r) {
21
+ return Reflect.has(e, r);
22
+ },
23
+ deleteProperty(t, r) {
24
+ return Reflect.deleteProperty(e, r);
25
+ },
26
+ ownKeys() {
27
+ return Reflect.ownKeys(e);
28
+ },
29
+ getOwnPropertyDescriptor(t, r) {
30
+ return Object.getOwnPropertyDescriptor(e, r);
31
+ },
32
+ defineProperty(t, r, y) {
33
+ return Object.defineProperty(e, r, y);
34
+ }
35
+ });
36
+ }
37
+ export {
38
+ c as m
39
+ };
40
+ //# sourceMappingURL=makeCallable-LDU0xZMJ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"makeCallable-LDU0xZMJ.js","sources":["../src/utils/makeCallable.ts"],"sourcesContent":["export const CALLABLE_APPLY_SYMBOL = Symbol('@@apply')\nexport const CALLABLE_CTOR_SYMBOL = Symbol('@@ctor')\nexport function makeCallable<C extends object, M extends keyof C>(\n instance: C,\n method: M\n): C &\n ((\n ...args: C[M] extends (...a: infer P) => any ? P : never\n ) => C[M] extends (...a: any[]) => infer R ? R : never) {\n if (typeof instance !== 'object' || instance === null || Array.isArray(instance)) {\n throw new TypeError('instance is not an object')\n }\n\n const apply: any = (...args: any[]) => {\n const fn = (instance as any)[method]\n if (typeof fn !== 'function') {\n throw new TypeError(`Property \"${String(method)}\" is not a function`)\n }\n return fn.apply(instance, args)\n }\n apply[CALLABLE_APPLY_SYMBOL] = apply\n apply[CALLABLE_CTOR_SYMBOL] = instance\n\n const ctorName = (instance as any)?.constructor?.name\n if (ctorName) (apply as any)[Symbol.toStringTag] = ctorName\n\n const proxy = new Proxy(apply, {\n get(_, p, receiver) {\n if (p === 'prototype') return Reflect.get(apply, p, receiver)\n return Reflect.get(instance as any, p, instance)\n },\n set(_, p, v) {\n return Reflect.set(instance as any, p, v)\n },\n has(_, p) {\n return Reflect.has(instance as any, p)\n },\n deleteProperty(_, p) {\n return Reflect.deleteProperty(instance as any, p)\n },\n ownKeys() {\n return Reflect.ownKeys(instance as any)\n },\n getOwnPropertyDescriptor(_, p) {\n return Object.getOwnPropertyDescriptor(instance as any, p)\n },\n defineProperty(_, p, desc) {\n return Object.defineProperty(instance as any, p, desc)\n },\n })\n\n return proxy as unknown as any\n}\n"],"names":["CALLABLE_APPLY_SYMBOL","CALLABLE_CTOR_SYMBOL","makeCallable","instance","method","apply","args","fn","ctorName","_","p","receiver","v","desc"],"mappings":"AAAO,MAAMA,IAAwB,OAAO,SAAS,GACxCC,IAAuB,OAAO,QAAQ;AAC5C,SAASC,EACdC,GACAC,GAIwD;AACxD,MAAI,OAAOD,KAAa,YAAYA,MAAa,QAAQ,MAAM,QAAQA,CAAQ;AAC7E,UAAM,IAAI,UAAU,2BAA2B;AAGjD,QAAME,IAAa,IAAIC,MAAgB;AACrC,UAAMC,IAAMJ,EAAiBC,CAAM;AACnC,QAAI,OAAOG,KAAO;AAChB,YAAM,IAAI,UAAU,aAAa,OAAOH,CAAM,CAAC,qBAAqB;AAEtE,WAAOG,EAAG,MAAMJ,GAAUG,CAAI;AAAA,EAChC;AACA,EAAAD,EAAML,CAAqB,IAAIK,GAC/BA,EAAMJ,CAAoB,IAAIE;AAE9B,QAAMK,IAAYL,GAAkB,aAAa;AACjD,SAAIK,MAAWH,EAAc,OAAO,WAAW,IAAIG,IAErC,IAAI,MAAMH,GAAO;AAAA,IAC7B,IAAII,GAAGC,GAAGC,GAAU;AAClB,aAAID,MAAM,cAAoB,QAAQ,IAAIL,GAAOK,GAAGC,CAAQ,IACrD,QAAQ,IAAIR,GAAiBO,GAAGP,CAAQ;AAAA,IACjD;AAAA,IACA,IAAIM,GAAGC,GAAGE,GAAG;AACX,aAAO,QAAQ,IAAIT,GAAiBO,GAAGE,CAAC;AAAA,IAC1C;AAAA,IACA,IAAIH,GAAGC,GAAG;AACR,aAAO,QAAQ,IAAIP,GAAiBO,CAAC;AAAA,IACvC;AAAA,IACA,eAAeD,GAAGC,GAAG;AACnB,aAAO,QAAQ,eAAeP,GAAiBO,CAAC;AAAA,IAClD;AAAA,IACA,UAAU;AACR,aAAO,QAAQ,QAAQP,CAAe;AAAA,IACxC;AAAA,IACA,yBAAyBM,GAAGC,GAAG;AAC7B,aAAO,OAAO,yBAAyBP,GAAiBO,CAAC;AAAA,IAC3D;AAAA,IACA,eAAeD,GAAGC,GAAGG,GAAM;AACzB,aAAO,OAAO,eAAeV,GAAiBO,GAAGG,CAAI;AAAA,IACvD;AAAA,EAAA,CACD;AAGH;"}
@@ -7,7 +7,7 @@ export declare class WikiPage {
7
7
  pageInfo: PageInfo;
8
8
  static readonly DEFAULT_PAGE_INFO: PageInfo;
9
9
  constructor(pageInfo: Partial<PageInfo>, api?: MediaWikiApi);
10
- getPageInfo(payload: MwApiParams): Promise<PageInfo>;
10
+ fetchPageInfo(payload: MwApiParams): Promise<PageInfo>;
11
11
  parse(params?: MwApiParams): Promise<import('fexios').FexiosFinalContext<import('wiki-saikou').MwApiResponse<{
12
12
  parse: PageParseData;
13
13
  }>>>;
@@ -34,7 +34,7 @@ export declare class WikiPage {
34
34
  }>): Promise<import('fexios').FexiosFinalContext<any>>;
35
35
  userCan(action: keyof PageInfo['actions']): boolean;
36
36
  userCanEdit(): boolean;
37
- refetch(): Promise<this>;
37
+ reloadSelfInfo(): Promise<this>;
38
38
  get pageid(): number;
39
39
  get title(): string;
40
40
  get ns(): number;
@@ -1,12 +1,88 @@
1
- export declare class WikiTitle {
2
- readonly namespaceMap: {
3
- id: number;
4
- canonical: string;
5
- aliases: string[];
6
- };
7
- constructor(title: string, ns: string | number, namespaceMap: {
8
- id: number;
9
- canonical: string;
10
- aliases: string[];
11
- });
1
+ import { SiteMetadata } from '../../types/SiteMetadata';
2
+ export interface IWikiTitle {
3
+ /**
4
+ * Get db key without namespace prefix
5
+ * e.g. "template:hello world" -> "Hello_world"
6
+ */
7
+ getMainDBKey(): string;
8
+ /**
9
+ * Get page name without namespace prefix
10
+ * e.g. "template:hello world" -> "Hello world"
11
+ */
12
+ getMainText(): string;
13
+ /**
14
+ * Get db key with namespace prefix
15
+ * e.g. "template:hello world" -> "Template:Hello_world"
16
+ */
17
+ getPrefixedDBKey(): string;
18
+ /**
19
+ * Get page name with namespace prefix
20
+ * e.g. "template:hello world" -> "Template:Hello world"
21
+ */
22
+ getPrefixedText(): string;
23
+ toText: () => string;
24
+ toString: () => string;
25
+ /**
26
+ * Get namespace ID
27
+ * e.g. "template:hello world" -> 10
28
+ */
29
+ getNamespaceId(): number;
30
+ /**
31
+ * Get namespace text
32
+ * e.g. "template:hello world" -> "Template"
33
+ */
34
+ getNamespaceText(): string;
35
+ /**
36
+ * Get namespace db key
37
+ * e.g. "template talk:hello world" -> "Template_talk"
38
+ */
39
+ getNamespaceDBKey(): string;
40
+ /**
41
+ * Get subject page
42
+ * If current page is subject page, return itself
43
+ * e.g. "template talk:hello world" -> new WikiTitle("Template:Hello world")
44
+ */
45
+ getSubjectPage(): IWikiTitle;
46
+ /**
47
+ * Get talk page
48
+ * If current page is talk page, return itself
49
+ * If current page cannot have talk page, return null
50
+ * e.g. "template:hello world" -> new WikiTitle("Template talk:Hello world")
51
+ */
52
+ getTalkPage(): IWikiTitle | null;
53
+ /**
54
+ * Get URL of the page
55
+ * e.g. "template:hello world" -> "https://example.com/wiki/Template:Hello_world"
56
+ */
57
+ getURL(params?: Record<string, string> | URLSearchParams): URL;
58
+ /**
59
+ * Reset current title with given title string
60
+ */
61
+ setTitle(title: string): IWikiTitle;
62
+ /**
63
+ * Set main title, keep current ns, update dbkey
64
+ */
65
+ setMainText(mainTitle: string): IWikiTitle;
66
+ /**
67
+ * Set namespace by text
68
+ */
69
+ setNamespaceText(namespaceText: string): IWikiTitle;
70
+ /**
71
+ * Set namespace by ID
72
+ */
73
+ setNamespaceId(namespaceId: number): IWikiTitle;
74
+ /**
75
+ * Check if the title is equal to another title
76
+ */
77
+ equals(other: IWikiTitle | string): boolean;
78
+ /**
79
+ * Check if the title is specific special page
80
+ * e.g. "Special:Diff" is "差异" or "diff" -> true
81
+ */
82
+ isSpecial(alia: string): boolean;
83
+ newTitle(title: string, namespace?: number): IWikiTitle;
12
84
  }
85
+ export interface WikiTitleConstructor {
86
+ new (title: string, namespace?: number): IWikiTitle;
87
+ }
88
+ export declare function createWikiTitleModel(metadata: SiteMetadata): WikiTitleConstructor;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,6 @@
1
+ const o = () => {
2
+ };
3
+ export {
4
+ o as n
5
+ };
6
+ //# sourceMappingURL=noop-ClDc6zv4.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"noop-ClDc6zv4.js","sources":["../src/utils/noop.ts"],"sourcesContent":["export const noop = () => {}\n"],"names":["noop"],"mappings":"AAAO,MAAMA,IAAO,MAAM;AAAC;"}
@@ -1,29 +1,55 @@
1
1
  import { InPageEdit } from '../../InPageEdit';
2
+ import { IWikiTitle } from '../../models/WikiTitle/index.js';
2
3
  declare module '../../InPageEdit' {
3
4
  interface InPageEdit {
4
5
  inArticleLinks: PluginInArticleLinks;
5
6
  }
6
7
  }
7
- export interface InArticleWikiLinkStat {
8
- $el: HTMLAnchorElement;
8
+ export interface InArticleWikiLinkInfo {
9
+ title: IWikiTitle;
9
10
  url: URL;
10
- query: URLSearchParams;
11
+ params: URLSearchParams;
11
12
  hash: string;
13
+ action: 'view' | 'edit' | 'create' | 'diff' | string;
14
+ }
15
+ export interface InArticleWikiAnchorInfo extends InArticleWikiLinkInfo {
16
+ $el: HTMLAnchorElement;
12
17
  kind: 'normal' | 'mw:File';
13
- /** MediaWiki page title */
14
- title: string;
15
18
  external: boolean;
16
- action: 'view' | 'edit' | 'create' | 'diff' | string;
19
+ redlink: boolean;
17
20
  }
18
21
  export declare class PluginInArticleLinks extends BasePlugin<{
22
+ /**
23
+ * @example "https://example.com"
24
+ */
19
25
  wikiBaseUrl: string;
26
+ /**
27
+ * Article path, with trailing slash
28
+ * @example "/wiki/" (if wgArticlePath is "/wiki/$1")
29
+ */
20
30
  wikiArticlePath: string;
31
+ /**
32
+ * Article base URL, with trailing slash
33
+ * @example "https://example.com/wiki/" (if wgArticlePath is "/wiki/$1")
34
+ */
21
35
  wikiArticleBaseUrl: string;
36
+ /**
37
+ * Script base URL, **without** trailing slash
38
+ * @example "https://example.com/w" (if wgScriptPath is "/w")
39
+ */
22
40
  wikiScriptBaseUrl: string;
23
41
  linkClassName: string;
24
42
  }> {
25
43
  constructor(ctx: InPageEdit);
26
44
  protected start(): Promise<void>;
27
45
  protected stop(): Promise<void>;
28
- parseInArticleLinkInfo(anchor: HTMLAnchorElement): InArticleWikiLinkStat | null;
46
+ isWikiLink(url: string): boolean;
47
+ static readonly REG_SKIPPED_HREF: RegExp;
48
+ private validateHrefAttr;
49
+ private _cachedAnchorInfo;
50
+ parseAnchor(anchor: HTMLAnchorElement): InArticleWikiAnchorInfo | null;
51
+ parseLink(link: string | URL): InArticleWikiLinkInfo | null;
52
+ scanAnchors(parent: HTMLElement): InArticleWikiAnchorInfo[];
53
+ handleQuickEdit(): Promise<void>;
54
+ handleQuickDiff(): void;
29
55
  }
@@ -0,0 +1,47 @@
1
+ import { InPageEdit } from '../../InPageEdit';
2
+ import { WikiPage } from '../../models/WikiPage';
3
+ import { IPEModal } from '../../services/ModalService/IPEModal';
4
+ import { ReactNode } from 'jsx-dom';
5
+ declare module '../../InPageEdit' {
6
+ interface InPageEdit {
7
+ quickDelete: PluginQuickDelete & {
8
+ (...args: Parameters<PluginQuickDelete['showModal']>): ReturnType<PluginQuickDelete['showModal']>;
9
+ };
10
+ }
11
+ interface Events {
12
+ 'quick-delete/init-options'(payload: Omit<QuickDeleteInitPayload, 'modal' | 'wikiPage'>): void;
13
+ 'quick-delete/show-modal'(payload: Omit<QuickDeleteInitPayload, 'wikiPage'>): void;
14
+ 'quick-delete/wiki-page'(payload: QuickDeleteInitPayload): void;
15
+ 'quick-delete/delete-notice'(payload: QuickDeleteInitPayload & {
16
+ deleteNotices: ReactNode[];
17
+ }): void;
18
+ }
19
+ }
20
+ export interface QuickDeleteOptions {
21
+ title: string;
22
+ pageId: number;
23
+ revision: number;
24
+ deleteReason: string;
25
+ reloadAfterDelete: boolean;
26
+ }
27
+ export interface QuickDeleteInitPayload {
28
+ ctx: InPageEdit;
29
+ options: QuickDeleteOptions;
30
+ modal: IPEModal;
31
+ wikiPage: WikiPage;
32
+ }
33
+ export interface QuickDeleteSubmitPayload {
34
+ wikiPage: WikiPage;
35
+ reason?: string;
36
+ }
37
+ export declare class PluginQuickDelete extends BasePlugin {
38
+ ctx: InPageEdit;
39
+ private readonly DEFAULT_OPTIONS;
40
+ constructor(ctx: InPageEdit);
41
+ protected start(): Promise<void> | void;
42
+ showModal(payload?: string | Partial<QuickDeleteOptions>): Promise<void>;
43
+ handleSubmit(payload: QuickDeleteSubmitPayload): Promise<import('fexios').FexiosFinalContext<any>>;
44
+ getWikiPageFromPayload(payload: Partial<QuickDeleteOptions>): Promise<WikiPage>;
45
+ private injectToolbox;
46
+ protected removeToolbox(ctx: InPageEdit): void;
47
+ }
@@ -1,6 +1,6 @@
1
1
  import { InPageEdit } from '../../InPageEdit';
2
2
  import { JsDiffDiffType } from './JsDiffService';
3
- import { IPEModal } from '../../services/ModalService/IPEModal.js';
3
+ import { IPEModal, IPEModalOptions } from '../../services/ModalService/IPEModal.js';
4
4
  declare module '../../InPageEdit' {
5
5
  interface InPageEdit {
6
6
  quickDiff: PluginQuickDiffCore;
@@ -48,6 +48,8 @@ export interface CompareApiResponse {
48
48
  tocomment: string;
49
49
  toparsedcomment: string;
50
50
  diffsize: number;
51
+ prev: number;
52
+ next: number;
51
53
  }> & {
52
54
  body: string;
53
55
  };
@@ -66,5 +68,5 @@ export declare class PluginQuickDiffCore extends BasePlugin {
66
68
  */
67
69
  renderJsDiff(oldStr: string, newStr: string, diffType?: JsDiffDiffType): DocumentFragment;
68
70
  readonly COMPARE_API_DEFAULT_OPTIONS: Partial<CompareApiRequestOptions>;
69
- comparePages(options: Partial<CompareApiRequestOptions>, modal?: IPEModal): IPEModal;
71
+ comparePages(options: Partial<CompareApiRequestOptions>, modal?: IPEModal, modalOptions?: Partial<IPEModalOptions>): IPEModal;
70
72
  }
@@ -1,6 +1,23 @@
1
1
  import { JSX } from 'jsx-dom/jsx-runtime';
2
2
  import { CompareApiResponse } from '../PluginQuickDiffCore';
3
+ import { InPageEdit } from '../../../InPageEdit';
3
4
  export type DiffTableProps = {
4
5
  data: Partial<CompareApiResponse['compare']>;
6
+ ctx: InPageEdit;
5
7
  } & JSX.IntrinsicElements['table'];
8
+ export declare enum DiffTableEvent {
9
+ update = "ipe:diff-table/update",
10
+ edit = "ipe:diff-table/edit"
11
+ }
12
+ declare global {
13
+ interface HTMLElementEventMap {
14
+ [DiffTableEvent.update]: CustomEvent<{
15
+ fromrev: number;
16
+ torev: number;
17
+ }>;
18
+ [DiffTableEvent.edit]: CustomEvent<{
19
+ revid: number;
20
+ }>;
21
+ }
22
+ }
6
23
  export declare const DiffTable: (props: DiffTableProps) => import('jsx-dom').ReactElement;