diff --git a/src/gadgets/MarkAsResolved-restricted/MediaWiki:Gadget-MarkAsResolved-restricted.js b/src/gadgets/MarkAsResolved-restricted/MediaWiki:Gadget-MarkAsResolved-restricted.js new file mode 100644 index 00000000..38dcd563 --- /dev/null +++ b/src/gadgets/MarkAsResolved-restricted/MediaWiki:Gadget-MarkAsResolved-restricted.js @@ -0,0 +1,258 @@ +//
+"use strict";
+$(() => {
+    const wgUserGroups = mw.config.get("wgUserGroups");
+    if (!/^萌娘百科_talk:讨论版\/[^存]+$/.test(mw.config.get("wgPageName"))) { return; }
+    if (!wgUserGroups.includes("goodeditor") && !wgUserGroups.includes("honoredmaintainer")) { return; }
+    if (mw.config.get("wgCurRevisionId") !== mw.config.get("wgRevisionId")) { return; }
+    const $body = $("body");
+    $("#mw-notification-area").appendTo($body);
+    const api = new mw.Api();
+
+    /**
+     * @type { { [key: string]: { status: string | undefined, archiveOffset: number, precomment: string, comment: string } } }
+     */
+    const caches = {};
+
+    class MARWindow extends OO.ui.ProcessDialog {
+        static static = {
+            ...super.static,
+            tagName: "div",
+            name: "AnnTools_MarkAsResolved",
+            title: wgULS("公共讨论页段落状态标记工具", "公共討論頁段落狀態標記工具"),
+            actions: [
+                {
+                    action: "cancel",
+                    label: "取消",
+                    flags: ["safe", "close", "destructive"],
+                },
+                {
+                    action: "submit",
+                    label: wgULS("确认", "確認"),
+                    flags: ["primary", "progressive"],
+                },
+            ],
+        };
+
+        static statusList = mw.config.get("wgPageName") === "萌娘百科_talk:讨论版/操作申请/注销账号申请" ?
+            [
+                ["w", "请求被撤回"],
+            ] : [
+                ["r", "问题已解决"],
+                ["p", "问题已答复"],
+                ["w", "请求被撤回"],
+                ["n", "无人回复"],
+            ];
+        static archiveOffsetsFromStatus = {
+            ...Object.fromEntries(MARWindow.statusList.map(([status]) => [status, 3])),
+            n: 10,
+        };
+
+        static bolbLabel = (text) => $("").addClass("AnnTools_bolb").text(text);
+
+        panelLayout = new OO.ui.PanelLayout({
+            scrollable: false,
+            expanded: false,
+            padded: true,
+        });
+
+        sectionTitleWidget = new OO.ui.Widget({
+            classes: ["AnnTools_paragraphs"],
+        });
+        /**
+         * @type { string | undefined }
+         */
+        get sectionTitle() {
+            return this.sectionTitleWidget.getData();
+        }
+
+        statusRadioSelect = new OO.ui.RadioSelectWidget({
+            items: MARWindow.statusList.map(([data, label]) => new OO.ui.RadioOptionWidget({
+                data,
+                label,
+            })),
+            classes: ["AnnTools_RadioSelectWidget_column_2"],
+        });
+        /**
+         * @type { string | undefined }
+         */
+        get status() {
+            return this.statusRadioSelect.findSelectedItem()?.getData?.();
+        }
+        /**
+         * @type { string | undefined }
+         */
+        get statusLabel() {
+            return this.statusRadioSelect.findSelectedItem()?.getLabel?.();
+        }
+
+        archiveOffsetNumberInput = new OO.ui.NumberInputWidget({
+            min: 1,
+            max: 10,
+            step: 1,
+            value: 3,
+        });
+        get archiveOffset() {
+            return Math.max(1, Math.min(30, Math.round(+this.archiveOffsetNumberInput.getValue())));
+        }
+
+        precommentMultilineTextInput = new OO.ui.MultilineTextInputWidget({
+            placeholder: wgULS("(但是如果不写就啥也没有)", "(但是如果不寫就啥也沒有)"),
+            autosize: true,
+        });
+        get precomment() {
+            return this.precommentMultilineTextInput.getValue();
+        }
+
+        commentTextInput = new OO.ui.TextInputWidget({
+            placeholder: wgULS("(但是如果不写就啥也没有)", "(但是如果不寫就啥也沒有)"),
+        });
+        get comment() {
+            return this.commentTextInput.getValue();
+        }
+
+        constructor (config) {
+            super(config);
+        }
+        initialize() {
+            super.initialize();
+            this.panelLayout.$element.append(...[
+                [this.sectionTitleWidget, wgULS("段落标题:", "段落標題:")],
+                [this.statusRadioSelect, wgULS("标记状态:", "標記狀態:")],
+                [this.archiveOffsetNumberInput, wgULS("存档用时:", "存檔用時:")],
+                [this.precommentMultilineTextInput, wgULS("前置留言:", "前置留言:")],
+                [this.commentTextInput, wgULS("内置留言:", "內置留言:")],
+            ].map(([fieldWidget, labelText]) => new OO.ui.FieldLayout(fieldWidget, {
+                label: MARWindow.bolbLabel(labelText),
+                align: "top",
+            }).$element));
+
+            this.statusRadioSelect.on("choose", (item) => {
+                this.archiveOffsetNumberInput.setValue(MARWindow.archiveOffsetsFromStatus[item.getData()] || 3);
+            });
+            this.precommentMultilineTextInput.on("resize", () => {
+                this.updateSize();
+            });
+
+            this.$body.append(this.panelLayout.$element);
+        }
+        getBodyHeight() {
+            return this.panelLayout.$element.outerHeight(true);
+        }
+        getSetupProcess(data) {
+            return super.getSetupProcess(data).next(() => {
+                if (this.sectionTitle && Reflect.has(caches, this.sectionTitle)) {
+                    const cache = caches[this.sectionTitle];
+                    if (cache.status) {
+                        this.statusRadioSelect.selectItemByData(cache.status);
+                    }
+                    this.archiveOffsetNumberInput.setValue(cache.archiveOffset);
+                    this.precommentMultilineTextInput.setValue(cache.precomment);
+                    this.commentTextInput.setValue(cache.comment);
+                }
+            }, this);
+        }
+        getActionProcess(action) {
+            if (action === "cancel") {
+                return new OO.ui.Process(() => this.close({ action }).closed.promise()).next(() => {
+                    caches[this.sectionTitle] = {
+                        status: this.status,
+                        archiveOffset: this.archiveOffset,
+                        precomment: this.precomment,
+                        comment: this.comment,
+                    };
+                    this.statusRadioSelect.selectItem();
+                    this.archiveOffsetNumberInput.setValue(3);
+                    this.precommentMultilineTextInput.setValue("");
+                    this.commentTextInput.setValue("");
+                });
+            }
+            if (action === "submit") {
+                return new OO.ui.Process($.when((async () => {
+                    if (!this.status) {
+                        throw new OO.ui.Error(wgULS("请选择一个状态", "請選擇一個狀態"), {
+                            recoverable: false,
+                        });
+                    }
+                    const toclist = Object.fromEntries((await api.post({
+                        action: "parse",
+                        format: "json",
+                        pageid: mw.config.get("wgArticleId"),
+                        prop: "sections",
+                    })).parse.sections.map(({ anchor, index }) => [anchor, index]));
+                    if (!Reflect.has(toclist, this.sectionTitle)) {
+                        throw new OO.ui.Error(wgULS("小工具无法根据段落标题找到该段落,请移除该段落标题内的模板后再行操作……", "小工具無法根據段落標題找到該段落,請移除該段落標題內的模板後再行操作……"), {
+                            recoverable: false,
+                        });
+                    }
+                    const section = toclist[this.sectionTitle];
+                    try {
+                        await this.markAsResolved({ section });
+                        this.close({ action });
+                        mw.notify(wgULS("即将刷新……", "即將刷新……"), {
+                            title: wgULS("标记成功", "標記成功"),
+                            type: "success",
+                            tag: "AnnTools_MarkAsResolved",
+                        });
+                        setTimeout(() => location.reload(), 730);
+                    } catch (e) {
+                        console.error("[MarkAsResolved] Error:", e);
+                        throw new OO.ui.Error(e);
+                    }
+                })()).promise(), this);
+            }
+            return super.getActionProcess(action);
+        }
+        async markAsResolved({ section }) {
+            const d = await api.postWithToken("csrf", {
+                action: "edit",
+                pageid: mw.config.get("wgArticleId"),
+                section,
+                summary: `标记讨论串「/* ${this.sectionTitle} */」状态为【${this.statusLabel}】`,
+                tags: "Automation tool",
+                nocreate: true,
+                appendtext: `${this.precomment.length > 0 ? `\n:${this.precomment}——~~~~` : ""}\n\n{{MarkAsResolved|time={{subst:#timel:Ymd}}|status=${this.status}|archive-offset=${this.archiveOffset}|comment=${this.comment}|sign=~~~~}}`,
+            });
+            if (d.error) {
+                throw d.error.code;
+            }
+        }
+        setSectionTitle(sectionTitle) {
+            this.sectionTitleWidget.setData(sectionTitle);
+            this.sectionTitleWidget.$element.text(sectionTitle);
+        }
+    }
+
+    const windowManager = new OO.ui.WindowManager();
+    $body.append(windowManager.$element);
+    const marDialog = new MARWindow({
+        size: "large",
+    });
+    windowManager.addWindows([marDialog]);
+    for (const ele of $("#mw-content-text > .mw-parser-output > h2, #mw-content-text > .mw-parser-output > .discussionContainer > h2")) {
+        const self = $(ele);
+        const content = self.nextUntil("h2").not("h2");
+        if (content.hasClass("saveNotice") || content.hasClass("MarkAsResolved")) { continue; }
+        const sectionTitle = self.find(".mw-headline").attr("id");
+        const button = $("");
+        button.attr("href", "javascript:void(0);").prop("draggable", false).addClass("AnnTools_MarkAsResolved").text(wgULS("标记状态", "標記狀態"));
+        self.find(".mw-editsection-bracket").first()
+            .after(' | ')
+            .after(button);
+        button.on("click", () => {
+            if (!marDialog.isVisible()) {
+                marDialog.setSectionTitle(sectionTitle);
+                windowManager.openWindow(marDialog);
+            }
+            return false;
+        });
+        const quicksave = self.find(".AnnTools_QuickSave");
+        if (quicksave[0]) {
+            const divider = quicksave.next(".mw-editsection-divider");
+            if (divider.length > 0) {
+                self.find(".mw-editsection .mw-editsection-bracket").first().after(divider).after(quicksave);
+            }
+        }
+    }
+});
+// 
diff --git a/src/gadgets/MarkAsResolved-restricted/definition.yaml b/src/gadgets/MarkAsResolved-restricted/definition.yaml new file mode 100644 index 00000000..892dc2d2 --- /dev/null +++ b/src/gadgets/MarkAsResolved-restricted/definition.yaml @@ -0,0 +1,38 @@ +ResourceLoader: true + +hidden: false + +default: true + +supportsUrlLoad: false + +targets: [] + +skins: [] + +actions: [] + +type: general + +package: false + +rights: + - edit + - patrolmarks + +peers: [] + +dependencies: + - mediawiki.api + - ext.gadget.libPolyfill + - ext.gadget.libOOUIDialog + - ext.gadget.site-lib + +_sites: + - zh + +_section: maintenance + +_files: + - MediaWiki:Gadget-MarkAsResolved.css + - MediaWiki:Gadget-MarkAsResolved-restricted.js