User:Chatsven/FastEditData.js
外观
注意:保存之后,你必须清除浏览器缓存才能看到做出的更改。Google Chrome、Firefox、Microsoft Edge及Safari:按住⇧ Shift键并单击工具栏的“刷新”按钮。参阅Help:绕过浏览器缓存以获取更多帮助。
// <nowiki>
// 功能:在中文维基页面侧栏加入“修改描述”,修改当前页面关联 Wikidata 项目的中文描述与繁体中文描述。
// 说明:弹窗 CSS 直接沿用原文档的 vpf-detail 弹窗体系,只做必要的输入框与撤销按钮扩展。
(function () {
'use strict';
const TOOL_NAME = 'Wikidata描述修改';
const PORTLET_LINK_ID = 'ca-wikidata-description-editor';
const STYLE_ID = 'wikidata-description-editor-style';
const WIKIDATA_API = 'https://www.wikidata.org/w/api.php';
let wddState = {
qid: null,
pageTitle: null,
previousDescriptions: null,
currentRevisionId: null,
createdNewItem: false,
submitting: false,
undoing: false
};
mw.loader.using(['mediawiki.api', 'mediawiki.util'], function () {
addStyles();
addPortletButton();
window.setTimeout(ensurePortletButton, 400);
window.setTimeout(ensurePortletButton, 1200);
window.setTimeout(ensurePortletButton, 2500);
});
function addStyles() {
if ($('#' + STYLE_ID).length) {
return;
}
$('head').append(
$('<style>')
.attr('id', STYLE_ID)
.text(`
#vpf-overlay {
scrollbar-width: none;
-ms-overflow-style: none;
}
#vpf-overlay::-webkit-scrollbar {
display: none;
width: 0;
height: 0;
}
@keyframes vpf-window-open {
0% {
opacity: 0;
transform: translate(-50%, -48%) scale(0.96);
}
100% {
opacity: 1;
transform: translate(-50%, -50%) scale(1);
}
}
@keyframes vpf-window-close {
0% {
opacity: 1;
transform: translate(-50%, -50%) scale(1);
}
100% {
opacity: 0;
transform: translate(-50%, -48%) scale(0.96);
}
}
@keyframes vpf-detail-overlay-fade-in {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
@keyframes vpf-detail-overlay-fade-out {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
@keyframes wdd-undo-fade-in {
0% {
opacity: 0;
transform: translateY(3px);
}
100% {
opacity: 1;
transform: translateY(0);
}
}
.vpf-overlay {
position: fixed;
inset: 0;
z-index: 9998;
background: rgba(32, 33, 36, 0.28);
backdrop-filter: blur(6px);
-webkit-backdrop-filter: blur(6px);
font-family: -apple-system, BlinkMacSystemFont, "SF Pro", "Segoe UI", sans-serif;
font-size: 12px;
line-height: 1.35;
}
.vpf-detail-layer {
position: fixed;
inset: 0;
z-index: 100;
display: flex;
align-items: center;
justify-content: center;
box-sizing: border-box;
background: transparent;
opacity: 0;
animation: vpf-detail-overlay-fade-in 0.22s cubic-bezier(0.2, 0.8, 0.2, 1) forwards;
}
.vpf-detail-layer.vpf-detail-closing {
pointer-events: none;
animation: vpf-detail-overlay-fade-out 0.18s cubic-bezier(0.4, 0, 1, 1) forwards;
}
.vpf-detail-card {
position: absolute;
left: 50%;
top: 50%;
width: 390px;
min-height: 330px;
height: 330px;
transform: translate(-50%, -50%);
box-sizing: border-box;
border-radius: 26px;
background: #FFFFFF;
overflow: hidden;
box-shadow: 0 8px 40px 0 rgba(0, 0, 0, 0.12);
animation: vpf-window-open 0.22s cubic-bezier(0.2, 0.8, 0.2, 1);
transform-origin: center center;
}
.vpf-detail-layer.vpf-detail-closing .vpf-detail-card {
animation: vpf-window-close 0.18s cubic-bezier(0.4, 0, 1, 1) forwards;
}
.vpf-detail-title {
position: absolute;
left: 120px;
top: 20px;
right: 31px;
color: rgba(0, 0, 0, 0.85);
font-family: -apple-system, BlinkMacSystemFont, "SF Pro", "Segoe UI", sans-serif;
font-size: 13px;
font-style: normal;
font-weight: 700;
line-height: 16px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.vpf-detail-subtitle {
position: absolute;
left: 120px;
top: 44px;
right: 31px;
color: rgba(0, 0, 0, 0.85);
font-family: -apple-system, BlinkMacSystemFont, "SF Pro", "Segoe UI", sans-serif;
font-size: 11px;
font-style: normal;
font-weight: 400;
line-height: 14px;
}
.vpf-detail-row-label {
position: absolute;
left: 34px;
display: flex;
width: 80px;
height: 24px;
flex-direction: column;
justify-content: center;
box-sizing: border-box;
color: rgba(0, 0, 0, 0.50);
text-align: right;
font-family: -apple-system, BlinkMacSystemFont, "SF Pro", "Segoe UI", sans-serif;
font-size: 13px;
font-style: normal;
font-weight: 400;
line-height: 14px;
letter-spacing: -0.26px;
}
.vpf-detail-row-value {
position: absolute;
left: 126px;
right: 31px;
display: -webkit-box;
height: 24px;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1;
align-items: center;
overflow: hidden;
color: rgba(0, 0, 0, 0.85);
text-overflow: ellipsis;
font-family: -apple-system, BlinkMacSystemFont, "SF Pro", "Segoe UI", sans-serif;
font-size: 13px;
font-style: normal;
font-weight: 510;
line-height: 16px;
mix-blend-mode: plus-darker;
}
.vpf-detail-row-value > span {
display: flex;
height: 24px;
align-items: center;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.vpf-detail-row-value.vpf-detail-summary {
display: block;
height: auto;
min-height: 24px;
line-height: 16px;
overflow: visible;
text-overflow: clip;
-webkit-line-clamp: unset;
-webkit-box-orient: initial;
}
.vpf-detail-row-value.vpf-detail-summary > span {
display: block;
height: auto;
max-height: none;
align-items: initial;
overflow: visible;
white-space: normal;
overflow-wrap: anywhere;
word-break: break-word;
text-overflow: clip;
}
.vpf-detail-row-1 {
top: 96px;
}
.vpf-detail-row-2 {
top: 134px;
}
.vpf-detail-row-3 {
top: 172px;
}
.vpf-detail-row-4 {
top: 210px;
}
.vpf-detail-row-5 {
top: 248px;
}
.vpf-detail-actions {
position: absolute;
right: 20px;
bottom: 20px;
display: flex;
gap: 8px;
}
.vpf-detail-button {
display: flex;
width: 74px;
height: 24px;
justify-content: center;
align-items: center;
box-sizing: border-box;
border: 0;
border-radius: 8px;
cursor: pointer;
text-align: center;
font-family: -apple-system, BlinkMacSystemFont, "SF Pro", "Segoe UI", sans-serif;
font-size: 13px;
font-style: normal;
font-weight: 510;
line-height: 16px;
mix-blend-mode: plus-darker;
}
.vpf-detail-button:focus {
outline: none;
}
.vpf-detail-close {
background: rgba(0, 0, 0, 0.06);
color: #1A1A1A;
}
.vpf-detail-add {
background: #007AFF;
color: #FFFFFF;
}
.vpf-detail-add:disabled {
opacity: 0.45;
cursor: not-allowed;
}
.wdd-detail-input {
display: block;
width: 100%;
height: 24px;
box-sizing: border-box;
border: 1px solid rgba(0, 0, 0, 0.08);
border-radius: 8px;
background: #FFFFFF;
color: rgba(0, 0, 0, 0.85);
font-family: -apple-system, BlinkMacSystemFont, "SF Pro", "Segoe UI", sans-serif;
font-size: 13px;
font-style: normal;
font-weight: 510;
line-height: 16px;
padding: 0 8px;
outline: none;
mix-blend-mode: plus-darker;
transition:
border-color 0.16s ease,
box-shadow 0.16s ease,
opacity 0.16s ease;
}
.wdd-detail-input:focus {
border-color: rgba(0, 0, 0, 0.08);
box-shadow:
0 0 0 1px rgba(0, 0, 0, 0.08),
0 0 0 3.5px rgba(0, 122, 255, 0.25),
0 0 0 7px rgba(0, 122, 255, 0.15);
}
.wdd-detail-input:disabled {
opacity: 0.45;
cursor: not-allowed;
}
.wdd-detail-undo {
display: none;
background: rgba(255, 0, 0, 0.13);
color: #FF0000;
opacity: 0;
}
.wdd-detail-undo.wdd-detail-undo-visible {
display: flex;
animation: wdd-undo-fade-in 0.22s cubic-bezier(0.2, 0.8, 0.2, 1) forwards;
}
.wdd-hidden {
display: none !important;
}
`)
);
}
function addPortletButton() {
$('#' + PORTLET_LINK_ID).remove();
const linkNode = mw.util.addPortletLink(
'p-cactions',
'#',
'修改描述',
PORTLET_LINK_ID,
'修改当前条目在 Wikidata 上的中文描述'
);
if (linkNode) {
bindPortletButton();
return true;
}
return false;
}
function ensurePortletButton() {
if ($('#' + PORTLET_LINK_ID).length || $('#pt-' + PORTLET_LINK_ID).length) {
bindPortletButton();
return;
}
if (addPortletButton()) {
return;
}
addPortletButtonToTools();
}
function addPortletButtonToTools() {
const ids = ['p-tb', 'p-page-tools', 'p-associated-pages', 'p-personal'];
for (let i = 0; i < ids.length; i += 1) {
if (!document.getElementById(ids[i])) {
continue;
}
const linkNode = mw.util.addPortletLink(
ids[i],
'#',
'修改描述',
PORTLET_LINK_ID,
'修改当前条目在 Wikidata 上的中文描述'
);
if (linkNode) {
bindPortletButton();
return true;
}
}
return false;
}
function bindPortletButton() {
$('#' + PORTLET_LINK_ID + ', #pt-' + PORTLET_LINK_ID)
.off('click.wdd')
.on('click.wdd', function (e) {
e.preventDefault();
openDescriptionDialog();
});
$('#' + PORTLET_LINK_ID + ' a, #pt-' + PORTLET_LINK_ID + ' a')
.off('click.wdd')
.on('click.wdd', function (e) {
e.preventDefault();
openDescriptionDialog();
});
}
function openDescriptionDialog() {
if ($('#vpf-overlay').length) {
return;
}
wddState = {
qid: null,
pageTitle: mw.config.get('wgTitle') || mw.config.get('wgPageName') || document.title,
previousDescriptions: null,
currentRevisionId: null,
createdNewItem: false,
submitting: false,
undoing: false
};
renderLoadingDialog();
fetchCurrentPageEntity()
.then(function (entityData) {
wddState.qid = entityData.qid || null;
wddState.previousDescriptions = entityData.descriptions || {};
wddState.currentRevisionId = entityData.lastrevid || null;
wddState.createdNewItem = false;
renderReadyDialog();
})
.fail(function (err) {
console.error(err);
mw.notify(getErrorMessage(err), {
title: TOOL_NAME,
type: 'error'
});
closeDescriptionDialog(true);
});
}
function renderBaseDialog() {
$('#vpf-overlay').remove();
const $overlay = $('<div>')
.attr('id', 'vpf-overlay')
.addClass('vpf-overlay');
const $layer = $('<div>')
.attr('id', 'vpf-detail-layer')
.addClass('vpf-detail-layer');
const $card = $('<div>')
.addClass('vpf-detail-card')
.on('click', function (e) {
e.stopPropagation();
});
$layer.append($card);
$overlay.append($layer);
$('body').append($overlay);
bindDialogKeys();
return $card;
}
function renderLoadingDialog() {
const $card = renderBaseDialog();
$card.append(
$('<div>').addClass('vpf-detail-title').text(wddState.pageTitle || '条目名称'),
$('<div>').addClass('vpf-detail-subtitle').text('正在读取此条目在 Wikidata 的描述。'),
$('<div>').addClass('vpf-detail-row-label vpf-detail-row-1').text('先前:'),
$('<div>')
.addClass('vpf-detail-row-value vpf-detail-row-1')
.append($('<span>').text('读取中')),
$('<div>')
.addClass('vpf-detail-actions')
.append(
$('<button>')
.attr('type', 'button')
.addClass('vpf-detail-button vpf-detail-close')
.text('取消')
.on('click', function (e) {
e.preventDefault();
closeDescriptionDialog();
}),
$('<button>')
.attr('type', 'button')
.addClass('vpf-detail-button vpf-detail-add')
.text('添加')
.prop('disabled', true)
)
);
}
function renderReadyDialog() {
const previousDisplay = getPreviousDescriptionForDisplay(wddState.previousDescriptions);
const $card = $('#vpf-detail-layer .vpf-detail-card');
if (!$card.length) {
return;
}
$card.empty();
const $descriptionInput = $('<input>')
.attr({
id: 'wdd-description-input',
type: 'text',
autocomplete: 'off',
spellcheck: 'false'
})
.addClass('wdd-detail-input')
.val(previousDisplay === '无' ? '' : previousDisplay);
const $summaryInput = $('<input>')
.attr({
id: 'wdd-summary-input',
type: 'text',
autocomplete: 'off',
spellcheck: 'false'
})
.addClass('wdd-detail-input')
.val(buildEditSummary(wddState.qid));
$card.append(
$('<div>').addClass('vpf-detail-title').text(wddState.pageTitle || '条目名称'),
$('<div>').addClass('vpf-detail-subtitle').text(wddState.qid ? '你可以在此快速修改条目在 Wikidata 的描述。' : '此页面尚未关联 Wikidata 项目,将新建项目并写入描述。'),
$('<div>').addClass('vpf-detail-row-label vpf-detail-row-1').text('先前:'),
$('<div>')
.addClass('vpf-detail-row-value vpf-detail-row-1')
.attr('title', previousDisplay)
.append($('<span>').text(previousDisplay)),
$('<label>')
.addClass('vpf-detail-row-label vpf-detail-row-2')
.attr('for', 'wdd-description-input')
.text('描述:'),
$('<div>')
.addClass('vpf-detail-row-value vpf-detail-row-2')
.append($descriptionInput),
$('<label>')
.addClass('vpf-detail-row-label vpf-detail-row-3')
.attr('for', 'wdd-summary-input')
.text('修改日志:'),
$('<div>')
.addClass('vpf-detail-row-value vpf-detail-row-3')
.append($summaryInput),
$('<div>')
.addClass('vpf-detail-actions')
.append(
$('<button>')
.attr('type', 'button')
.addClass('vpf-detail-button wdd-detail-undo')
.text('撤销')
.on('click', function (e) {
e.preventDefault();
undoSubmission();
}),
$('<button>')
.attr('type', 'button')
.addClass('vpf-detail-button vpf-detail-close')
.text('取消')
.on('click', function (e) {
e.preventDefault();
closeDescriptionDialog();
}),
$('<button>')
.attr('type', 'button')
.addClass('vpf-detail-button vpf-detail-add')
.text('添加')
.on('click', function (e) {
e.preventDefault();
submitDescriptionChange();
})
)
);
window.setTimeout(function () {
$descriptionInput.trigger('focus').select();
}, 40);
}
function closeDescriptionDialog(immediate) {
const $overlay = $('#vpf-overlay');
const $layer = $('#vpf-detail-layer');
if (!$overlay.length) {
return;
}
unbindDialogKeys();
if (immediate) {
$overlay.remove();
return;
}
if ($overlay.hasClass('vpf-closing')) {
return;
}
$overlay.addClass('vpf-closing');
$layer.addClass('vpf-detail-closing');
window.setTimeout(function () {
$overlay.remove();
}, 190);
}
function fetchCurrentPageEntity() {
const localApi = new mw.Api();
const pageName = mw.config.get('wgPageName');
if (!pageName) {
return $.Deferred().reject(new Error('无法识别当前页面。')).promise();
}
return localApi.get({
action: 'query',
prop: 'pageprops',
ppprop: 'wikibase_item',
titles: pageName,
formatversion: 2,
format: 'json'
}).then(function (data) {
const page = data && data.query && data.query.pages && data.query.pages[0];
const qid = page && page.pageprops && page.pageprops.wikibase_item;
if (!qid) {
return fetchWikidataEntityBySitelink(getCurrentWikiSiteId(), getCurrentPageTitleForWikidata())
.then(function (entityData) {
return entityData;
}, function () {
return {
qid: null,
descriptions: {},
lastrevid: null,
missingItem: true
};
});
}
return fetchWikidataEntity(qid);
});
}
function fetchWikidataEntity(qid) {
return mw.loader.using('mediawiki.ForeignApi').then(function () {
const wikidataApi = new mw.ForeignApi(WIKIDATA_API);
return wikidataApi.get({
action: 'wbgetentities',
ids: qid,
props: 'descriptions|info',
languages: 'zh|zh-hans|zh-hant',
format: 'json'
});
}).then(function (data) {
const entity = data && data.entities && data.entities[qid];
if (!entity || entity.missing) {
return $.Deferred().reject(new Error('无法读取 Wikidata 项目:' + qid)).promise();
}
return {
qid: qid,
descriptions: cloneDescriptions(entity.descriptions || {}),
lastrevid: entity.lastrevid || null
};
});
}
function fetchWikidataEntityBySitelink(siteId, pageTitle) {
return mw.loader.using('mediawiki.ForeignApi').then(function () {
const wikidataApi = new mw.ForeignApi(WIKIDATA_API);
return wikidataApi.get({
action: 'wbgetentities',
sites: siteId,
titles: pageTitle,
props: 'descriptions|info',
languages: 'zh|zh-hans|zh-hant',
format: 'json'
});
}).then(function (data) {
const entities = data && data.entities ? data.entities : {};
const ids = Object.keys(entities).filter(function (id) {
return id !== '-1' && entities[id] && !entities[id].missing;
});
if (!ids.length) {
return $.Deferred().reject(new Error('当前页面没有关联的 Wikidata 项目。')).promise();
}
const qid = ids[0];
const entity = entities[qid];
return {
qid: qid,
descriptions: cloneDescriptions(entity.descriptions || {}),
lastrevid: entity.lastrevid || null
};
});
}
function cloneDescriptions(descriptions) {
const result = {};
['zh', 'zh-hans', 'zh-hant'].forEach(function (lang) {
if (descriptions[lang] && typeof descriptions[lang].value === 'string') {
result[lang] = descriptions[lang].value;
}
});
return result;
}
function getPreviousDescriptionForDisplay(descriptions) {
const variant = getUserChineseVariant();
let value = '';
if (variant === 'zh-hant') {
value = descriptions['zh-hant'] || descriptions.zh || descriptions['zh-hans'] || '';
} else if (variant === 'zh-hans') {
value = descriptions.zh || descriptions['zh-hans'] || descriptions['zh-hant'] || '';
} else {
value = descriptions.zh || descriptions['zh-hans'] || descriptions['zh-hant'] || '';
}
return value || '无';
}
function getUserChineseVariant() {
const variant =
mw.config.get('wgUserVariant') ||
mw.user.options.get('variant') ||
mw.config.get('wgUserLanguage') ||
mw.config.get('wgContentLanguage') ||
'zh';
const normalized = String(variant).toLowerCase().replace('_', '-');
if (/^zh-(hant|tw|hk|mo)$/.test(normalized)) {
return 'zh-hant';
}
if (/^zh-(hans|cn|sg|my)$/.test(normalized)) {
return 'zh-hans';
}
return 'zh';
}
function submitDescriptionChange() {
if (wddState.submitting) {
return;
}
const rawDescription = ($('#wdd-description-input').val() || '').trim();
const rawSummary = ($('#wdd-summary-input').val() || '').trim();
if (!rawDescription) {
mw.notify('请先填写描述。', {
title: TOOL_NAME,
type: 'warn'
});
$('#wdd-description-input').trigger('focus');
return;
}
wddState.submitting = true;
$('.vpf-detail-add').prop('disabled', true).text('提交中');
$('#wdd-description-input, #wdd-summary-input').prop('disabled', true);
$.when(
convertChineseVariant(rawDescription, 'zh-hans'),
convertChineseVariant(rawDescription, 'zh-hant')
).then(function (simplifiedText, traditionalText) {
return saveWikidataDescriptions({
zh: normalizeConvertedText(simplifiedText),
'zh-hant': normalizeConvertedText(traditionalText)
}, rawSummary || buildEditSummary(wddState.qid));
}).done(function () {
$('.vpf-detail-add')
.prop('disabled', true)
.text('完成');
$('.vpf-detail-close')
.addClass('wdd-hidden');
$('.wdd-detail-undo')
.addClass('wdd-detail-undo-visible')
.prop('disabled', false);
mw.notify(wddState.createdNewItem ? '已新建 Wikidata 项目并写入描述。' : '已更新 Wikidata 描述。', {
title: TOOL_NAME,
type: 'success'
});
}).fail(function (err) {
console.error(err);
mw.notify(getErrorMessage(err), {
title: TOOL_NAME,
type: 'error'
});
$('.vpf-detail-add').prop('disabled', false).text('添加');
$('#wdd-description-input, #wdd-summary-input').prop('disabled', false);
}).always(function () {
wddState.submitting = false;
});
}
function undoSubmission() {
if (wddState.undoing || !wddState.previousDescriptions) {
return;
}
wddState.undoing = true;
$('.wdd-detail-undo').prop('disabled', true).text('撤销中');
saveWikidataDescriptions({
zh: wddState.previousDescriptions.zh || '',
'zh-hant': wddState.previousDescriptions['zh-hant'] || ''
}, wddState.createdNewItem ? '撤销本次新建项目的中文与繁体中文描述' : '撤销先前的 Wikidata 描述修改,恢复中文与繁体中文描述')
.done(function () {
$('#wdd-description-input').val(
getPreviousDescriptionForDisplay(wddState.previousDescriptions) === '无'
? ''
: getPreviousDescriptionForDisplay(wddState.previousDescriptions)
);
$('.vpf-detail-add')
.prop('disabled', true)
.text('已撤销');
$('.wdd-detail-undo')
.prop('disabled', true)
.text('已撤销');
mw.notify('已撤销本次 Wikidata 描述修改。', {
title: TOOL_NAME,
type: 'success'
});
})
.fail(function (err) {
console.error(err);
mw.notify(getErrorMessage(err), {
title: TOOL_NAME,
type: 'error'
});
$('.wdd-detail-undo').prop('disabled', false).text('撤销');
})
.always(function () {
wddState.undoing = false;
});
}
function saveWikidataDescriptions(descriptions, summary) {
if (wddState.qid) {
return updateWikidataEntityTerms(wddState.qid, descriptions, summary, false);
}
return createWikidataItemForCurrentPage(summary)
.then(function (qid) {
wddState.qid = qid;
wddState.createdNewItem = true;
return updateWikidataEntityTerms(qid, descriptions, summary, true);
});
}
function createWikidataItemForCurrentPage(summary) {
return mw.loader.using('mediawiki.ForeignApi').then(function () {
const wikidataApi = new mw.ForeignApi(WIKIDATA_API);
const siteId = getCurrentWikiSiteId();
const pageTitle = getCurrentPageTitleForWikidata();
if (!siteId || !pageTitle) {
return $.Deferred().reject(new Error('无法取得当前页面的站点或标题,不能新建 Wikidata 项目。')).promise();
}
return wikidataApi.postWithToken('csrf', {
action: 'wbsetsitelink',
new: 'item',
linksite: siteId,
linktitle: pageTitle,
summary: summary || '新建 Wikidata 项目并连接当前页面',
format: 'json'
}).then(function (response) {
const qid = extractQidFromEntityResponse(response);
if (qid) {
if (response && response.entity && response.entity.lastrevid) {
wddState.currentRevisionId = response.entity.lastrevid;
}
return qid;
}
return fetchWikidataEntityBySitelink(siteId, pageTitle).then(function (entityData) {
wddState.currentRevisionId = entityData.lastrevid || null;
return entityData.qid;
});
});
});
}
function updateWikidataEntityTerms(qid, descriptions, summary, includeLabel) {
return mw.loader.using('mediawiki.ForeignApi').then(function () {
const wikidataApi = new mw.ForeignApi(WIKIDATA_API);
const data = {
descriptions: {
zh: {
language: 'zh',
value: descriptions.zh || ''
},
'zh-hant': {
language: 'zh-hant',
value: descriptions['zh-hant'] || ''
}
}
};
if (includeLabel) {
data.labels = {
zh: {
language: 'zh',
value: wddState.pageTitle || getCurrentPageTitleForWikidata()
}
};
}
const params = {
action: 'wbeditentity',
id: qid,
data: JSON.stringify(data),
summary: summary,
bot: false,
format: 'json'
};
if (wddState.currentRevisionId) {
params.baserevid = wddState.currentRevisionId;
}
return wikidataApi.postWithToken('csrf', params);
}).then(function (response) {
if (response && response.entity && response.entity.lastrevid) {
wddState.currentRevisionId = response.entity.lastrevid;
}
return descriptions;
});
}
function extractQidFromEntityResponse(response) {
if (!response) {
return '';
}
if (response.entity && response.entity.id) {
return response.entity.id;
}
if (response.entities) {
const ids = Object.keys(response.entities).filter(function (id) {
return /^Q\d+$/.test(id);
});
if (ids.length) {
return ids[0];
}
}
if (response.item && response.item.id) {
return response.item.id;
}
if (response.id && /^Q\d+$/.test(response.id)) {
return response.id;
}
return '';
}
function getCurrentWikiSiteId() {
return mw.config.get('wgDBname') || 'zhwiki';
}
function getCurrentPageTitleForWikidata() {
const pageName = mw.config.get('wgPageName') || '';
return pageName.replace(/_/g, ' ');
}
function convertChineseVariant(text, targetVariant) {
const localApi = new mw.Api();
return localApi.get({
action: 'parse',
text: String(text),
contentmodel: 'wikitext',
prop: 'text',
variant: targetVariant,
disablelimitreport: true,
formatversion: 2,
format: 'json'
}).then(function (data) {
const html = data && data.parse && data.parse.text;
if (!html) {
return fallbackChineseVariantConversion(text, targetVariant);
}
return extractPlainTextFromHtml(html);
}, function () {
return fallbackChineseVariantConversion(text, targetVariant);
});
}
function extractPlainTextFromHtml(html) {
const div = document.createElement('div');
div.innerHTML = html;
return (div.textContent || '').replace(/\s+/g, ' ').trim();
}
function normalizeConvertedText(text) {
return String(text || '').replace(/\s+/g, ' ').trim();
}
function fallbackChineseVariantConversion(text, targetVariant) {
const simplified = {
'們': '们', '個': '个', '國': '国', '與': '与', '為': '为', '於': '于', '這': '这', '後': '后',
'會': '会', '時': '时', '來': '来', '對': '对', '體': '体', '關': '关', '開': '开', '發': '发',
'學': '学', '長': '长', '廣': '广', '東': '东', '門': '门', '風': '风', '電': '电', '車': '车',
'馬': '马', '島': '岛', '區': '区', '縣': '县', '鄉': '乡', '鎮': '镇', '臺': '台', '灣': '湾',
'歷': '历', '義': '义', '華': '华', '設': '设', '劃': '划', '稱': '称', '屬': '属', '類': '类',
'別': '别', '條': '条', '項': '项', '頁': '页', '編': '编', '輯': '辑', '寫': '写', '無': '无',
'雙': '双', '邊': '边', '織': '织', '構': '构', '員': '员', '團': '团', '線': '线', '證': '证',
'戰': '战', '將': '将'
};
const traditional = {};
Object.keys(simplified).forEach(function (trad) {
traditional[simplified[trad]] = trad;
});
const table = targetVariant === 'zh-hant' ? traditional : simplified;
return String(text).replace(/./g, function (char) {
return table[char] || char;
});
}
function buildEditSummary(qid) {
if (qid) {
return '更新 Wikidata 描述:补充或更正用于区分同名项目的简短说明' +
'(' + qid + ',zh、zh-hant)';
}
return '新建 Wikidata 项目并添加中文与繁体中文描述';
}
function bindDialogKeys() {
$(document)
.off('keydown.wddDialog')
.on('keydown.wddDialog', function (e) {
if (!$('#vpf-overlay').length) {
return;
}
if (e.key === 'Escape' && !wddState.submitting && !wddState.undoing && !$('.vpf-detail-close').hasClass('wdd-hidden')) {
e.preventDefault();
closeDescriptionDialog();
}
if ((e.metaKey || e.ctrlKey) && e.key === 'Enter') {
e.preventDefault();
submitDescriptionChange();
}
});
}
function unbindDialogKeys() {
$(document).off('keydown.wddDialog');
}
function getErrorMessage(err) {
if (!err) {
return '操作失败。';
}
if (typeof err === 'string') {
return err;
}
if (err.error && err.error.info) {
return err.error.info;
}
if (err.exception) {
return err.exception;
}
if (err.message) {
return err.message;
}
if (Array.isArray(err) && err.length) {
return getErrorMessage(err[0]);
}
return '操作失败,请查看控制台。';
}
})();
// </nowiki>