跳转到内容

User:魔琴/gadgets/FullWikidataDesc/index.js

维基百科,自由的百科全书
注意:保存之后,你必须清除浏览器缓存才能看到做出的更改。Google ChromeFirefoxMicrosoft EdgeSafari:按住⇧ Shift键并单击工具栏的“刷新”按钮。参阅Help:绕过浏览器缓存以获取更多帮助。
/**
 * FullWikidataDesc
 *
 * 在条目顶端显示/编辑维基数据描述(包括所有中文变体和英语、多语言)
 *
 * 原作者:User:Alexander Misel ([[Special:Permalink/45559457]])
 * 改进:User:逆襲的天邪鬼 ([[MediaWiki:Gadget-WikidataDesc.js]])
 * 修改为所有中文变体(利用AI/LLM)
 */

mw.loader.using('mediawiki.ForeignApi').done(function () {
    'use strict';

    // Define language list
    var languages = ['zh', 'zh-hans', 'zh-cn', 'zh-my', 'zh-sg', 'zh-hant', 'zh-hk', 'zh-mo', 'zh-tw', 'en', 'mul'];

    var UI = ['zh-hk', 'zh-mo', 'zh-tw'].indexOf(mw.config.get('wgUserLanguage'))!== -1 ? {
        SAVING: '正在儲存',
        EDIT: '編輯',
        SAVE: '儲存',
        CANCEL: '取消',
        PLACEHOLDER_DESC: '維基數據描述',
        PLACEHOLDER_LABEL: '維基數據標籤',
        LANG: '語言',
        DESC: '描述',
        LABEL: '標籤',
        EMPTY_DESC: '無描述',
        EMPTY_LABEL: '無標籤',
        SUCCESS: '儲存成功',
        ERROR: '發生错误',
    } : {
        SAVING: '正在保存',
        EDIT: '编辑',
        SAVE: '保存',
        CANCEL: '取消',
        PLACEHOLDER_DESC: '维基数据描述',
        PLACEHOLDER_LABEL: '维基数据标签',
        LANG: '语言',
        DESC: '描述',
        LABEL: '标签',
        EMPTY_DESC: '无描述',
        EMPTY_LABEL: '无标签',
        SUCCESS: '保存成功',
        ERROR: '发生错误',
    };

    var $desc = $('<div id="fullwikidatadesc" class="noprint">');
    var $table = $('<table id="fullwikidatadesc_table">');
    var CSS = `
        #fullwikidatadesc .text { color: var(--color-subtle,#54595d); }
        #fullwikidatadesc .editbox { width: 100%; padding: 4px; border: none; border-bottom: 1px solid #ccc; box-sizing: border-box; }
        #fullwikidatadesc .editbox:focus { border-bottom: 1px solid #0645ad; }
        #fullwikidatadesc .option { font-size: smaller; }
        #fullwikidatadesc_table { width: 100%; border-collapse: collapse; }
        #fullwikidatadesc_table td { padding: 2px; border-bottom: 1px solid #ddd; }
        .fullwikidatadesc_table_langcell { white-space:nowrap; }
        .fullwikidatadesc_table_labelcell { width:30%; }
        .fullwikidatadesc_table_desccell { width:70%; }
		.fullwikidatadesc_editlink { white-space:nowrap }
    `;

    var status = {};         // 每个语言的标签和描述分别对应显示或编辑状态
    var loaded = false;
    var saving = {};
    var id = '';
    var label = {};
    var lastdesc = {};
    var lastlabel = {};
    var pagename = mw.config.get('wgPageName');

    // 初始化每个语言的状态
    languages.forEach(function (lang) {
        status[lang] = {
            label: 0,
            desc: 0
        };
        saving[lang] = {
            label: false,
            desc: false
        };
        label[lang] = '';
        lastdesc[lang] = '';
        lastlabel[lang] = '';
    });

    var loadCtl = function () {
        $('body').append($('<style>').text(CSS));

        // 添加表头
        var $headerRow = $('<tr style="text-align:left">');
        $headerRow.append($('<th>').text(UI.LANG));
        $headerRow.append($('<th>').text(UI.LABEL));
        $headerRow.append($('<th>').text(UI.DESC));
        $table.append($headerRow);

        languages.forEach(function (lang) {
            var $row = $('<tr>');
            var $langCell = $('<td class="fullwikidatadesc_table_langcell">').text(lang);

            // 标签列
            var $labelCell = $('<td class="fullwikidatadesc_table_contentcell fullwikidatadesc_table_labelcell">');
            var $labelSaving = $('<span id="fullwikidatadesc_label_loading_' + lang + '" class="text option" style="display:none;">(' + UI.SAVING + ')</span>');
            var $labelText = $('<span id="fullwikidatadesc_label_text_' + lang + '" class="text">');
            var $labelEditlink = $('<a href="#" class="fullwikidatadesc_editlink option">[' + UI.EDIT + ' ' + lang + ' ' + UI.LABEL + ']</a>');
            var $labelDescbox = $('<div id="fullwikidatadesc_label_descbox_' + lang + '">')
               .append($labelText)
               .append(' ')
               .append($labelSaving)
               .append($labelEditlink);
            var $labelInput = $('<input class="editbox" type="text" placeHolder="' + UI.PLACEHOLDER_LABEL + '">');
            var $labelSave = $('<a href="#" class="option" id="fullwikidatadesc_label_save_' + lang + '">[' + UI.SAVE + ']</a>');
            var $labelCancel = $('<a href="#" class="option" id="fullwikidatadesc_label_cancel_' + lang + '">[' + UI.CANCEL + ']</a>');
            var $labelEditbox = $('<div id="fullwikidatadesc_label_editbox_' + lang + '" style="display:none;">')
               .append($labelInput)
               .append('<br>')
               .append($labelSave)
               .append($labelCancel);

            $labelCell.append($labelDescbox).append($labelEditbox);

            // 描述列
            var $contentCell = $('<td class="fullwikidatadesc_table_contentcell fullwikidatadesc_table_desccell">');
            var $saving = $('<span id="fullwikidatadesc_loading_' + lang + '" class="text option" style="display:none;">(' + UI.SAVING + ')</span>');
            var $text = $('<span id="fullwikidatadesc_text_' + lang + '" class="text">');
            var $editlink = $('<a href="#" class="fullwikidatadesc_editlink option">[' + UI.EDIT + ' ' + lang + ' ' + UI.DESC + ']</a>');
            var $descbox = $('<div id="fullwikidatadesc_descbox_' + lang + '">')
               .append($text)
               .append(' ')
               .append($saving)
               .append($editlink);
            var $input = $('<input class="editbox" type="text" placeHolder="' + UI.PLACEHOLDER_DESC + '">');
            var $save = $('<a href="#" class="option" id="fullwikidatadesc_save_' + lang + '">[' + UI.SAVE + ']</a>');
            var $cancel = $('<a href="#" class="option" id="fullwikidatadesc_cancel_' + lang + '">[' + UI.CANCEL + ']</a>');
            var $editbox = $('<div id="fullwikidatadesc_editbox_' + lang + '" style="display:none;">')
               .append($input)
               .append('<br>')
               .append($save)
               .append($cancel);

            $contentCell.append($descbox).append($editbox);

            $row.append($langCell).append($labelCell).append($contentCell);
            $table.append($row);

            // 标签编辑事件
            $labelEditlink.click(function () {
                if (status[lang].label!== 0 || saving[lang].label) {
                    return;
                }
                status[lang].label = 1;

                $labelDescbox.hide();
                $labelEditbox.show();
                $labelInput.focus();
            });

            $labelSave.click(function () {
                if (status[lang].label!== 1) {
                    return;
                }
                status[lang].label = 0;
                saving[lang].label = true;

                var newlabel = $labelInput.val();

                $labelText.text(newlabel);
                $labelSaving.show();
                $labelEditlink.hide();
                $labelDescbox.show();
                $labelEditbox.hide();

                saveLabel(lang, newlabel, function (success, error) {
                    saving[lang].label = false;
                    $labelSaving.hide();
                    $labelEditlink.show();
                    if (success) {
                        lastlabel[lang] = newlabel;
                        mw.notify(UI.SUCCESS + ':' + lang + ' ' + UI.LABEL);
                    } else {
                        $labelText.text(lastlabel[lang]);
                        mw.notify(UI.ERROR + ':' + lang + ' ' + UI.LABEL);
                    }
                });
            });

            $labelCancel.click(function () {
                if (status[lang].label!== 1) {
                    return;
                }
                status[lang].label = 0;
                $labelInput.val(lastlabel[lang]);
                $labelDescbox.show();
                $labelEditbox.hide();
            });

            $labelInput.keydown(function (e) {
                if (e.which === 13) {
                    $labelSave.click();
                } else if (e.which === 27) {
                    $labelCancel.click();
                }
            });

            // 描述编辑事件
            $editlink.click(function () {
                if (status[lang].desc!== 0 || saving[lang].desc) {
                    return;
                }
                status[lang].desc = 1;

                $descbox.hide();
                $editbox.show();
                $input.focus();
            });

            $save.click(function () {
                if (status[lang].desc!== 1) {
                    return;
                }
                status[lang].desc = 0;
                saving[lang].desc = true;

                var newdesc = $input.val();

                $text.text(newdesc);
                $saving.show();
                $editlink.hide();
                $descbox.show();
                $editbox.hide();

                save(lang, newdesc, function (success, error) {
                    saving[lang].desc = false;
                    $saving.hide();
                    $editlink.show();
                    if (success) {
                        lastdesc[lang] = newdesc;
                        mw.notify(UI.SUCCESS + ':' + lang + ' ' + UI.DESC);
                    } else {
                        $text.text(lastdesc[lang]);
                        mw.notify(UI.ERROR + ':' + lang + ' ' + UI.DESC);
                    }
                });
            });

            $cancel.click(function () {
                if (status[lang].desc!== 1) {
                    return;
                }
                status[lang].desc = 0;
                $input.val(lastdesc[lang]);
                $descbox.show();
                $editbox.hide();
            });

            $input.keydown(function (e) {
                if (e.which === 13) {
                    $save.click();
                } else if (e.which === 27) {
                    $cancel.click();
                }
            });
        });

        $desc.append($table);
        $("#siteSub").before($desc);
        loaded = true;
    };

    var show = function (descs, labels) {
        if (!loaded) {
            loadCtl();
        }

        languages.forEach(function (lang) {
            var desc = descs[lang];
            var labelValue = labels[lang];
            var $text = $('#fullwikidatadesc_text_' + lang);
            var $input = $('#fullwikidatadesc_editbox_' + lang + ' input');
            var $labelText = $('#fullwikidatadesc_label_text_' + lang);
            var $labelInput = $('#fullwikidatadesc_label_editbox_' + lang + ' input');

            if (desc) {
                $text.text(desc);
                $input.val(desc);
                lastdesc[lang] = desc;
            } else {
                $text.html('<abbr title="' + UI.EMPTY_DESC + '">(' + UI.EMPTY_DESC + ')</abbr>');
                $input.val('');
                lastdesc[lang] = '';
            }

            if (labelValue) {
                $labelText.text(labelValue);
                $labelInput.val(labelValue);
                lastlabel[lang] = labelValue;
            } else {
                $labelText.html('<abbr title="' + UI.EMPTY_LABEL + '">(' + UI.EMPTY_LABEL + ')</abbr>');
                $labelInput.val('');
                lastlabel[lang] = '';
            }
        });
    };

    var load = function (callback) {
        var ns = mw.config.get('wgNamespaceNumber');
        if (ns === 0) {
            var api = new mw.ForeignApi('https://www.wikidata.org/w/api.php');
            var resDescs = {};
            var resLabels = {};

            api.get({
                action: 'wbgetentities',
                props: 'labels|descriptions',
                sites: 'zhwiki',
                titles: pagename,
                languages: languages.join('|')
            }).done(function (data) {
                $.each(data.entities, function (i, item) {
                    if (i == '-1') {
                        id = 'NE';
                        callback({}, {});
                    } else {
                        id = item.id;
                        var labels = item.labels;
                        var descs = item.descriptions;
                        languages.forEach(function (lang) {
                            if (labels[lang]) {
                                resLabels[lang] = labels[lang].value;
                            }
                            if (descs[lang]) {
                                resDescs[lang] = descs[lang].value;
                            }
                        });
                        callback(resDescs, resLabels);
                    }
                });
            });
        }
    };

    var save = function (lang, newdesc, callback) {
        var api = new mw.ForeignApi('https://www.wikidata.org/w/api.php');

        api.get({
            action: 'query',
            meta: 'tokens'
        }).done(function (data) {
            if (id == 'NE') {
                var jdata = JSON.stringify({
                    labels: { [lang]: { language: lang, value: pagename } },
                    descriptions: { [lang]: { language: lang, value: newdesc } },
                    sitelinks: { zhwiki: { site: 'zhwiki', title: pagename } }
                });
                api.post({
                    action: 'wbeditentity',
                    'new': 'item',
                    token: data.query.tokens.csrftoken,
                    data: jdata
                }).done(function () {
                    callback(true);
                }).fail(function () {
                    callback(false);
                });
            } else {
                api.post({
                    action: 'wbsetdescription',
                    id: id,
                    token: data.query.tokens.csrftoken,
                    language: lang,
                    value: newdesc,
                }).done(function () {
                    if (label['zh'] === '') { // 這裏需要僅僅提交zh
                        api.post({
                            action: 'wbsetlabel',
                            id: id,
                            token: data.query.tokens.csrftoken,
                            language: 'zh',
                            value: pagename,
                        }).always(function () {
                            callback(true);
                        });
                    } else {
                        callback(true);
                    }
                }).fail(function () {
                    callback(false);
                });
            }
        }).fail(function () {
            callback(false);
        });
    };

    var saveLabel = function (lang, newlabel, callback) {
        var api = new mw.ForeignApi('https://www.wikidata.org/w/api.php');

        api.get({
            action: 'query',
            meta: 'tokens'
        }).done(function (data) {
            if (id == 'NE') {
                var jdata = JSON.stringify({
                    labels: { [lang]: { language: lang, value: newlabel } },
                    descriptions: { [lang]: { language: lang, value: lastdesc[lang] } },
                    sitelinks: { zhwiki: { site: 'zhwiki', title: pagename } }
                });
                api.post({
                    action: 'wbeditentity',
                    'new': 'item',
                    token: data.query.tokens.csrftoken,
                    data: jdata
                }).done(function () {
                    callback(true);
                }).fail(function () {
                    callback(false);
                });
            } else {
                api.post({
                    action: 'wbsetlabel',
                    id: id,
                    token: data.query.tokens.csrftoken,
                    language: lang,
                    value: newlabel,
                }).done(function () {
                    if (label['zh'] === '' && lang !== 'zh') { // 要排除提交了zh的情况
                        api.post({
                            action: 'wbsetlabel',
                            id: id,
                            token: data.query.tokens.csrftoken,
                            language: 'zh',
                            value: pagename,
                        }).always(function () {
                            callback(true);
                        });
                    } else {
                        callback(true);
                    }
                }).fail(function () {
                    callback(false);
                });
            }
        }).fail(function () {
            callback(false);
        });
    };

    load(show);
});