cejs
Version:
A JavaScript module framework that is simple to use.
461 lines (392 loc) • 14.8 kB
JavaScript
/**
* @name CeL function for MediaWiki (Wikipedia / 維基百科): 常用模板特設功能。本工具檔放置的是指定 wiki
* 計畫特有的模板。
*
* 注意: 本程式庫必須應各 wiki project 模板內容改動而改寫。
*
* @fileoverview 本檔案包含了 MediaWiki 自動化作業用程式庫的子程式庫。
*
* TODO:<code>
</code>
*
* @since 2021/1/24 16:6:50
*/
// More examples: see /_test suite/test.js
// Wikipedia bots demo: https://github.com/kanasimi/wikibot
;
// 'use asm';
// @examples
(function() {
require('./wiki loader.js');
CeL.run('application.net.wiki.template_functions');
var wiki = Wiki(true, 'zh');
wiki.page('簡繁轉換一對多列表').parse(function(parsed) {
// var page_data = parsed.page;
parsed.each('Template:簡繁轉換', function(token) {
console.log(token.简 + '⇄' + token.繁);
});
});
});
// --------------------------------------------------------------------------------------------
// 不採用 if 陳述式,可以避免 Eclipse JSDoc 與 format 多縮排一層。
typeof CeL === 'function' && CeL.run({
// module name
name : 'application.net.wiki.template_functions.zhwiki',
require : 'data.native.'
// Should also load essential MediaWiki modules
+ '|application.net.wiki.',
// 設定不匯出的子函式。
no_extend : 'this,*',
// 為了方便格式化程式碼,因此將 module 函式主體另外抽出。
code : module_code
});
function module_code(library_namespace) {
// requiring
var wiki_API = library_namespace.application.net.wiki;
// @inner
// var is_api_and_title = wiki_API.is_api_and_title,
// normalize_title_parameter = wiki_API.normalize_title_parameter;
var to_exit = wiki_API.parser.parser_prototype.each.exit;
// e.g., 'zhwiki'
var module_site_name = this.id.match(/[^.]+$/)[0];
function empty_string(/* options */) {
// var token = this;
return '';
}
// --------------------------------------------------------------------------------------------
// token.expand() 可將模板轉換成一般 wiki 語法。
// https://www.mediawiki.org/w/api.php?action=help&modules=expandtemplates
// 用於 function preprocess_section_link_token()。
// --------------------------------------------------------------------------------------------
// {{#invoke:Number}} [[Module:Number]]
function expand_template_數字性質列表(options) {
var parameters = this.parameters;
// function p.numberDivisorInformation(frame) @ [[Module:Number]]
var white_index;
var number_step = parameters.white_list || parameters['white list'];
if (number_step) {
white_index = Object.create(null);
number_step.split(',').forEach(function(number) {
white_index[+number] = true;
});
}
var num_start = +parameters.start || 0;
var num_end = +parameters.end || 0;
if (wiki_API.Yesno(parameters['sort invert'] || parameters.sort_invert)) {
// Swap start, end
number_step = num_start;
num_start = num_end;
num_end = number_step;
number_step = -1;
} else {
number_step = 1;
}
if (parameters.type === '少量列舉' || parameters.type === '複雜') {
// function p.manyNumberInformation(frame) @ [[Module:Number]]
white_index = null;
num_start = +parameters[1];
num_end = num_start + (parameters.count || 1) + 1;
number_step = 1;
}
var wikitext = [];
for (; number_step > 0 ? num_start <= num_end : num_start >= num_end; num_start += number_step) {
if (white_index && !(num_start in white_index))
continue;
wikitext.push(';' + num_start + '<span id="' + num_start
+ '"></span>');
}
return wikitext.join('\n');
}
expand_template_數字性質列表.incomplete = 'Only for get_all_anchors()';
// --------------------------------------------------------------------------------------------
function expand_template_A(options) {
var parameters = this.parameters;
return (parameters.name ? '<span id="' + parameters.name
//
+ '"></span>' : '') + '[[' + parameters[1]
//
+ (parameters[2] ? '|' + parameters[2] : '') + ']]';
}
// --------------------------------------------------------------------------------------------
// [[w:zh:Template:Al]]
function expand_template_Al(options) {
var token = this;
return token.page_title_list.map(function(title) {
return wiki_API.title_link_of(title);
}).join('、');
}
function parse_template_Al(token, index, parent, options) {
var index = 0, page_title_list = [];
while (index < token.length) {
var page_title = token.parameters[++index];
// allow `{{al||title}}`
if (page_title)
page_title_list.push(page_title);
}
Object.assign(token, {
page_title_list : page_title_list,
expand : expand_template_Al
});
return page_title_list;
}
// --------------------------------------------------------------------------------------------
function parse_template_不存檔(token, index, parent, options) {
token.message_expire_date = Infinity;
}
// --------------------------------------------------------------------------------------------
function expand_template_楷體(options) {
var parameters = this.parameters;
return '<span class="template-kai">' + (parameters[1] || '楷体')
+ '</span>';
}
function parse_template_楷體(token, index, parent, options) {
token.expand = expand_template_楷體;
}
// --------------------------------------------------------------------------------------------
/**
* [[Template:Interlanguage link]] 跨語言模板 多語言模板。會為 token 增加下列屬性: <code>
</code>
*/
var interlanguage_link_template_attributes = {
// local_title: local title 中文條目名
"local_page_title" : '',
// 只會提供第一個。
"foreign_language_code" : '',
// 只會提供第一個。
"foreign_page_title" : '',
"foreign_page_mapper" : {
// foreign_language: foreign language code 外文語言代號
// foreign_title: foreign title 外文條目名
foreign_language_code : 'foreign_page_title'
},
// label: label text displayed 顯示名
"display_text" : '',
// Keep foreign language links when displayed
"preserve_foreign_links" : true,
"wikidata_entity_id" : '' || 1,
// 屬性的index,改變屬性值時使用。
"attribute_index" : {
"local_page_title" : 1,
// 只會提供第一個。
"foreign_language_code" : 1,
// 只會提供第一個。
"foreign_page_title" : 1,
"display_text" : 1,
"preserve_foreign_links" : 1,
"wikidata_entity_id" : 1
}
};
function setup_interlanguage_link_template_parameters(template_pattern) {
var parsed_token = wiki_API.parse(template_pattern);
var attribute_index = Object.create(null);
var configuration = {
attribute_index : attribute_index
};
var parameters = parsed_token.parameters;
for ( var parameter in parameters) {
var attribute_name = parameters[parameter];
if (attribute_name in interlanguage_link_template_attributes)
attribute_index[attribute_name] = parameter;
}
var functions_of_site = wiki_API.template_functions.functions_of_site[module_site_name];
if (functions_of_site[parsed_token.name]) {
library_namespace
.error('setup_interlanguage_link_template_parameters: '
+ '已設定' + parsed_token.name
+ '之模板特設功能,無法設定跨語言模板功能。');
return;
}
functions_of_site[parsed_token.name] = parse_interlanguage_link_template
.bind(configuration);
}
function parse_interlanguage_link_template(token, index, parent, options) {
var configuration = this;
var attribute_index = configuration.attribute_index;
var foreign_page_mapper = Object.create(null);
for ( var attribute_name in attribute_index) {
if (attribute_index[attribute_name] in token.parameters)
token[attribute_name] = token.parameters[attribute_index[attribute_name]];
}
if ('foreign_language_code' in token)
foreign_page_mapper[token.foreign_language_code] = token.foreign_page_title;
token.attribute_index = attribute_index;
token.foreign_page_mapper = foreign_page_mapper;
}
// --------------------------------------------------------------------------------------------
// {{Lang|ja|參數值}} → -{參數值}-
function expand_template_Lang(options) {
var parameters = this.parameters;
return /^(?:zh|gan)/.test(parameters[1]) ? parameters[2] : '-{'
+ parameters[2] + '}-';
}
// --------------------------------------------------------------------------------------------
// [[w:zh:Template:NoteTA]]
function parse_template_NoteTA(token, options) {
var conversion_list = Object.assign([], {
// 固定轉換規則
// fixed : [],
// 公共轉換組
group_data : [],
groups : []
});
var index, value = token.parameters.T;
if (value) {
// 標題轉換
conversion_list.title = value;
}
// TODO: {{NoteTA}} 使用「1=」可以同時轉換標題和正文(T=)?
for (index = 1; index < token.length; index++) {
value = token.parameters[index];
if (!value)
continue;
// [[w:zh:模組:NoteTA]]
// @see function item_to_conversion(item) @
// CeL.application.net.wiki
value = wiki_API.parse('-{A|' + value + '}-', {
normalize : true,
with_properties : true
});
if (typeof value === 'string') {
// 遇到無法轉換的值別 throw。 e.g., "a\nb"
continue;
}
// value.parameter_name = index;
value.index = token.index_of[index];
// console.log(value);
conversion_list.push(value);
}
// [[w:zh:Module:NoteTA]]
for (index = 1; index < token.length; index++) {
var parameter_name = 'G' + index;
value = token.parameters[parameter_name];
if (!value)
continue;
value = wiki_API.parse.wiki_element_to_key(value);
var group_name_String;
if (typeof value === 'string') {
group_name_String = value = value.replace(/_/g, ' ').trim()
// '\u200E\u200F'.trim().length === 2
.replace(/^[\u200E\u200F\s]+/, '').replace(
/[\u200E\u200F\s]+$/, '');
} else {
library_namespace.warn('parse_template_NoteTA: 非字串之公共轉換組名稱: ['
+ value + '] @ ' + token);
console.trace(value);
group_name_String = value.toString().trim().replace(
/^[\u200E\u200F\s]+/, '').replace(/[\u200E\u200F\s]+$/,
'');
}
// console.trace([ value, group_name_String ]);
conversion_list.groups.push(group_name_String);
conversion_list.group_data[group_name_String] = {
parameter_name : parameter_name,
// Maybe {Ayyay} and includes "\n"、不可見字符
group_name : value,
group_name_String : group_name_String,
index : token.index_of[parameter_name]
};
// TODO
}
Object.assign(token, {
conversion_list : conversion_list,
expand : empty_string
});
return conversion_list;
}
// --------------------------------------------------------------------------------------------
function template_簡繁轉換_to_string(template_token, parameter) {
var words = template_token.parameters[parameter];
if (Array.isArray(words)) {
words = words.map(function(token) {
if (typeof token === 'string')
return token;
if (token.tag === 'sup') {
// e.g., "<sup>台/陸繁</sup>"
return '';
}
if (token.type === 'transclusion') {
if (token.name === 'Lang'
//
&& typeof token.parameters[2] === 'string')
return token.parameters[2];
if (token.name === '僻字') {
// console.log(token.toString());
}
if (token.name === '僻字'
//
&& typeof token.parameters[1] === 'string')
return token.parameters[1];
}
throw new Error('包含無法處理的字元: ' + token);
}).join('');
}
words = library_namespace.HTML_to_Unicode(words);
// [[w:zh:Unicode字符平面映射]]
// http://ubuntu-rubyonrails.blogspot.com/2009/06/unicode.html
words = words.replace(
// 發音用 Pinyin diacritic-vowel combinations:
// \u00E0-\u00FC [[w:en:Latin-1 Supplement (Unicode block)]]
// \u0100-\u017F [[w:en:Latin Extended-A]]
// \u01CD-\u01DC [[w:en:Latin Extended-B]]
/[(),、a-z\u00E0-\u00FC\u0100-\u017F\u01CD-\u01DC\uD800-\uDFFF]/g, '');
if (false && /[^\u4E00-\u9FFF\u3400-\u4DBF\uF900-\uFAFF\u2E80-\u2EFF]/
.test(words)) {
// words.charCodeAt(0).toString(16)
console.log([ words, words.replace(
// 匹配中文字符的正則表達式
/[\u4E00-\u9FFF\u3400-\u4DBF\uF900-\uFAFF\u2E80-\u2EFF]/g,
//
'') ]);
// throw words;
}
return words;
}
// for {{簡繁轉換}} @ [[w:zh:簡繁轉換一對多列表]]
// @see wiki_API.convert_Chinese()
function parse_template_簡繁轉換(token) {
Object.assign(token, {
简 : template_簡繁轉換_to_string(token, 's'),
繁 : template_簡繁轉換_to_string(token, 't')
});
}
// --------------------------------------------------------------------------------------------
// export 導出.
wiki_API.template_functions.functions_of_site[module_site_name] = {
// 一些會產生網頁錨點 anchors 的模板或模組。
// Templates or modules that generate web anchors
'Invisible anchor' : {
properties : {
expand : wiki_API.template_functions.functions_of_all_sites.Anchor.properties.expand
}
},
// {{#invoke:Number}} [[Module:Number]]
數字性質列表 : {
properties : {
expand : expand_template_數字性質列表
}
},
// 一些會用於章節標題的特殊模板。 for preprocess_section_link_token()
A : {
properties : {
expand : expand_template_A
}
},
Al : parse_template_Al,
// {{Do not archive}}
// wiki/routine/20210429.Auto-archiver.js: avoid being archived
不存檔 : parse_template_不存檔,
// [[Template:Interlanguage link]] 跨語言模板 多語言模板。
Lang : {
properties : {
expand : expand_template_Lang
}
},
NoteTA : parse_template_NoteTA,
簡繁轉換 : parse_template_簡繁轉換
};
[ '{{Interlanguage link multi|local_page_title|foreign_language_code|foreign_page_title|lt=display_text|WD=wikidata_entity_id}}' ]
.forEach(setup_interlanguage_link_template_parameters);
// --------------------------------------------------------------------------------------------
// 不設定(hook)本 module 之 namespace,僅執行 module code。
return library_namespace.env.not_to_extend_keyword;
}