For faster navigation, this Iframe is preloading the Wikiwand page for User:Chiefwei/rater/rater-t.js.

User:Chiefwei/rater/rater-t.js

//简体中文用户请使用 User:Chiefwei/rater/rater.js
//原始地址:en:User:Kephir/gadgets/rater.js 版本:2012-11-11
/*jshint shadow:true, latedef:true, boss:true, scripturl:true, loopfunc:true, undef:true */
/*global $, mw, importStylesheet, wgScript, wgNamespaceIds, wgFormattedNamespaces, wgNamespaceNumber, wgPageName, wgTitle, wgAction */
mw.loader.using(['mediawiki.api', 'mediawiki.Title', 'jquery.ui'], function () {
	"use strict";
	if (mw.config.get('wgNamespaceNumber') < 0)
		return;
	
	mw.loader.load('/wiki/User:Chiefwei/rater/rater.css?action=raw&ctype=text/css', 'text/css');
	
	/*
	== 程式碼 ==
	 */
	var api = new mw.Api();
	
	/*
	=== 模板資料 ===
	 */
	var raterData = {};
	var dataurl ='';
	function getRaterData(kind) {
		if (kind === 'default') {
			dataurl = mw.config.get('wgScript') + '?action=raw&ctype=application/json&maxage=86400&title=User:Chiefwei/rater/' + kind + '.js';
		} else {
			dataurl = mw.config.get('wgScript') + '?action=raw&ctype=application/json&maxage=86400&title=User:Sz-iwbot/rater/' + kind + '.json';
		}
		if (raterData[kind] === void(null)) {
			try {
				$.ajax({
					'url': dataurl,
					'dataType': 'json',
					'async': false,
					'success': function (data) {
						raterData[kind] = data;
					},
					'error': function (xhr, message) {
						mw.log.error(new Error(message));
					}
				});
			}  catch (e) {
				alert('獲取評級工具“' + kind + '”資料錯誤:' + e.message + '。評級工具可能無法正常工作。');
				raterData[kind] = null;
			}
		}
		return raterData[kind];
	}
	
	var projectKeywords = null;
	
	function getKeywordsMapping() {
		if (projectKeywords === null) {
			var projects = getRaterData('projects-t');
			projectKeywords = {};
			for (var key in projects) {
				for (var i = 0; i < projects[key].length; ++i) {
					projectKeywords[projects[key][i].toLowerCase()] = key;
				}
			}
		}
		return projectKeywords;
	}
	
	function cloneInto(what, target) {
		if (typeof what === 'object') {
			if (what === null)
				return what;
			if ((target === null) || (typeof target !== 'object'))
				target = {};
			for (var key in what) {
				target[key] = cloneInto(what[key], target[key]);
			}
			return target;
		} else
			return what;
	}
	
	function clone(what) {
		return cloneInto(what, null);
	}
	
	var projectData = {};
	function getTemplateInfo(name) {
		if (projectData[name] === void(null)) {
			try {
				$.ajax({
					'url': mw.config.get('wgScript') + '?action=raw&ctype=application/json&maxage=86400&title=Template:' + name + '/rater-data.js',
					'dataType': 'json',
					'async': false,
					'success': function (data) {
						projectData[name] = data;
					},
					'error': function (xhr, message) {
						if (xhr.status === 404) { // just pretend nothing happened.
							projectData[name] = null;
							return;
						}
						mw.log.error(new Error(message));
					}
				});
			}  catch (e) {
				alert('獲取模板“' + name + '”資料錯誤:' + e.message + '。如果您力所能及請修復之。正在回滾至預設資料,可能未必準確。');
				projectData[name] = null;
			}
		}
		return projectData[name];
	}
		
	function wantedTemplate(name) {
		var projects = getRaterData('projects-t');
		return name in projects;
	}
	
	function normaliseTitle(name) {
		var aliases = getRaterData('aliases');
		name = (new mw.Title(name)).getMainText();
		if (aliases[name])
			name = aliases[name];
		return name;
	}
	
	/*
	=== 模板物件 ===
	 */
	function ProjectTemplate(name, params, postws) {
		var sumtrack = {};
		var isnew = (params === null);
		var dropped = false;
		var tpinfo = getTemplateInfo(name);
		var defdata = getRaterData('default-t');
		var fallback;
	
		if (tpinfo === null || typeof(tpinfo) === 'undefined') {
			tpinfo = {};
			fallback = true;
		}
		tpinfo = cloneInto(tpinfo, clone(defdata));
	
		// make data nice
		if (tpinfo.taskforces) {
			if (tpinfo.taskforces.items) {
				var newtf = [];
				for (var key in tpinfo.taskforces.items) {
					var tfe = {
						'name': tpinfo.taskforces.items[key],
						'part': (typeof tpinfo.taskforces.partsuf === 'string') ? key + tpinfo.taskforces.partsuf : null,
						'prio': (typeof tpinfo.taskforces.priosuf === 'string') ? key + tpinfo.taskforces.priosuf : null
					};
					newtf[newtf.length] = tfe;
				}
				tpinfo.taskforces = newtf;
			}
		} else
			tpinfo.taskforces = [];
	
		for (var key in tpinfo.params)
			if (tpinfo.params[key] === null)
				delete tpinfo.params[key];
	
		for (var i = 0; i < tpinfo.taskforces.length; ++i) {
			var tf = tpinfo.taskforces[i];
			if (tf.part) {
				tpinfo.params[tf.part] = cloneInto(tpinfo.params[tf.part] || {}, {
					'group': 'task'
				});
			}
			if (tf.prio) {
				tpinfo.params[tf.prio] = cloneInto(tpinfo.params[tf.prio] || {}, {
					'group': 'task'
				});
			}
			if (tf.prio && tf.part) {
				tpinfo.params[tf.prio].implies = tf.part;
			}
		}
	
		params = params || {};
	
		// process params
		for (var key in params) {
			if ((key in tpinfo.params) && (tpinfo.params[key].alias)) {
				params[tpinfo.params[key].alias] = params[key];
				delete params[key];
			}
		}
	
		this.isFallback = function () {
			return fallback;
		};
	
		this.getParam = function (key) {
			return key in params ? params[key] : null;
		};
		
		this.setParam = function (key, value) {
			if ((value === null) || (value === void(null)))
				return this.delParam(key);
			params[key] = String(value);
			sumtrack[key] = String(value);
			return value;
		};
		
		this.delParam = function (key) {
			delete params[key];
			sumtrack[key] = false;
			return void(null);
		};
	
		this.serialise = function () {
			if (dropped)
				return '';
			var result = '((' + name;
			for (var key in params) {
				result += ' |' + key + '=' + params[key];
			}
			return result + '))' + postws;
		};
		
		this.getChanges = function () {
			if (dropped)
				return isnew ? '' : '-' + this.getProjectName();
			var result = [];
			for (var key in sumtrack) {
				if (sumtrack[key] !== false)
					result[result.length] = key + '=' + sumtrack[key];
				else
					result[result.length] = '-' + key;
			}
			if (!result.length) {
				if (isnew)
					return '+' + this.getProjectName();
				return void(null);
			}
			return (isnew ? '+' : '') + this.getProjectName() + ': ' + result.join(", ");
		};
		
		this.getProjectName = function () {
			if (tpinfo.name)
				return tpinfo.name;
			return name.replace(/^WikiProject /, '');
		};
		
		this.getTemplateName = function () {
			return name;
		};
		
		this.getParamData = function (key) {
			var defParamData = {
				'desc': key,
				'group': (key in tpinfo.params) ? 'main' : 'unk',
				'mandatory': false,
				'obsolete': false,
				'values': 'string',
				'defvalue': (key in tpinfo.params) ? 
					( (tpinfo.params[key].values === 'flag-temp') ? 'y'
					: (tpinfo.params[key].values === 'flag-perm') ? 'n'
					: ''
				) : ''
			};
			return cloneInto(tpinfo.params[key] || {}, defParamData);
		};
		
		this.drop = function () {
			return dropped = !dropped;
		};
	
		this.forEachParam = function (walker) {
			for (var key in tpinfo.params) {
				if (tpinfo.params[key].alias)
					continue;
				if (walker(key, key in params ? params[key] : null, this.getParamData(key)))
					return;
			}
			for (var key in params) {
				if (!(key in tpinfo.params))
					if (walker(key, params[key], this.getParamData(key)))
						return;
			}
		};
		
		this.forEachTaskForce = function (walker) {
			for (var i = 0; i < tpinfo.taskforces.length; ++i) {
				var tf = tpinfo.taskforces[i];
				if (walker(tf.name, this.getParam(tf.part), this.getParam(tf.prio), tf.part, tf.prio))
					return;
			}
		};
	}
	
	/*
	=== 介面 ===
	 */
	function UserInterface() {
		if (this === window)
			return new UserInterface();
	
		var self = this;
	
		function el(tag, child, attr, events) {
			var node = document.createElement(tag);
	
			if (child) {
				if (typeof child !== 'object')
					child = [child];
				for (var i = 0; i < child.length; ++i) {
					var ch = child[i];
					if ((ch === void(null)) || (ch === null))
						continue;
					else if (typeof ch !== 'object')
						ch = document.createTextNode(String(ch));
					node.appendChild(ch);
				}
			}
	
			if (attr) for (var key in attr) {
				node.setAttribute(key, String(attr[key]));
			}
	
			if (events) for (var key in events) {
				if(node)node.addEventListener(key, events[key], false);
			}
	
			return node;
		}
	
		function link(child, href, attr, ev) {
			attr = attr || {};
			ev = ev || {};
			if (typeof href === 'string')
				attr.href = href;
			else {
				attr.href = 'javascript:void(null);';
				ev.click = href;
			}
			return el('a', child, attr, ev);
		}
	
		function pform(child, handler, attr) {
			attr = attr || {};
			attr.action = 'javascript:void(null);';
			return el('form', child, attr, { 'submit': handler });
		}
		
		var pluckedData = [];
		var tab = [null, null, null];
		
		var tabIsFresh = [false, false, false];
		var uiSource, uiPreview, uiStatus, uiTemplates, uiSummary, uiAddTemplName;
		var dirtySummary = false;
		
		var curTab = 0;
		function setTab(target) {
			tab[curTab].style.display = 'none';
			tab[curTab = target].style.display = '';
		}
		
		function switchTab(target) {
			if (!tabIsFresh[target]) {
				if (target === 2) { // preview
					var source = tabIsFresh[1] ? uiSource.value : serialise();
					api.post({
						'action': 'parse',
						'title': talkpage,
						'text': source,
						'pst': '1',
						'prop': 'text'
					}, {
						success: function (result) {
							uiPreview.innerHTML = result.parse.text['*']; // XXX
							setTab(target);
							tabIsFresh[2] = true;
						},
						error: function () {
							self.setStatus('渲染錯誤。');
						}
					});
					return;
				} else if (target === 1) { // source
					if (tabIsFresh[0]) {
						uiSource.value = serialise();
					}
				} else if (target === 0) { // editor
					try {
						self.extract(uiSource.value);
					} catch (e) {
						self.setStatus(e.message + ' — 請編輯原始碼並重試。');
						return;
					}
				}
				tabIsFresh[target] = true;
			}
			
			setTab(target);
		}
		
		function tabSwitcher(target) {
			return function (ev) {
				switchTab(target);
			};
		}
		
		function serialise() {
			var result = '';
			for (var i = 0; i < pluckedData.length; ++i) {
				if (typeof pluckedData[i] === 'string')
					result += pluckedData[i];
				else if (pluckedData[i].serialise)
					result += pluckedData[i].serialise();
			}
			return result;
		}
		
		function gatherSummary() {
			var sums = [];
			for (var i = 0; i < pluckedData.length; ++i) {
				if (pluckedData[i].getChanges) {
					var ch = pluckedData[i].getChanges();
					if (ch) sums[sums.length] = ch;
				}
			}
			return '評級:' + sums.join('; ') + '([[User:Chiefwei/rater|工具協助]])';
		}
	
		var lastTemplate;
		var contig;
	
		var uiProjList = el('datalist');
		(function () {
			var projects = getRaterData('projects-t');
			for (var key in projects) {
				for (var k in projects[key]) {
					var pname = projects[key][k] || key.replace(/^WikiProject /, '');
					uiProjList.appendChild(el('option', [pname], { 'value': pname }));
				}
			}
		})();
		
		var uiBox = el('div', [
			// header
			el('h4', ['評級',
				el('span', ['\u00a0[', link('關閉', function (ev) {
					ev.preventDefault();
					self.show(false);
				}), ']'], { 'class': 'editsection' }),
				el('span', ['\u00a0[',
					'β (2012-11-11) | ',
					link('關於', mw.util.getUrl('en:User:Kephir/gadgets/rater'), { 'title': '關於本小工具' }), ' | ',
					link('中文化', mw.util.getUrl('User:Chiefwei/rater'), { 'title': '中文化者頁面' }), ' | ',
					link('回饋', mw.util.getUrl('en:User talk:Kephir/gadgets/rater'), { 'title': '向作者回饋' }),
				']'], { 'class': 'editsection' })
			]),
				
			// tabs
			el('ul', [
				el('li', [link('編輯' , tabSwitcher(0))]),
				el('li', [link('原碼' , tabSwitcher(1))]),
				el('li', [link('預覽', tabSwitcher(2))])
			], { 'class': 'tabs' }),
				
			// body: main
			tab[0] = el('div', [
				uiTemplates = el('ul'),
				el('div', [
					'附注',
					el('ul', [
						el('li', [
							'部分專題模板(標示', el('span', '如此', { 'class': 'fallback' }),
							')缺少評級資料,故已使用預設資料,但可能無法正確對應模板所能識別的實際參數。例如,部分專題橫幅未適用重要度或圖片/資訊框請求等欄位,亦可能使用了特殊名稱。請使用預覽功能以檢查參數是否受正確識別,並使用原始碼編輯器修正,亦可點選[編輯]連結填寫模板評級資料。添加其他非評級討論頁模板時,請將評級參數按照預設留空,並填寫該模板所含欄位。', link('請清除瀏覽器快取', mw.util.getUrl('WP:BYPASS')), '以確保評級工具使用最新的模板資料。'
						])
					])
				], { 'class': 'notes' }),
				el('form', [
					uiAddTemplName = el('input', null, {
						'type': 'text',
						'size': '30',
						'placeholder': '專題名、模板名、關鍵字或縮寫',
						'class': 'name'
					}),
					el('input', null, {
						'type': 'submit',
						'value': '添加'
					})
				], { 'action': 'javascript:void(0);', 'class': 'new-template' }, {
					'submit': function (ev) {
						var name = uiAddTemplName.value;
						if (!name)
							return;
						var keywords = getKeywordsMapping();
						if (keywords[name.toLowerCase()])
							name = keywords[name.toLowerCase()];
						name = normaliseTitle(name);
						if (!wantedTemplate(name))
							name = 'WikiProject ' + name;
						if (!wantedTemplate(name)) {
							if (!confirm('“' + uiAddTemplName.value + '”無法與已知專題關聯。是否依然添加?'))
								return;
						}
						var ptpl = new ProjectTemplate(name, null, '\n');
						pluckedData.splice(++lastTemplate, 0, ptpl);
						uiTemplates.appendChild(createUIForProjectTemplate(ptpl, true));
						tabIsFresh[1] = tabIsFresh[2] = false;
						uiAddTemplName.value = '';
						if (!dirtySummary) {
							uiSummary.value = gatherSummary();
						}
					}
				})
			]),
				
			// body: source
			tab[1] = el('div', [
				uiSource = el('textarea', null, {
					'rows': 15,
					'cols': 70
				}, {
					'keypress': function () {
						tabIsFresh[0] = tabIsFresh[2] = false;
						if (!dirtySummary) {
							dirtySummary = true;
							uiSummary.classList.add('dirty');
							uiSummary.value = '修改討論頁頂部([[User:Chiefwei/rater|工具協助]])';
						}
					},
					'change': function () {
						tabIsFresh[0] = tabIsFresh[2] = false;
						if (!dirtySummary) {
							dirtySummary = true;
							uiSummary.classList.add('dirty');
							uiSummary.value = '修改討論頁頂部([[User:Chiefwei/rater|工具協助]])';
						}
					}
				})
			]),
	
			// body: preview
			tab[2] = el('div', [
				uiPreview = el('div')
			]),
	
			el('br', null, { 'class': 'before-footer' }),
	
			// footer
			el('div', [
				el('div', [
					el('label', '編輯摘要:'),
					uiSummary = el('input', null, {
						'type': 'text',
						'size': '60'
					}, { 'keypress': function (ev) {
						if (!dirtySummary) {
							dirtySummary = true;
							this.classList.add('dirty');
						}
					)))
				]),
				el('span', [uiStatus = document.createTextNode('')], { 'class': 'status-line' }),
				el('input', null, {
					'type': 'button',
					'value': '儲存',
					'class': 'save-button'
				}, { 'click': function (ev) {
					var summary = uiSummary.value;
					var markup = (curTab === 0) ? serialise() : uiSource.value;
					self.setStatus('正在送出……');
					self.save(markup, summary, {
						success: function () {
							self.setStatus('已更新');
							setTimeout(function () {
								self.show(false);
							}, 1500);
						},
						error: function () {
							console.error(arguments);
							self.setStatus('錯誤');
						}
					});
				} }),
				el('br')
			], { 'class': 'bottom' }),
				
			// nothing
			null
		], { 'class': 'kephir-rater' });
		
		$(uiBox).draggable().resizable(); // XXX: jQuery sucks
		tab[0].style.display = tab[1].style.display = tab[2].style.display = 'none';
	
		function createUIForProjectTemplate(tp, expanded) {
			var paramWidget = {};
			
			function normaliseBool(value) {
				if (typeof value === 'boolean')
					return value;
				if ((value === '1') || (value === 'Y') || (value === 'y') || (value.toLowerCase() === 'yes'))
					return true;
				if ((value === '0') || (value === 'N') || (value === 'n') || (value.toLowerCase() === 'no'))
					return false;
				mw.log.error(new Error("無法正常化布林值"));
			}
			
			function updateValue(param, value) {
				tabIsFresh[1] = tabIsFresh[2] = false;
				tp.setParam(param, value);
				if (!dirtySummary) {
					uiSummary.value = gatherSummary();
				}
			}
	
			var grph = { };
			function createWidget(name, value, data) {
				var widget;
				
				var dataTypes = {
					'flag-temp': function () {
						widget = el('input', null, { 'type': 'checkbox' });
						widget.checked = normaliseBool(value);
						widget.addEventListener('change', function () {
							updateValue(name, this.checked ? 'yes' : null);
						}, false);
					},
					'flag-perm': function () {
						widget = el('input', null, { 'type': 'checkbox' });
						widget.checked = normaliseBool(value);
						widget.addEventListener('change', function () {
							updateValue(name, this.checked ? 'yes' : 'no');
						}, false);
					},
					'flag-inv': function () {
						widget = el('input', null, { 'type': 'checkbox' });
						widget.checked = !normaliseBool(value);
						widget.addEventListener('change', function () {
							updateValue(name, this.checked ? 'no' : 'yes');
						}, false);
					},
					'string': function () {
						widget = el('input', null, { 'type': 'text' });
						widget.value = value;
						widget.addEventListener('change', function () {
							updateValue(name, this.value);
						}, false);
						widget.addEventListener('keypress', function () {
							updateValue(name, this.value);
						}, false);
					},
					'class-std': {
						'list': ['', 'Stub', 'Start', 'C', 'B', 'GA', 'A', 'FA', 'List', 'FL', 'Disambig', 'NA'],
						'normalise': 'mlc'
					},
					'class-ext': {
						'list': ['', 'Stub', 'Start', 'C', 'B', 'GA', 'A', 'FA', 'List', 'FL', 'NA', 'Category', 'Disambig', 'File', 'Portal', 'Project', 'Template'],
						'normalise': 'mlc'
					},
					'class-ext-list': {
						'list': ['', 'Stub', 'Start', 'C', 'B', 'GA', 'A', 'FA', 'SL', 'List', 'CL', 'BL', 'AL', 'FL'],
						'normalise': 'mlc'
					},
					'importance-std': {
						'list': ['', 'Low', 'Mid', 'High', 'Top', 'NA', 'Bottom', 'Unknown'],
						'normalise': 'mlc'
					},
					'importance-lit': {
						'list': ['', 'Low', 'Mid', 'High', 'Top'],
						'normalise': 'mlc'
					},
					'b-checklist': { 
						'list': ['', 'yes', 'no', 'n/a'], 
						'normalise': 'mlc' 
					}
				};
				var uiName = el('span', [data.desc]);
				var uiHelp = null;
				
				if (typeof data.values === 'string') {
					try {
						if (typeof dataTypes[data.values] === 'function')
							dataTypes[data.values]();
						else if (dataTypes[data.values])
							data.values = dataTypes[data.values];
						else
							dataTypes.string();
					} catch (e) {
						dataTypes.string();
					}
				}
	
				if (data.values.list) {
					widget = el('select');
					
					var vlist;
					if (data.values.list instanceof Array) {
						vlist = data.values.list;
						for (var i = 0; i < vlist.length; ++i) {
							widget.appendChild(el('option', [vlist[i]], { 'value': vlist[i] }));
						}
					} else {
						vlist = Object.keys(data.values.list);
						for (var key in data.values.list) {
							widget.appendChild(el('option', [data.values.list[key]], { 'value': key }));
						}
					}
					
					if (data.values.normalise) {
						value = value || '';
						switch (data.values.normalise) {
						case 'lc':
							value = value.toLowerCase();
							break;
						case 'mlc':
							for (var i = 0; i < vlist.length; ++i) {
								if (vlist[i].toLowerCase() === value.toLowerCase()) {
									value = vlist[i];
									break;
								}
							}
							break;
						}
					}
	
					if (data.values.aliases) {
						if (value in data.values.aliases) {
							value = data.values.aliases[value];
						}
					}
	
					if (vlist.indexOf(value) === -1) {
						dataTypes.string();
						// TODO: datalist
					} else {
						widget.value = value;
						widget.addEventListener('change', function () {
							updateValue(name, this.value);
						}, false);
					}
				}
	
				// TODO: datalist
	
				if (data.obsolete) {
					uiName.classList.add('obsolete');
					uiName.title = 'This parameter is obsolete.';
				}
				
				if (data.helplink) {
					uiHelp = el('span', ['[', link('?', mw.util.getUrl(data.helplink)), ']']);
				}
	
				paramWidget[name] = widget;
				return el('li', [uiName, uiHelp && ' ', uiHelp, ':', widget]);
			}
			
			function createPlaceholder(name, data) {
				var pholder = el('li', [paramWidget[name] = link(data.desc, function (ev) {
					tabIsFresh[1] = tabIsFresh[2] = false;
					tp.setParam(name, data.defvalue);
					if (grph[data.group])
						grph[data.group].classList.remove('absent');
					var widget = createWidget(name, data.defvalue, data);
					pholder.parentNode.insertBefore(widget, pholder);
					pholder.parentNode.removeChild(pholder);
					if (!dirtySummary) {
						uiSummary.value = gatherSummary();
					}
				})], { 'class': 'absent' });
				return pholder;
			}
			
			function createWidgetTF(tfname, part, prio, partpname, priopname, prioscale) {
				var uiCheck = null, uiCombo = null;
	
				if (partpname !== null) {
					uiCheck = el('input', null, { 'type': 'checkbox' });
					try {
						uiCheck.checked = normaliseBool(part);
					} catch (e) {
						uiCheck.checked = true;
					}
					uiCheck.addEventListener('change', function (w) {
						updateValue(partpname, this.checked ? 'yes' : null);
					}, false);
					paramWidget[partpname] = uiCheck;
				}
	
				if (priopname !== null) {
					var items = prioscale || ["", "Top", "High", "Mid", "Low", "Unknown"]; // XXX
					uiCombo = el('select');
					for (var i = 0; i < items.length; ++i) {
						uiCombo.appendChild(el('option', [items[i]], { 'value': items[i] }));
					}
					uiCombo.value = prio;
					uiCombo.addEventListener('change', function () {
						updateValue(priopname, this.value);
					}, false);
					paramWidget[priopname] = uiCombo;
				}
	
				return el('li', [uiCheck, tfname, uiCombo && ': ', uiCombo]);
			}
	
			function createPlaceholderTF(tfname, partpname, priopname) {
				var pholder = el('li', [ paramWidget[priopname] = paramWidget[partpname] = link(tfname, function (ev) {
					if (partpname) tp.setParam(partpname, 'y');
					if (priopname) tp.setParam(priopname, '');
					var widget = createWidgetTF(tfname, true, '', partpname, priopname);
					grph.task.classList.remove('absent');
					pholder.parentNode.insertBefore(widget, pholder);
					pholder.parentNode.removeChild(pholder);
					if (!dirtySummary) {
						uiSummary.value = gatherSummary();
					}
				})], { 'class': 'absent' });
				return pholder;
			}
	
			var uiParams, uiGroups, uiDel;
			var ui = el('li', [
				uiDel = link('(delete)', function () {
					if (tp.drop())
						ui.classList.add('dropped');
					else
						ui.classList.remove('dropped');
					tabIsFresh[1] = tabIsFresh[2] = false;
					if (!dirtySummary)
						uiSummary.value = gatherSummary();
				}, { 'class': 'delete-template' }),
				el('b', [link(tp.getProjectName(), mw.util.getUrl('Template:' + tp.getTemplateName()))]),
				el('small', [' [', link('編輯', '/wiki/Template:' + tp.getTemplateName() + '/rater-data.js?action=edit&editintro=User:Chiefwei/rater/data-editnotice&preload=User:Chiefwei/rater/data-preload'), ']'], { 'class': 'absent', 'title': 'Edit data' }), ':',
				uiParams = el('ul', [], { 'class': 'params' }),
				uiGroups = el('dl', [], { 'class': 'p-groups' })
			], { 'class': 'template-entry' });
			var grpNames = {
				'vis' : '外觀',
				'req' : '請求',
				'task': '工作組',
				'misc': '其他',
				'unk' : '未識別'
			};
			var grps = {
				'main': uiParams
			};
			var grpl = {
				'main': null
			};
			
			function addGroup(tag) {
				uiGroups.appendChild(grph[tag] = el('dt', grpNames[tag] || tag, { 'class': 'absent' }));
				uiGroups.appendChild(el('dd', [grps[tag] = el('ul', null, { 'class': 'params' })]));
				return grps[tag];
			}
	
			if (!expanded) {
				ui.classList.add('hide-absent');
			}
	
			if (tp.isFallback()) {
				ui.classList.add('fallback');
			}
			
			tp.forEachParam(function (name, value, data) {
				if (data.group === 'task')
					return;
				if (!grps[data.group])
					addGroup(data.group);
				if ((value === null) && !data.mandatory)
					if (!data.obsolete)
						grps[data.group].appendChild(createPlaceholder(name, data));
					else;
				else {
					grps[data.group].appendChild(createWidget(name, value, data));
					if (grph[data.group])
						grph[data.group].classList.remove('absent');
				}
			});
			
			tp.forEachTaskForce(function (tfname, part, prio, partpname, priopname) {
				var item;
				if (!grps.task) addGroup('task');
				if (partpname && (part === null))
					item = createPlaceholderTF(tfname, partpname, priopname);
				else {
					item = createWidgetTF(tfname, part, prio, partpname, priopname);
					grph.task.classList.remove('absent');
				}
				grps.task.appendChild(item);
			});
			
			var uiNewCustParmName;
			ui.appendChild(el('div', [
				el('form', [
					uiNewCustParmName = el('input', null, { 'type': 'text', 'placeholder': '新自訂參數', 'size': 20 }),
					el('input', null, { 'type': 'submit', 'value': '添加' })
				], { 'action': 'javascript:void(0);', 'class': 'new-custom-param' }, {
					'submit': function (ev) {
						var nname = uiNewCustParmName.value;
						tabIsFresh[1] = tabIsFresh[2] = false;
						if (paramWidget[nname]) {
							if (paramWidget[nname].tagName === 'A') { // XXX - placeholder
								paramWidget[nname].click();
							} else {
								// reactivate if deleted (deleting not implemented yet)
								paramWidget[nname].focus();
							}
						} else {
							var pd = tp.getParamData(nname);
							tp.setParam(nname, '');
							(grps[pd.group] || addGroup(pd.group)).appendChild(createWidget(nname, '', pd));
							if (!dirtySummary) {
								uiSummary.value = gatherSummary();
							}
						}
						uiNewCustParmName.value = '';
					}
				})
			], { 'class': 'absent' }));
	
			var hidelink, hltext;
			uiParams.appendChild(hidelink = link([hltext = document.createTextNode('[+]')], function () {
				if (!ui.classList.contains('hide-absent')) {	
					ui.classList.add('hide-absent');
					hltext.data = '[+]';
				} else {
					ui.classList.remove('hide-absent');
					hltext.data = '[–]';
				}
			}));
	
			return ui;
		}
		
		this.clear = function () {
			dirtySummary = false;
			uiSummary.value = '';
			uiSummary.classList.remove('dirty');
		};
	
		this.extract = function (markup) {
			var m;
	
			pluckedData = [];
			lastTemplate = -1;
			contig = true;
	
			while (uiTemplates.hasChildNodes())
				uiTemplates.removeChild(uiTemplates.firstChild);
			
			uiSource.value = markup;
			tabIsFresh[1] = true;
	
			try {
				// TODO: Parsoid?
				while (markup !== '') {
					if (!(m = /^([^]*?)\{\{\s*((?:\}[^\}\|]|[^\}\|])+?)\s*(?=\||)))/.exec(markup))) {
						pluckedData[pluckedData.length] = markup;
						break;
					}
					var name = normaliseTitle(m[2]);
					if (!wantedTemplate(name)) {
						pluckedData[pluckedData.length] = markup.substr(0, m[0].length);
						markup = markup.substr(m[0].length);
						continue;
					}
					pluckedData[pluckedData.length] = m[1];
					var params = {};
					var postws = '';
					markup = markup.substr(m[0].length);
					var ppid = 1;
	
					for (;;) {
						if (m = /^\s*))(\s*)/.exec(markup)) {
							postws = m[1];
							markup = markup.substr(m[0].length);
							break;
						} else if (m = /^\s*\|\s*([^=\|]+?)\s*=\s*(.*?)\s*(?=\||)))/.exec(markup)) {
							markup = markup.substr(m[0].length);
							params[m[1]] = m[2];
						} else if (m = /^\s*\|\s*(.*?)\s*(?=\||)))/.exec(markup)) {
							markup = markup.substr(m[0].length);
							params[ppid++] = m[1];
						} else {
							mw.log.error(new Error('“' + name + '”錯誤的模板呼叫'));
						}
					}
					
					if (lastTemplate !== (pluckedData.length - 1))
						contig = false;
	
					var ptpl = new ProjectTemplate(name, params, postws);
					pluckedData[lastTemplate = pluckedData.length] = ptpl;
					uiTemplates.appendChild(createUIForProjectTemplate(ptpl));
				}
	
				tabIsFresh[0] = true;
				setTab(0);
			} catch (e) {
				this.setStatus('解析' + e.message + '時出錯,請修復原始碼並重試。');
				setTab(1);
			}
		};
			
		this.save = function (markup, summary, handlers) {
			alert('@!#?@!\n' + summary + '\n' + markup);
		};
	
		this.show = function (value) {
			uiBox.style.display = value ? '' : 'none';
			if (value) {
				if (curTab === 0)
					uiAddTemplName.focus();
				else if (curTab === 1)
					uiSource.focus();
			}
		};
		
		this.install = function (where) {
			function uniqid() {
				var s = '', cs = 'QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm1234567890.-';
				for (var i = 0; i < 24; ++i) {
					s += cs.charAt(Math.floor(Math.random() * cs.length));
				}
				return s;
			}
			where.appendChild(uiBox);
			where.appendChild(uiProjList);
			uiProjList.id = 'kephir-rater-' + uniqid();
			uiAddTemplName.setAttribute('list', uiProjList.id);
		};
		
		this.setStatus = function (message, level) {
			uiStatus.data = message;
		};
		
		return this;
	}
	
	/*
	=== Glue ===
	 */
	var api = new mw.Api();
	
	var ui = new UserInterface();
	ui.show(false);
	ui.install(document.body);
	
	var talkpage = mw.config.get('wgFormattedNamespaces')[mw.config.get('wgNamespaceNumber') - (mw.config.get('wgNamespaceNumber') % 2) + 1] + ':' + mw.config.get('wgTitle');
	
	var link = mw.util.addPortletLink(mw.config.get('skin') === 'vector' ? 'p-views' : 'p-cactions',
		'javascript:void(0);', '評級', 'p-kephir-rater', '使用工具為條目評級', '5'
	);
	if(link) {
	link.addEventListener('click', function (ev) {
		ev.preventDefault();
		api.get({
			action: 'query',
			prop: 'info|revisions',
			rvprop: 'timestamp|content',
			rvsection: 0,
			rvlimit: 1,
			rvdir: 'older',
			meta: 'tokens',
			titles: talkpage
		}, {
			success: function (result) {
				var tpgpid = Object.keys(result.query.pages)[0];
				var tpg = result.query.pages[tpgpid];
				var tpgstart = tpg.starttimestamp;
				var tpgtoken = result.query.tokens.csrftoken;
				var tpgbase = tpg.revisions ? tpg.revisions[0].timestamp : void(0);
				var tpgrev = tpg.lastrevid;
				ui.save = function (markup, summary, handlers) {
					api.post({
						action: 'edit',
						section: 0,
						title: talkpage,
						basetimestamp: tpgbase,
						starttimestamp: tpgstart,
						token: tpgtoken,
						notminor: true,
						summary: summary,
						watchlist: 'nochange',
						text: markup,
						tags: 'rater'
					}, handlers);
				};
				ui.clear();
				ui.extract(tpg.revisions ? tpg.revisions[0]['*'] : '');
				ui.show(true);
			},
			error: function () {
				console.error(arguments);
				alert('錯誤,參見主控台。');
			}
		});
	}, false);
	}
	
	if (/^Category:(Unassessed|Unknown-importance)_.*?_articles$/.test(mw.config.get('wgPageName'))) {
		var links = document.getElementById('mw-pages').getElementsByTagName('a');
		for (var i = 0; i < links.length; ++i)
			links[i].href = links[i].href.replace(/\/wiki\/Talk:/, '/wiki/');
	}
	 
	if ((mw.config.get('wgNamespaceNumber') === mw.config.get('wgNamespaceIds').template) && /\/rater-data\.js$/.test(mw.config.get('wgPageName'))) {
		mw.config.set('wgCodeEditorCurrentLanguage', 'json');
		mw.loader.load('ext.codeEditor');
		if (Object.defineProperty)
			Object.defineProperty(window, 'syntaxHighlighterConfig', {
				'set': function () { }
			});
		else if (window.__defineSetter__)
			window.__defineSetter__('syntaxHighlighterConfig', function () { });
	}
	
	});
{{bottomLinkPreText}} {{bottomLinkText}}
User:Chiefwei/rater/rater-t.js
Listen to this article

This browser is not supported by Wikiwand :(
Wikiwand requires a browser with modern capabilities in order to provide you with the best reading experience.
Please download and use one of the following browsers:

This article was just edited, click to reload
This article has been deleted on Wikipedia (Why?)

Back to homepage

Please click Add in the dialog above
Please click Allow in the top-left corner,
then click Install Now in the dialog
Please click Open in the download dialog,
then click Install
Please click the "Downloads" icon in the Safari toolbar, open the first download in the list,
then click Install
{{::$root.activation.text}}

Install Wikiwand

Install on Chrome Install on Firefox
Don't forget to rate us

Tell your friends about Wikiwand!

Gmail Facebook Twitter Link

Enjoying Wikiwand?

Tell your friends and spread the love:
Share on Gmail Share on Facebook Share on Twitter Share on Buffer

Our magic isn't perfect

You can help our automatic cover photo selection by reporting an unsuitable photo.

This photo is visually disturbing This photo is not a good choice

Thank you for helping!


Your input will affect cover photo selection, along with input from other users.

X

Get ready for Wikiwand 2.0 🎉! the new version arrives on September 1st! Don't want to wait?