跳转到内容

MediaWiki:Gadget-dykc-nomination.js

维基百科,自由的百科全书
注意:保存之后,你必须清除浏览器缓存才能看到做出的更改。Google ChromeFirefoxMicrosoft EdgeSafari:按住⇧ Shift键并单击工具栏的“刷新”按钮。参阅Help:绕过浏览器缓存以获取更多帮助。
/**
 * DYKC nomination tool
 * 
 * @version 1.0 (2017-07-02)
 * @author [[User:WhitePhosphorus]]
 */

//<nowiki>
(function($, mw) {

'use strict';

var site = {
	DYKCPage: 'Wikipedia:新条目推荐/候选',
	apiUrl: mw.util.wikiScript('api'),
	articlePage: mw.config.get('wgArticlePath'),
	parse: function(wikitext, extraPara, doneFunc, failFunc) {
		var dataObj = {
			action: 'parse',
			title: site.DYKCPage,
			text: wikitext,
			prop: 'text',
			format: 'json'
		};
		$.extend(dataObj, extraPara);
		$.ajax({
			url: site.apiUrl,
			data: dataObj
		}).done(function (data) {
			var parsedHTML = null;
			if (data.parse) {
				if (data.parse.text) {
					parsedHTML = $.trim(data.parse.text['*']);
				}
			}
			if (parsedHTML !== null) {
				if ($.isFunction(doneFunc))
					doneFunc(parsedHTML);
			} else {
				if ($.isFunction(failFunc))
					failFunc(data && data.error && data.error.code ? 
						data.error.code : 'unknown');
			}
		}).fail(function(jqXHR, textStatus, errorThrown) {
			console.log('Error when parsing wikitext: ' + errorThrown);
			if ($.isFunction(failFunc))
				failFunc('network');
		});
	},
	loadPage: function(pageTitle, doneFunc, failFunc) {
		$.ajax({
			url: site.apiUrl,
			data: {
				action: 'query',
				prop: 'revisions',
				titles: pageTitle,
				rvprop: 'content',
				format: 'json'
			}
		}).done(function(data) {
			var content = null;
			if (data.query) {
				if (data.query.pages) {
					for (var id in data.query.pages) {
						if (data.query.pages[id]) {
							var page = data.query.pages[id];
							if (page.revisions && page.revisions.length) {
								if (page.revisions[0]['*']) {
									content = page.revisions[0]['*'];
								}
							}
						}
					}
				}
			}
			if (content !== null) {
				if ($.isFunction(doneFunc))
					doneFunc(content);
			} else {
				if ($.isFunction(failFunc))
					failFunc('missing');
			}
		}).fail(function(jqXHR, textStatus, errorThrown) {
			console.log('Error when loading page ' + pageTitle + ': ' + errorThrown);
			if ($.isFunction(failFunc))
				failFunc('network');
		});
	},
	edit: function(pageTitle, newRevision, doneFunc, failFunc) {
		$.ajax({
			url: site.apiUrl,
			dataType: 'json',
			type: 'POST',
			data: {
				action: 'edit',
				title: pageTitle,
				summary: msg.edit_summary,
				text: newRevision,
				token: mw.user.tokens.get('csrfToken'),
				format: 'json'
			}
		}).done(function(data) {
			if (data && data.edit && data.edit.result === 'Success') {
				if ($.isFunction(doneFunc))
					doneFunc(content);
			} else {
				if ($.isFunction(failFunc)) {
					if (data && data.error) {
						failFunc(data.error.code ? data.error.code : 'unknown');
					} else if (data && data.edit && data.edit.code) {
						var code = data.edit.code;
						if (code === 'abusefilter-disallowed' || code == 'abusefilter-warning') {
							failFunc(code, data.edit.warning);
						} else {
							failFunc(code);
						}
					} else {
						failFunc('unknown');
					}
				}
			}
		}).fail(function(jqXHR, textStatus, errorThrown) {
			console.log('Error when editing page ' + pageTitle + ': ' + errorThrown);
			if ($.isFunction(failFunc))
				failFunc('network');
		});
	},
	post: function(image) {
		dialog.dl.dialog('close');
		if (dialog.rst && dialog.rst.dialog('isOpen'))
			dialog.rst.dialog('close');
		dialog.rst = $('<p>' + msg.msg_posting + '</p>').dialog({
			title: msg.dialog_title
		});
		var dykcArr = [
				'==== ====',
				'{{ subst:#invoke:Template:DYKEntry|normalize',
				' | article = ' + article.title,
				' | question = ' + dialog.config.dykcQuestion,
				' | image = ' + image,
				' | type = ' + dialog.config.dykcType,
				' | author = ' + dialog.config.dykcAuthor,
				' | nominator = {{subst:REVISIONUSER}}',
				' | timestamp = {{subst:#time:U}}',
				'}}',
				''
			],
			remark = $.trim(dialog.config.dykcRemarks),
			remarkStr = (remark.length ? '** {{Remark}}:' + remark + '\n' : ''),
			dykcStr = dykcArr.join('\n') + remarkStr;
		site.loadPage(site.DYKCPage, function(revision) {
			var	curDate = new Date(),
				curMD = (curDate.getUTCMonth()+1) + '月' + curDate.getUTCDate() + '日',
				dateRe = new RegExp('===\\s*' + curMD + '\\s*===[\\r\\n]*'),
				succeed = true;
			if (!dateRe.test(revision)) {
				dykcStr = '=== ' + curMD + ' ===\n' + dykcStr;
			}
			dykcStr = '\n' + dykcStr;
			// update here if the insertion position has been changed
			// the new nomination will be added BEFORE this match
			var match = /\n==== ====\n{{safesubst:DYKEntry\/auto/.exec(revision);
			if (match === null) {
				window.prompt(msg.dialog_error_format, dykcStr);
				if (dialog.rst && dialog.rst.dialog('isOpen'))
					dialog.rst.dialog('close');
				return null;
			}
			var newText = revision.substring(0, match.index) + dykcStr + revision.substring(match.index, revision.length);
			site.edit(site.DYKCPage, newText, function() {
				dialog.rst.html('<p>' + msg.msg_post_complete +
					'<a href="' + site.articlePage.replace('$1', site.DYKCPage) +
					'">' + msg.msg_dykc + '</a>' + msg.msg_close_this + '</p>');
			}, function(code, warning) {
				if (warning !== undefined) {
					warning = '<p><span style="error">' + msg.dialog_error_af +
						'</span><a href="#" id="dykcAFReturn">' +
						msg.dialog_return + '</a></p>' + warning;
					dialog.rst.html(warning);
					$('#dykcAFReturn').click(function(e) {
						e.preventDefault();
						dialog.rst.dialog('close');
						dialog.dl.dialog('open');
					});
				} else {
					window.prompt(msg.dialog_error(code), dykcStr);
					if (dialog.rst && dialog.rst.dialog('isOpen'))
						dialog.rst.dialog('close');
				}
			});
		});
	}
};

var article = {
	title: mw.config.get('wgPageName'),
	images: null,  // parsed html of images used by the article
	imageTitles: null  // filename (e.g. File:foo.jpg) of images used by the article
};

var img = {
	// Check if there is a <img> in the parsed html.
	isExists: function(imgHTML) {
		return $(imgHTML).find('img').length !== 0;
	},
	// Check if the image exists on commons.wikimedia.org, not on local wiki,
	// for most files on local wiki are non-free and copyrighted.
	isInCommons: function(imgHTML) {
		return ~imgHTML.indexOf('//upload.wikimedia.org/wikipedia/commons/');
	},
	// Normalize input data to something like *File:Foo.jpg* or *Foo.jpg*.
	normalize: function(image, ns) {
		var rst = /^\[\[:?(.*?)(\|.*?)?\]\]/.exec(image);
		if (rst !== null) {
			image = rst[1];
		}
		rst = /^(file|image|文件|[檔档]案)\s*:/i.exec(image);
		if (rst === null && ns) {
			image = 'File:' + image;
		} else if (rst !== null && !ns) {
			image = image.substring(rst[0].length, image.length);
		}
		return image.replace(/[ _]+/g, ' ');
	}
};

var msg;

switch (mw.config.get('wgUserLanguage')) {
	case 'zh-cn':
	case 'zh-hans':
	case 'zh-my':
	case 'zh-sg':
		msg = {
			link_title: '提交新条目推荐候选',
			edit_summary: '[[User:WhitePhosphorus/js/dykc.js|半自动提交]]新条目推荐候选',
			msg_question: '问题',
			msg_type: '类型',
			msg_loading_images: '正在加载条目中的图片……',
			msg_loading_images_failed: '无法加载条目中的图片!',
			msg_no_required_para: '您没有填写以下必填项目:\n\n',
			msg_are_you_sure: '\n\n确定要提交吗?',
			msg_posting: '正在提交,请起身活动一下吧^_^',
			msg_post_complete: '提交完成。您可以前往',
			msg_dykc: '推荐页',
			msg_close_this: '查看,或关闭此对话框留在本页。',
			dialog_title: '提交新条目推荐候选',
			dialog_button_submit: '提交',
			dialog_button_cancel: '取消',
			dialog_button_preview: '预览',
			dialog_question: '问题(必填):',
			dialog_image: '图片(可选):',
			dialog_other_image: '使用下面的图片',
			dialog_type: '类型(可选,建议用英文):',
			dialog_author: '主编(若非一人主编或主编非注册用户,请留空):',
			dialog_remarks: '其他说明(可选,如果填写则需签名):',
			dialog_preview: '预览:',
			dialog_return: '单击返回提交表单',
			dialog_warning_img_invalid: '警告:图片不存在!',
			dialog_warning_img_not_in_commons: '警告:图片不存在于维基共享资源,很可能是合理使用而不能用于首页展示!',
			dialog_warning_img_unused: '警告:图片未被条目使用,不能用于首页展示!',
			dialog_warning_qus_no_marks: '警告:问题中没有出现问号“?”,请加入之,或修正半角问号“?”。',
			dialog_warning_qus_not_bold: '警告:问题中没有加粗条目名!',
			dialog_auto_formatting: '为选中部分加粗、加链接',
			dialog_auto_bolding: '自动修复',
			dialog_warning_qus_no_links: '警告:问题中没有到条目的内部链接,请检查是否繁简不同或使用了重定向。',
			dialog_error: function(code) { return '很抱歉本工具出现问题,未能自动推荐该条目。\n' +
				'您可前往 User talk:WhitePhosphorus 回报出现问题的条目、时间和以下错误原因:' +
				code + '。\n请按下Ctrl+C或command+C来复制下面的代码并手动推荐:' },
			dialog_error_af: '您的编辑已被过滤器拦截。',
			dialog_error_format: '很抱歉因为无法识别新条目推荐候选页的格式,故未能自动推荐该条目。\n' +
				'您可前往 User talk:WhitePhosphorus 回报出现问题的条目和时间。\n' +
				'请按下Ctrl+C或command+C来复制下面的代码并手动推荐:'
		};
		break;
	default:
		msg = {
			link_title: '提交新條目推薦候選',
			edit_summary: '[[User:WhitePhosphorus/js/dykc.js|半自動提交]]新條目推薦候選',
			msg_question: '問題',
			msg_type: '類型',
			msg_loading_images: '正在加載條目中的圖片……',
			msg_loading_images_failed: '無法加載條目中的圖片!',
			msg_no_required_para: '您沒有填寫以下必填項目:\n\n',
			msg_are_you_sure: '\n\n確定要提交嗎?',
			msg_posting: '正在提交,請起身活動一下吧^_^',
			msg_post_complete: '提交完成。您可以前往',
			msg_dykc: '推薦頁',
			msg_close_this: '查看,或關閉此對話框留在本頁。',
			dialog_title: '提交新條目推薦候選',
			dialog_button_submit: '提交',
			dialog_button_cancel: '取消',
			dialog_button_preview: '預覽',
			dialog_question: '問題(必填):',
			dialog_image: '圖片(可選):',
			dialog_other_image: '使用下面的圖片',
			dialog_type: '類型(可選,建議用英文):',
			dialog_author: '主編(若非一人主編或主編非註冊用戶,請留空):',
			dialog_remarks: '其他說明(可選,如果填寫則需簽名):',
			dialog_preview: '預覽:',
			dialog_return: '單擊返回提交表單',
			dialog_warning_img_invalid: '警告:圖片不存在!',
			dialog_warning_img_not_in_commons: '警告:圖片不存在於維基共享資源,很可能是合理使用而不能用於首頁展示!',
			dialog_warning_img_unused: '警告:圖片未被條目使用,不能用於首頁展示!',
			dialog_warning_qus_no_marks: '警告:問題中沒有出現問號“?”,請加入之,或修正半角問號“?”。',
			dialog_warning_qus_not_bold: '警告:問題中沒有加粗條目名!',
			dialog_auto_formatting: '爲選中部分加粗、加鏈接',
			dialog_auto_bolding: '自動修復',
			dialog_warning_qus_no_links: '警告:問題中沒有到條目的內部鏈接,請檢查是否繁簡不同或使用了重新導向。',
			dialog_error: function(code) { return '很抱歉本工具出現問題,未能自動推薦該條目。\n' +
				'您可前往 User talk:WhitePhosphorus 回報出現問題的條目、時間和以下錯誤原因:' +
				code + '。\n請按下Ctrl+C或command+C來複制下面的代碼並手動推薦:' },
			dialog_error_af: '您的編輯已被過濾器攔截。',
			dialog_error_format: '很抱歉因爲無法識別新條目推薦候選頁的格式,故未能自动推荐该条目。\n' +
				'您可前往 User talk:WhitePhosphorus 回报出现问题的条目和时间。\n' +
				'请按下Ctrl+C或command+C来复制下面的代码并手动推荐:'
		};
}

var dialog = {
	dl: null,
	rst: null,
	config: {},
	$: {},
	loadJQueryObjs: function() {
		// Cache often-used JQuery objects.
		dialog.$ = {
			dykcDialog: $('#dykcDialog'),
			dykcQuestion: $('#dykcQuestion'),
			dykcImage: $('#dykcImage'),
			dykcOtherImage: $('#dykcOtherImage'),
			dykcType: $('#dykcType'),
			dykcAuthor: $('#dykcAuthor'),
			dykcRemarks: $('#dykcRemarks'),
			previewImage: $('#previewImage'),
			previewQuestion: $('#previewQuestion'),
			previewRemarks: $('#previewRemarks'),
			warning: $('p[id*="warning"]'),
			warningImg: $('p[id*="warningImg"]'),
			warningQus: $('p[id*="warningQus"]'),
			warningImgInvalid: $('#warningImgInvalid'),
			warningImgUnused: $('#warningImgUnused'),
			warningImgNotInCommons: $('#warningImgNotInCommons'),
			warningQusNoMarks: $('#warningQusNoMarks'),
			warningQusNotBold: $('#warningQusNotBold'),
			warningQusNoLinks: $('#warningQusNoLinks'),
			loadingArticleImages: $('#loadingArticleImages'),
			autoFormatting: $('#autoFormatting'),
			autoBolding: $('#autoBolding')
		};
	},
	updateConfig: function() {
		// Cache everything when the dialog is closed.
		dialog.$.dykcDialog.find("input[id*='dykc'], textarea[id*='dykc'], select[id*='dykc']").each(function(i) {
			dialog.config[this.id] = $(this).val();
		});
		dialog.$.dykcDialog.find("div[id*='preview'], li[id*='preview']").each(function(i) {
			dialog.config[this.id] = $(this).html();
		});
		dialog.$.warning.each(function(i) {
			dialog.config[this.id] = $(this).is(":visible");
		});
	},
	loadCSS: function() {
		dialog.$.dykcDialog.find("select").css("max-width", "97%").css('margin-left', '3%');
		dialog.$.dykcDialog.find("input, textarea").css("width", "97%").css('margin-left', '3%');
		dialog.$.previewQuestion.css('padding-right', '100px');
		dialog.$.previewRemarks.css('padding-right', '100px');
		dialog.$.dykcDialog.find("p[id*=warning]:not(a)").addClass('error');
		// Do not show that when web browser does not support the property
		if (dialog.$.dykcQuestion[0].selectionStart === undefined) {
			dialog.$.autoFormatting.hide();
		}
	},
	loadConfig: function() {
		// Load everything we cached before.
		dialog.$.warning.hide();
		for (var k in dialog.config) {
			if (dialog.config.hasOwnProperty(k)) {
				if (k.startsWith('preview')) {
					dialog.$[k].html(dialog.config[k]);
				} else if (k.startsWith('warning')) {
					if (dialog.config[k])
						dialog.$[k].show();
					else
						dialog.$[k].hide();
				} else {
					dialog.$[k].val(dialog.config[k]);
				}
			}
		}
		// #previewRemarks is hidden by default.
		if (dialog.config.previewRemarks && dialog.config.previewRemarks.length)
			dialog.$.previewRemarks.show();

		if (article.images === null) {
			// The images are still loading.
			dialog.$.loadingArticleImages.show();
			dialog.$.dykcImage.hide();
		}

		dialog.loadCSS();
	},
	bindEvents: function() {
		// When question is modified, do not show the warnings.
		dialog.$.dykcQuestion.on('input selectionchange propertychange', function() {
			dialog.$.warningQus.hide();
		});
		dialog.$.dykcImage.on('change', function() {
			dialog.previewImage();
		});
		dialog.$.autoFormatting.on('click', function() {
			dialog.autoFormatting();
		});
		dialog.$.autoBolding.on('click', function() {
			dialog.autoBolding();
		});
		dialog.$.dykcOtherImage.on('keypress', function() {
			dialog.selectOtherImage();
		});
	},
	init: function() {
		dialog.loadJQueryObjs();
		dialog.bindEvents();
		dialog.loadConfig();
	},
	previewImage: function() {
		dialog.$.warningImg.hide();
		dialog.$.previewImage.html("");
		if (article.images !== null) {
			var index = dialog.$.dykcImage.val();
			if (index.length) {
				dialog.$.previewImage.html(article.images[parseInt(index)]);
				if (!img.isInCommons(article.images[parseInt(index)])) {
					dialog.$.warningImgNotInCommons.show();
				}
			} else {
				var image = $.trim(dialog.$.dykcOtherImage.val());
				if (!image.length)
					return null;
				var imageTitle = img.normalize(image, false);
				image = '[[File:' + imageTitle + '|80px]]';
				site.parse(image, {
					disablelimitreport: '1'
				}, function (data) {
					if (!img.isExists(data)) {
						dialog.$.warningImgInvalid.show();
					} else {
						if (!img.isInCommons(data))
							dialog.$.warningImgNotInCommons.show();
						data = $(data)[0].outerHTML;
						if (article.imageTitles.indexOf(imageTitle) === -1)
							dialog.$.warningImgUnused.show();
						dialog.$.previewImage.html(data);
					}
				});
			}
		}
	},
	previewRemarks: function() {
		dialog.$.previewRemarks
			.html("")
			.hide();
		var text = $.trim(dialog.$.dykcRemarks.val());
		if (!text.length)
			return null;
		site.parse('{{Remark}}:' + text, {
			pst: '1',
			disablelimitreport: '1'
		}, function (data) {
			dialog.$.previewRemarks
				.html(data)
				.show();
		});
	},
	previewQuestion: function() {
		var qusWikitext = dialog.$.dykcQuestion.val();
		site.parse(qusWikitext, {
			disablelimitreport: '1'
		}, function (qusHTML) {
			dialog.$.previewQuestion.html(qusHTML);
			dialog.$.warningQus.hide();
			var $qus = $(qusHTML);
			if (qusHTML.indexOf('?') === -1) {
				dialog.$.warningQusNoMarks.show();
			}
			var linkSelector = 'a[href="' + site.articlePage.replace('$1', encodeURI(article.title.replace(/ /g, '_'))) + '"]';
			if ($qus.find(linkSelector).length === 0) {
				dialog.$.warningQusNoLinks.show();
			} else if ($qus.find('b').find(linkSelector).length === 0) {
				dialog.$.warningQusNotBold.show();
			}
		});
	},
	// Called when the user types something in the input box #otherImage.
	// The user may want to manually specify an image so we select 'other_image' for him.
	selectOtherImage: function() {
		dialog.$.dykcImage.val("");
		dialog.$.previewImage.html("");
		dialog.$.warningImg.hide();
	},
	// Find a link like *[[title]]* and replace them with *'''[[title]]'''*.
	// Something like *''''foo''''* will be parsed to *'<b>foo</b>'* by MediaWiki.
	autoBolding: function() {
		var text = dialog.$.dykcQuestion.val(),
			escapedTitle = article.title.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'),
			titleRe = new RegExp("(\\[\\[:?" + escapedTitle + "(\\|.*?)?\\]\\])");
		dialog.$.dykcQuestion.val(text.replace(titleRe, "'''$1'''"));
		dialog.$.warningQus.hide();
	},
	// Wrap selected text with *'''[[* and *]]'''*.
	autoFormatting: function() {
		var start = dialog.$.dykcQuestion[0].selectionStart,
			end = dialog.$.dykcQuestion[0].selectionEnd,
			qus = dialog.$.dykcQuestion.val();
		if (start !== undefined) {
			if (start === end)
				return null;
			var pre = qus.substring(0, start),
				tar = qus.substring(start, end),
				suf = qus.substring(end, qus.length);
			dialog.$.dykcQuestion.val(pre + "'''[[" + article.title + "|" + tar + "]]'''" + suf);
			dialog.$.warningQus.hide();
			// set cursor at the end of selected string
			dialog.$.dykcQuestion[0].selectionStart =
				dialog.$.dykcQuestion[0].selectionEnd =
				end + 11 + article.title.length;
		}
	}
};

// Load all images used by the article.
// When the dialog is loaded, those images will be listed in the select box.
var loadArticleImages = function() {
	$.ajax({
		url: site.apiUrl,
		data: {
			action: 'query',
			prop: 'images|revisions',
			titles: article.title,
			rvprop: 'content',
			imlimit: 'max',  // 500 should be enough.
			format: 'json'
		}
	}).done(function (data) {
		var allImageTitles = [], revision = '';
		if (data && data.query) {
			var pages = data.query.pages;
			for (var pageid in pages) {
				var page = pages[pageid];
				if ('images' in page) {
					allImageTitles = page.images.map(function(x) { return x.title.substring(5, x.title.length); });
				}
				if (page.revisions && page.revisions.length && page.revisions[0]['*']) {
					revision = page.revisions[0]['*'];
				}
			}
		}
		// The filename (without prefix 'File:') must appear in article text.
		// Or if we failed to get the article text, do not filter anything.
		allImageTitles = !revision.length ? allImageTitles : allImageTitles.filter(function (e) {
			return ~revision.replace(/[ _]+/g, ' ').indexOf(e.substring(5, e.length));
		});
		var imageTitlesStr = '[[File:' + allImageTitles.join('|80px]]\n\n[[File:') + '|80px]]',
			filterArr = [];
		site.parse(imageTitlesStr, {
			disablelimitreport: '1'
		}, function (data) {
			if(!data) return;
			var $data = $(data);
			article.images = $data.find('p, div').toArray().map(function(e) {
				return e.outerHTML;
			}).filter(function(e, i) {
				filterArr[i] = img.isExists(e);
				return filterArr[i];
			});
			article.imageTitles = allImageTitles.filter(function(e, i) { return filterArr[i]; });
			$('#loadingArticleImages').hide();
			$('#dykcImage').show();
		}, function (code) {
			$('#loadingArticleImages').val(msg.msg_loading_images_failed + '(' + code + ')');
		});
	}).fail(function(jqXHR, textStatus, errorThrown) {
		console.log('Error when loading images of ' + article.title + ': ' + errorThrown);
		$('#loadingArticleImages').val(msg.msg_loading_images_failed + 'queryImages');
	});
};

var addDYKCLink = function() {
	$(mw.util.addPortletLink(
		"p-tb",
		"#",
		msg.link_title
	)).click(function(e) {
		e.preventDefault();
		// List images used by the article.
		var imageTitleArr = article.imageTitles.map(function (t, i) {
			return '<option value="' + i + '">' + t + '</option>';
		});
		// This is our html source code of the dialog box.
		// CSS is set in *dialog.loadCSS()* and some events are bound in *dialog.bindEvents()*.
		var html =
			'<div id="dykcDialog" style="line-height:2em">' +
			msg.dialog_question +
			'<div class="floatright"><a id="autoFormatting">' +
			msg.dialog_auto_formatting + '</a></div><br>' +
			'<textarea name="question" id="dykcQuestion" style="resize:vertical" rows=2></textarea>' +
			msg.dialog_image + '<br><span id="loadingArticleImages" style="display:none">' + msg.msg_loading_images + '</span>' +
			'<select name="image" id="dykcImage">' +
			imageTitleArr.join('') +
			'<option value="" selected="selected">' + msg.dialog_other_image + '</option>' +
			'</select><br>' +
			'<input name="otherImage" type="text" id="dykcOtherImage"><br>' +
			msg.dialog_type + '<br>' + '<input name="type" type="text" id="dykcType"><br>' +
			msg.dialog_author + '<br>' +
			'<input name="author" type="text" id="dykcAuthor" value="' + mw.config.get('wgUserName') + '"><br>' +
			msg.dialog_remarks + '<br>' + '<textarea name="remarks" id="dykcRemarks" style="resize:vertical" rows=4></textarea><br>' +
			msg.dialog_preview + '<br>' +
			'<div width="100%"><div id="previewImage" class="floatright"></div>' +
			'<ul><li id="previewQuestion"></li><ul><li id="previewRemarks" style="display:none"></li></ul></ul>' +
			'<p id="warningImgInvalid">' + msg.dialog_warning_img_invalid + '</p>' +
			'<p id="warningImgNotInCommons">' + msg.dialog_warning_img_not_in_commons + '</p>' +
			'<p id="warningImgUnused">' + msg.dialog_warning_img_unused + '</p>' +
			'<p id="warningQusNoMarks">' + msg.dialog_warning_qus_no_marks + '</p>' +
			'<p id="warningQusNotBold">' + msg.dialog_warning_qus_not_bold  +
			'<a id="autoBolding">&gt;&gt; ' + msg.dialog_auto_bolding + '</a>' + '</p>' +
			'<p id="warningQusNoLinks">' + msg.dialog_warning_qus_no_links + '</p>' +
			'</div></div>';
		if (dialog.dl) {
			if (!dialog.dl.dialog('isOpen'))
				dialog.dl.html(html).dialog("open");
		} else {
			dialog.dl = $(html).dialog({
				title: msg.dialog_title,
				minWidth: 515,
				minHeight: 175,
				beforeClose: dialog.updateConfig,
				buttons: [
					{
						text: msg.dialog_button_preview,
						click: function() {
							dialog.previewImage();
							dialog.previewQuestion();
							dialog.previewRemarks();
						}
					},
					{
						text: msg.dialog_button_submit,
						click: function() {
							dialog.updateConfig();
							var empty_para = [];
							if (!dialog.config.dykcQuestion.length)
								empty_para.push(msg.msg_question);
							if (empty_para.length) {
								if (!window.confirm(msg.msg_no_required_para +
									empty_para.join('\n') + msg.msg_are_you_sure)) {
									return null;
								}
							}
							var image = dialog.config.dykcOtherImage;
							if (dialog.config.dykcImage.length)
								image = article.imageTitles[parseInt(dialog.config.dykcImage)];
							site.post(image);
						}
					},
					{
						text: msg.dialog_button_cancel,
						click: function() { $(this).dialog('close'); }
					}
				]
			});
		}
		dialog.init();
	});
};

if (mw.config.get('wgCanonicalNamespace') === '' && mw.config.get('wgArticleId') !== 0) {
	loadArticleImages();
	addDYKCLink();
}

})(jQuery, mw);
//</nowiki>