User:春上冰月/WikiplusWithDotsSyntaxHighlighter.js
外观
注意:保存之后,你必须清除浏览器缓存才能看到做出的更改。Google Chrome、Firefox、Microsoft Edge及Safari:按住⇧ Shift键并单击工具栏的“刷新”按钮。参阅Help:绕过浏览器缓存以获取更多帮助。
// Simple combination of Wikiplus and DotsSyntaxHighlighter
// License: CC-BY-SA-3.0-Unported, GFDL
// Date: 20170723
//============================
// Wikiplus: https://zh.moegirl.org/User:%E5%A6%B9%E7%A9%BA%E9%85%B1/Wikiplus
// Author:+Eridanus Sora/@妹空酱
// License: Apache License 2.0
//============================
// DotsSyntaxHighlighter: https://www.mediawiki.org/wiki/User:Remember_the_dot/Syntax_highlighter.js
// Author: User:Remember_the_dot
// License: GPLv2, CC-BY-SA-3.0-Unported, GFDLv1.2
/* == Origin License of Wikiplus ==
Copyright 2017 Eridanus Sora
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/* global mw */
/// <reference path="./typings/jquery/jquery.d.ts"/>
/**
* Wikiplus
* Author:+Eridanus Sora/@妹空酱
* Github:https://github.com/Last-Order/Wikiplus
*/
/**
* 依赖组件:MoeNotification
* https://github.com/Last-Order/MoeNotification
*/
'use strict';
var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
function MoeNotification(undefined) {
var self = this;
this.display = function (text, type, callback) {
var _callback = callback || function () {};
var _text = text || '喵~';
var _type = type || 'success';
$("#MoeNotification").append($("<div>").addClass('MoeNotification-notice').addClass('MoeNotification-notice-' + _type).append('<span>' + _text + '</span>').fadeIn(300));
self.bind();
self.clear();
_callback($("#MoeNotification").find('.MoeNotification-notice').last());
};
this.create = {
success: function success(text, callback) {
var _callback = callback || function () {};
self.display(text, 'success', _callback);
},
warning: function warning(text, callback) {
var _callback = callback || function () {};
self.display(text, 'warning', _callback);
},
error: function error(text, callback) {
var _callback = callback || function () {};
self.display(text, 'error', _callback);
}
};
this.clear = function () {
if ($(".MoeNotification-notice").length >= 10) {
$("#MoeNotification").children().first().fadeOut(150, function () {
$(this).remove();
});
setTimeout(self.clear, 300);
} else {
return false;
}
};
this.empty = function (f) {
$(".MoeNotification-notice").each(function (i) {
if ($.isFunction(f)) {
var object = this;
setTimeout(function () {
f($(object));
}, 200 * i);
} else {
$(this).delay(i * 200).fadeOut('fast', function () {
$(this).remove();
});
}
});
};
this.bind = function () {
$(".MoeNotification-notice").mouseover(function () {
self.slideLeft($(this));
});
};
window.slideLeft = this.slideLeft = function (object, speed) {
object.css('position', 'relative');
object.animate({
left: "-200%"
}, speed || 150, function () {
$(this).fadeOut('fast', function () {
$(this).remove();
});
});
};
this.init = function () {
$("body").append('<div id="MoeNotification"></div>');
};
if (!($("#MoeNotification").length > 0)) {
this.init();
}
}
$(function () {
var i18nData = {};
var scriptPath = location.protocol + '//wikiplus-app.smartgslb.com';
i18nData['zh-cn'] = {
"__language": "zh-cn",
"__author": ["Eridanus Sora"],
"__version": "207",
"unknown_error_name": "未知的错误名",
"api_unaccessiable": "无可用的API",
"api_unwriteable": "无可用的写入API",
"fail_to_get_timestamp": "无法获得页面编辑起始时间戳",
"fail_to_get_edittoken": "无法获得页面编辑权标",
"fail_to_get_pageinfo": "无法获得页面信息",
"not_autoconfirmed_user": "非自动确认用户",
"hit_abusefilter": "被防滥用过滤器拦截",
"unknown_edit_error": "未知编辑错误",
"unknown_edit_error_message": "未知编辑错误($1)",
"notitle": "无法编辑空标题页面",
"notext": "缺少页面内容",
"notoken": "空编辑权标",
"invalidsection": "段落编号非法",
"protectedtitle": "该标题被保护,无法创建",
"cantcreate": "无新建页面权限",
"cantcreate_anon": "匿名用户无新建页面权限",
"articleexists": "无法创建已经存在的页面",
"noimageredirect_anon": "匿名用户无新建文件重定向权限",
"noimageredirect": "无新建文件重定向权限",
"spamdetected": "文本含有敏感内容,被SPAM过滤器拦截",
"filtered": "编辑被过滤器拦截",
"contenttoobig": "文本超过最大长度限制",
"noedit_anon": "匿名用户无编辑页面权限",
"noedit": "无编辑页面权限",
"pagedeleted": "编辑时,此页面被删除",
"emptypage": "无法新建空内容页面",
"emptynewsection": "无法新建空内容段落",
"editconflict": "编辑冲突,请手工检查页面当前内容与提交内容差异并修正后,刷新页面提交",
"revwrongpage": "编辑的修订版本与编辑的页面不匹配",
"undofailure": "由于存在冲突的中间版本,无法撤销编辑",
"missingtitle": "无法创建或编辑空标题页面",
"mustbeposted": "必须使用POST方式提交编辑",
"readapidenied": "无读取API使用权限",
"writeapidenied": "无通过API编辑页面权限",
"noapiwrite": "本Wiki未开启可用的写入API",
"badtoken": "非法的编辑权标",
"missingparam": "缺少必要参数,页面名和页面ID不能均为空",
"invalidparammix": "参数重复,页面名和页面ID不能同时给定",
"invalidtitle": "非法的标题",
"nosuchpageid": "不存在的页面ID",
"pagecannotexist": "该名称空间不允许新建一般页面",
"nosuchrevid": "不存在的修订版本",
"badmd5": "非法的MD5值",
"hookaborted": "编辑被扩展Hook拦截",
"parseerror": "无法解析页面文本",
"summaryrequired": "编辑摘要不能为空",
"blocked": "已被封禁",
"ratelimited": "达到操作速率上限,请稍后重试",
"unknownerror": "未知错误",
"nosuchsection": "无法编辑不存在的段落",
"sectionsnotsupported": "该页面不支持段落编辑",
"editnotsupported": "该页面不支持通过API编辑",
"appendnotsupported": "该页面无法在前后插入文本",
"redirect_appendonly": "在遵循重定向的情况下,只能进行前后插入或创建新段落",
"badformat": "文本格式错误",
"customcssprotected": "无法编辑用户CSS页",
"customjsprotected": "无法编辑用户JS页",
"cascadeprotected": "该页面被级联保护",
"network_edit_error": "由于网络原因编辑失败",
"redirect_to_summary": "重定向页面至 [[$1]] // Wikiplus",
"redirect_from_summary": "将[[$1]]重定向至[[$2]] // Wikiplus",
"need_init": "页面类未加载完成",
"fail_to_get_wikitext": "无法获得页面文本",
"quickedit_topbtn": "快速编辑",
"quickedit_sectionbtn": "快速编辑",
"fail_to_init_quickedit": "无法加载快速编辑",
"back": "返回",
"goto_editbox": "到编辑框",
"summary_placehold": "请输入编辑摘要",
"submit": "提交",
"preview": "预览",
"cancel": "取消",
"mark_minoredit": "标记为小编辑",
"onclose_confirm": "[Wikiplus] 您确认要关闭/刷新页面吗 这会导致您的编辑数据丢失",
"fail_to_get_wikitext_when_edit": "无法获得页面文本以编辑",
"cant_parse_wikitext": "无法解析维基文本",
"loading_preview": "正在读取预览",
"submitting_edit": "正在提交编辑",
"edit_success": "编辑成功 用时$1ms",
"empty_page_confirm": "您向编辑函数传入了空内容参数 这将清空页面\r\n由于该行为危险 请将config参数的empty键值设定为true来确认",
"cross_page_edit": "编辑目标位于其他页面 正在获取基础信息",
"cross_page_edit_submit": "基础信息获取成功 正在提交编辑",
"cross_page_edit_error": "无法获得基础信息>.<",
"install_tip": "您是否允许Wikiplus采集非敏感数据用于改进Wikiplus及为当前Wiki: $1 提供改进建议?",
"accept": "接受",
"decline": "拒绝",
"install_finish": "Wikiplus安装完毕",
"loading": "正在载入",
"cant_add_funcbtn": "无法增加功能按钮",
"wikiplus_settings": "Wikiplus设置",
"wikiplus_settings_desc": "请在下方按规范修改Wikiplus设置",
"wikiplus_settings_placeholder": "当前设置为空 请在此处按规范修改Wikiplus设置",
"wikiplus_settings_grammar_error": "设置存在语法错误 请检查后重试",
"wikiplus_settings_saved": "设置已保存",
"redirect_from": "将页面重定向至此",
"redirect_desc": "请输入要重定向至此的页面名",
"empty_input": "输入不能为空",
"redirect_saved": "重定向完成",
"uninited": "Wikiplus未加载完毕 请刷新重试",
"cant_parse_i18ncache": "无法解析多语言定义文件缓存",
"cant_load_language": "无法获取多语言定义文件",
"history_edit_warning": " // 正试图编辑历史版本 这将会应用到本页面的最新版本 请慎重提交",
"create_page_tip": "<!-- 正在创建新页面 请删去此行注释后继续 -->",
"continue": "仍然继续"
};
i18nData['en-us'] = {
"__language": "en-us",
"__author": ["Eridanus Sora", "AnnAngela"],
"__translator": ["Eridanus Sora", "YinYan"],
"__version": "207",
"unknown_error_name": "Unknown error",
"api_unaccessiable": "API of this wiki is not available",
"api_unwriteable": "Write API of this wiki is not available",
"fail_to_get_timestamp": "Failed to get the timestamp of this page.",
"fail_to_get_edittoken": "Failed to get the EditToken of this page.",
"fail_to_get_pageinfo": "Failed to load infomation of this page",
"not_autoconfirmed_user": "You are not an autoconfiremd user",
"hit_abusefilter": "Your edit hit the abusefilter(s)",
"unknown_edit_error": "Unknown edit error",
"unknown_edit_error_message": "Unknown edit error($1)",
"notitle": "The title parameter must be set",
"notext": "The text parameter must be set",
"notoken": "The token parameter must be set",
"invalidsection": "The section parameter must be set to an integer or 'new'",
"protectedtitle": "This title has been protected from creation",
"cantcreate": "You don't have permission to create new pages",
"cantcreate_anon": "Anonymous users can't create new pages",
"articleexists": "The article you tried to create has already existed",
"noimageredirect_anon": "Anonymous users can't create image redirects",
"noimageredirect": "You don't have the permission to create image redirects",
"spamdetected": "Your edit was rejected because it contained a spam fragment",
"filtered": "The filter callback function rejected your edit",
"contenttoobig": "The content you submitted exceeds the article size limit",
"noedit_anon": "Anonymous users can't edit pages",
"noedit": "You don't have the permission to edit pages",
"pagedeleted": "The page was deleted during your edit",
"emptypage": "Creating new, empty pages is not allowed",
"emptynewsection": "Creating empty new sections is not possible.",
"editconflict": "Edit Conflict! Don't panic. Please check the difference between your content below and the existing revision, then refresh the page to make another submit",
"revwrongpage": "The revision you are editing now is not one a valid reversions of this page",
"undofailure": "Undo failed due to conflicts.",
"missingtitle": "Missing title in your edit/creation",
"mustbeposted": "The edit must be submited by POST method",
"readapidenied": "Read API Denied",
"writeapidenied": "Write API Denied",
"noapiwrite": "No available write API in this wiki",
"badtoken": "Invalid EditToken",
"missingparam": "One of the parameters title, pageid is required",
"invalidparammix": "The parameters title, pageid can not be used together",
"invalidtitle": "Invalid page title",
"nosuchpageid": "Inexistent page ID",
"pagecannotexist": "No access to create a new page in this namespace",
"nosuchrevid": "Inexisting reversion ID",
"badmd5": "Invalid MD5",
"hookaborted": "Your edit was rejected by the hook(s)",
"parseerror": "Failed to parse the wikitext of this page",
"summaryrequired": "No summary in your edit",
"blocked": "You has been already BLOCKED",
"ratelimited": "You've exceeded your rate limit. Please have a tea and try again later",
"unknownerror": "Unknown error",
"nosuchsection": "There is no such section",
"sectionsnotsupported": "Can't edit in this section",
"editnotsupported": "Can't edit in this section by writing section",
"appendnotsupported": "Can't append/prepend wikitext to this page",
"redirect_appendonly": "Only append/prepend can be made to this page because of the rules of the redirect page",
"badformat": "The requested serialization format can not be applied to the page's content model",
"customcssprotected": "You're not allowed to edit custom CSS pages",
"customjsprotected": "You're not allowed to edit custom JavaScript pages",
"cascadeprotected": "This page is under a cascading protection",
"network_edit_error": "Failed to edit this page because of network errors",
"redirect_to_summary": "Redirect to [[$1]] \/\/ Wikiplus",
"redirect_from_summary": "Redirect [[$1]] to [[$2]] \/\/ Wikiplus",
"need_init": "WikiPlus haven't been loaded completely. It's a rare occasion so you can try to refresh and try again.",
"fail_to_get_wikitext": "Failed to load the wikitext of this page",
"quickedit_topbtn": "QuickEdit",
"quickedit_sectionbtn": "QuickEdit",
"fail_to_init_quickedit": "Failed to initialize WikiPlus",
"back": "Back",
"goto_editbox": "Jump to editbox",
"summary_placehold": "Edit summary",
"submit": "Submit",
"preview": "Preview",
"cancel": "Cancel",
"mark_minoredit": "Mark this edit as a minor edit",
"onclose_confirm": "[Wikiplus] Do you really want to close this page when you are still editing it, as you will lose all your unsaved work?",
"fail_to_get_wikitext_when_edit": "Failed to load wikitext for your edit",
"cant_parse_wikitext": "Failed to parse the wikitext",
"loading_preview": "Loading the preview",
"submitting_edit": "Submitting your edit",
"edit_success": "Your edit is submitted within $1ms",
"empty_page_confirm": "The wikitext in your edit is empty, which will empty this page.\r\nPlease set the value of key \"empty\" true to allow this kind of edits. (This is a tip for developers)",
"cross_page_edit": "The content you are editing belongs to another page, please wait...",
"cross_page_edit_submit": "Submitting your edit...",
"cross_page_edit_error": "Failed to load the infomation",
"install_tip": "Do you allow WikiPlus to collect insensitive data to help us develop WikiPlus and provide feedback to current site: $1 ?",
"accept": "Yes",
"decline": "No",
"install_finish": "Wikiplus is installed, enjoy it",
"loading": "Loading",
"cant_add_funcbtn": "Failed to add buttons for WikiPlus",
"wikiplus_settings": "Wikiplus Setting",
"wikiplus_settings_desc": "Please modify your setting according to the standards below",
"wikiplus_settings_placeholder": "Your setting is empty, please modify your setting according to the documentation.",
"wikiplus_settings_grammar_error": "Syntax error in your setting",
"wikiplus_settings_saved": "Your settings have been saved",
"redirect_from": "Redirect from",
"redirect_desc": "Which page do you want to redirect here?",
"empty_input": "Empty input",
"redirect_saved": "Redirection is finished",
"uninited": "Wikiplus is not completely initialized, please refeash this page",
"cant_parse_i18ncache": "Failed to parse the cache of i18n file",
"cant_load_language": "Failed to load i18n file",
"history_edit_warning": " // You are trying to edit a history revision of this page. This will apply to the latest revision. Please be careful.",
"create_page_tip": "<!-- You are now creating a new page. Please delete this line and be careful. -->",
"continue": "Continue anyway"
};
/**
* 加载其他语言文件
* @param {string} language 语言名
*/
function loadLanguage(language) {
$.ajax({
url: scriptPath + '/languages/get.php?lang=' + language,
dataType: 'json',
success: function success(data) {
if (data.__language && data.__version) {
if (i18nData[data.__language]) {
if (data.__version >= i18nData[data.__language].__version) {
i18nData[data.__language] = data;
console.log('更新语言版本' + data.___language + '至' + data.___version);
} else {
// 服务端未跟进语言版本 不更新本地缓存
}
} else {
i18nData[data.__language] = data;
}
localStorage.Wikiplus_i18nCache = JSON.stringify(i18nData); //更新缓存
}
},
error: function error(e) {
console.log('无法加载语言' + language);
}
});
}
/**
* 多语言转换
* @param {stirng} key 字段标识名
* @return {string} 经过转换的内容 如未找到对应的多语言字段 则返回简体中文
*/
function i18n(key) {
var language;
try {
language = JSON.parse(localStorage.Wikiplus_Settings)['language'] || window.navigator.language.toLowerCase();
} catch (e) {
language = window.navigator.language.toLowerCase();
}
if (i18nData[language] && i18nData[language][key]) {
return i18nData[language][key];
} else if (i18nData['en-us'][key]) {
return i18nData['en-us'][key];
} else {
return 'undefined';
}
}
/**
* 获得错误信息
* @param {stirng} name
* @return {object} {number,message}
*/
function getErrorInfo(name) {
var errorList = {
unknown_error_name: {
number: 1001,
message: i18n('unknown_error_name')
},
api_unaccessiable: {
number: 1002
},
api_unwriteable: {
number: 1003
},
fail_to_get_timestamp: {
number: 1004
},
fail_to_get_edittoken: {
number: 1005
},
fail_to_get_pageinfo: {
number: 1006
},
not_autoconfirmed_user: {
number: 1007
},
hit_abusefilter: {
number: 1008
},
unknown_edit_error: {
number: 1009
},
unknown_edit_error_message: {
number: 1010
},
notitle: {
number: 1011
},
notext: {
number: 1012
},
notoken: {
number: 1013
},
invalidsection: {
number: 1014
},
protectedtitle: {
number: 1015
},
cantcreate: {
number: 1016
},
cantcreate_anon: {
number: 1017
},
articleexists: {
number: 1018
},
noimageredirect_anon: {
number: 1019
},
noimageredirect: {
number: 1020
},
spamdetected: {
number: 1021
},
filtered: {
number: 1022
},
contenttoobig: {
number: 1023
},
noedit_anon: {
number: 1025
},
noedit: {
number: 1026
},
pagedeleted: {
number: 1027
},
emptypage: {
number: 1028
},
emptynewsection: {
number: 1029
},
editconflict: {
number: 1030
},
revwrongpage: {
number: 1031
},
undofailure: {
number: 1032
},
missingtitle: {
number: 1033
},
mustbeposted: {
number: 1034
},
readapidenied: {
number: 1035
},
writeapidenied: {
number: 1036
},
noapiwrite: {
number: 1037
},
badtoken: {
number: 1038
},
missingparam: {
number: 1039
},
invalidparammix: {
number: 1040
},
invalidtitle: {
number: 1041
},
nosuchpageid: {
number: 1042
},
pagecannotexist: {
number: 1043
},
nosuchrevid: {
number: 1044
},
badmd5: {
number: 1045
},
hookaborted: {
number: 1046
},
parseerror: {
number: 1047
},
summaryrequired: {
number: 1048
},
blocked: {
number: 1049
},
ratelimited: {
number: 1050
},
unknownerror: {
number: 1051
},
nosuchsection: {
number: 1052
},
sectionsnotsupported: {
number: 1053
},
editnotsupported: {
number: 1054
},
appendnotsupported: {
number: 1055
},
redirect_appendonly: {
number: 1056
},
badformat: {
number: 1057
},
customcssprotected: {
number: 1058
},
customjsprotected: {
number: 1059
},
cascadeprotected: {
number: 1060
},
network_edit_error: {
number: 1061
},
need_init: {
number: 1062
},
fail_to_get_wikitext: {
number: 1063
},
fail_to_init_quickedit: {
number: 1064
},
fail_to_get_wikitext_when_edit: {
number: 1065
},
cant_parse_wikitext: {
number: 1066
},
empty_page_confirm: {
number: 1067
},
uninited: {
number: 1068
},
cant_parse_i18ncache: {
number: 1069
},
cant_load_language: {
number: 1070
}
};
if (errorList[name]) {
if (errorList[name].message) {
return {
number: errorList[name].number,
message: errorList[name].message
};
} else if (i18n(name) !== 'undefined') {
return {
number: errorList[name].number,
message: i18n(name)
};
} else {
return {
number: errorList[name].number,
message: i18n('unknownerror')
};
}
} else {
return {
number: errorList.unknown_error_name.number,
message: errorList.unknown_error_name.message
};
}
}
/**
* 判断值是否存在于数组
* @param {string} value
* @param {array} array
* @return {boolean} whether the value is in the array
*/
function inArray(value) {
var array = arguments.length <= 1 || arguments[1] === undefined ? [] : arguments[1];
return $.inArray(value, array) === -1 ? false : true;
}
/**
* 抛出错误
* @param {string} name
* @return boolean
*/
function throwError(name, message) {
var errInfo = getErrorInfo(name);
var e = new Error();
e.number = errInfo.number;
e.message = message || errInfo.message;
console.log('%c致命错误[' + e.number + ']:' + e.message, 'color:red');
console.log(e);
return e;
}
/**
* 将mw的段落的id转换为可显示的文本
* @param {string} URL
* @return string
*/
var Wikipage = (function () {
function Wikipage() {
var pageName = arguments.length <= 0 || arguments[0] === undefined ? window.mw.config.get('wgPageName') : arguments[0];
_classCallCheck(this, Wikipage);
console.log('页面类构建中');
//可用性和权限检测
if (!window.mw) {
console.log('页面Javascript载入不完全或这不是一个Mediawiki站点');
return;
}
if (false || false) {
throwError('api_unaccessiable');
return;
}
if (!inArray('autoconfirmed', window.mw.config.get('wgUserGroups'))) {
throwError('not_autoconfirmed_user');
return;
}
//从MediaWiki定义的全局变量中获得信息
this.pageName = pageName.replace(/ /ig, '_'); // Mediawiki处理空格时可能会出错
this.revisionId = window.mw.config.get('wgRevisionId');
this.articleId = window.mw.config.get('wgArticleId');
this.API = location.protocol + '//' + location.host + window.mw.config.get('wgScriptPath') + '/api.php';
//从API获得编辑令牌和起始时间戳
this.editToken = {};
this.timeStamp = {};
this.init(this.pageName, {
success: function success() {
console.log('Wikiplus加载完毕');
},
fail: function fail(e) {
console.log('Wikiplus未能正确加载(' + e.message + ')');
}
});
}
/**
* 针对非本页面的编辑 提供重定义时间戳和权标接口
* @param {string} titile 标题
* @param {object} callback 回调函数
*/
_createClass(Wikipage, [{
key: 'reConstruct',
value: function reConstruct(title) {
var callback = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1];
this.init(title, callback);
}
/**
* 获取页面基础信息并记录
*/
}, {
key: 'init',
value: function init(title, callback, config) {
if (title === undefined) title = this.pageName;
if (callback === undefined) callback = {};
var self = this;
callback.success = callback.success || new Function();
callback.fail = callback.success || new Function();
$.ajax({
type: 'GET',
dataType: 'json',
url: this.API,
data: {
'action': 'query',
'prop': 'revisions|info',
'titles': title,
'rvprop': 'timestamp',
'format': 'json'
},
beforeSend: function beforeSend() {
console.time('获得页面基础信息时间耗时');
},
success: function success(data) {
if (data && data.query && data.query.pages) {
var info = data.query.pages;
for (var key in info) {
if (key !== '-1') {
if (info[key].revisions && info[key].revisions.length > 0) {
self.timeStamp[title] = info[key].revisions[0].timestamp;
} else {
callback.fail(throwError('fail_to_get_timestamp'));
}
if (mw.user.tokens.get('csrfToken') && mw.user.tokens.get('csrfToken') !== '+\\') {
self.editToken[title] = mw.user.tokens.get('csrfToken');
console.log('成功获得编辑令牌 来自前端API');
} else {
//前端拿不到Token 尝试通过API
$.ajax({
url: self.API,
type: "GET",
dataType: "json",
data: {
'action': 'query',
'meta': 'tokens',
'format': 'json'
},
success: function success(data) {
if (data.query && data.query.tokens && data.query.tokens.csrftoken && data.query.tokens.csrftoken !== '+\\') {
self.editToken[title] = data.query.tokens.csrftoken;
console.log('成功获得编辑令牌 通过后端API');
} else {
callback.fail(throwError('fail_to_get_edittoken'));
}
},
error: function error(e) {
callback.fail(throwError('fail_to_get_edittoken'));
}
});
callback.fail(throwError('fail_to_get_edittoken'));
}
} else {
if (mw.config.get('wgArticleId') === 0) {
// 如果是空页面就只拿一个edittoken
if (mw.user.tokens.get('csrfToken') && mw.user.tokens.get('csrfToken') !== '+\\') {
self.editToken[title] = mw.user.tokens.get('csrfToken');
console.log('成功获得编辑令牌 来自前端API');
self.inited = true;
} else {
self.inited = false;
callback.fail(throwError('fail_to_get_edittoken'));
}
} else {
// 如果不是 那就是失败了 抛出错误
self.inited = false;
callback.fail(throwError('fail_to_get_pageinfo'));
}
}
}
}
}
}).done(function () {
console.timeEnd('获得页面基础信息时间耗时');
self.inited = self.inited === false ? false : true;
callback.success();
});
}
/**
* 页面编辑
* @param {string} content 页面内容
* @param {string} title 页面标题 默认为当前页面标题
* @param {object} callback 回调函数
* @param {object} config 设置 覆盖到默认的设置
*/
}, {
key: 'edit',
value: function edit(content) {
var title = arguments.length <= 1 || arguments[1] === undefined ? this.pageName : arguments[1];
var callback = arguments.length <= 2 || arguments[2] === undefined ? {} : arguments[2];
var config = arguments.length <= 3 || arguments[3] === undefined ? {} : arguments[3];
var self = this;
callback.success = callback.success || new Function();
callback.fail = callback.fail || new Function();
if (content === undefined) {
if (!config.empty === true) {
callback.fail(throwError('empty_page_confirm'));
return false;
}
}
if (self.inited) {
$.ajax({
type: 'POST',
url: self.API,
data: $.extend({
'action': 'edit',
'format': 'json',
'text': content,
'title': title,
'token': self.editToken[title] || self.editToken[self.pageName],
'basetimestamp': self.timeStamp[title]
}, config),
success: function success(data) {
if (data && data.edit) {
if (data.edit.result && data.edit.result == 'Success') {
callback.success();
} else {
if (data.edit.code) {
//防滥用过滤器
callback.fail(throwError('hit_abusefilter', i18n('hit_abusefilter') + ':' + data.edit.info.replace('/Hit AbuseFilter: /ig', '') + '<br><small>' + data.edit.warning + '</small>'));
} else {
callback.fail(throwError('unknown_edit_error'));
}
}
} else if (data && data.error && data.error.code) {
callback.fail(throwError(data.error.code.replace(/-/ig, '_')), i18n('unknown_edit_error_message').replace(/\$1/ig, data.error.code));
} else if (data.code) {
callback.fail(throwError('unknown_edit_error'), i18n('unknown_edit_error_message').replace(/\$1/ig, data.code));
} else {
callback.fail(throwError('unknown_edit_error'));
}
},
error: function error(e) {
callback.fail(throwError('network_edit_error'));
}
});
} else {
callback.fail(throwError('uninited'));
}
}
/**
* 编辑段落
* @param {number} section 段落编号
* @param {string} content 内容
* @param {string} title 页面标题
* @param {object} callback 回调函数
* @param {object} config 设置
*/
}, {
key: 'editSection',
value: function editSection(section, content) {
var title = arguments.length <= 2 || arguments[2] === undefined ? this.pageName : arguments[2];
var config = arguments.length <= 3 || arguments[3] === undefined ? {} : arguments[3];
var callback = arguments.length <= 4 || arguments[4] === undefined ? {} : arguments[4];
callback.success = callback.success || new Function();
callback.fail = callback.fail || new Function();
this.edit(content, title, callback, $.extend({
'section': section
}, config));
}
/**
* 重定向页面至
* @param {string} target 目标页面标题
* @param {string} title 页面名 默认为当前页面
* @param {object} callback 回调函数
*/
}, {
key: 'redirectTo',
value: function redirectTo(target) {
var title = arguments.length <= 1 || arguments[1] === undefined ? this.pageName : arguments[1];
var callback = arguments.length <= 2 || arguments[2] === undefined ? {} : arguments[2];
callback.success = callback.success || new Function();
callback.fail = callback.fail || new Function();
this.edit('#REDIRECT [[' + target + ']]', title, callback, {
'summary': i18n('redirect_to_summary').replace(/\$1/ig, target)
});
}
/**
* 重定向自
* @param {string} origin 重定向页标题
* @param {string} title 重定向目标页标题 默认为当前页
* @param {object} callback
*/
}, {
key: 'redirectFrom',
value: function redirectFrom(origin) {
var title = arguments.length <= 1 || arguments[1] === undefined ? this.pageName : arguments[1];
var callback = arguments.length <= 2 || arguments[2] === undefined ? {} : arguments[2];
var force = arguments.length <= 3 || arguments[3] === undefined ? false : arguments[3];
callback.success = callback.success || new Function();
callback.fail = callback.fail || new Function();
var data = {
summary: i18n('redirect_from_summary').replace(/\$1/ig, origin).replace(/\$2/ig, title)
};
if (!force) {
data.createonly = 'true';
}
this.edit('#REDIRECT [[' + title + ']]', origin, callback, data);
}
/**
* 获得页面维基文本
* @param {object} callback 回调函数
* @param {string} title 页面标题 默认为当前页面
* @param {object} config 设置
*/
}, {
key: 'getWikiText',
value: function getWikiText() {
var callback = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
var title = arguments.length <= 1 || arguments[1] === undefined ? this.pageName : arguments[1];
var config = arguments.length <= 2 || arguments[2] === undefined ? {} : arguments[2];
callback.success = callback.success || new Function();
callback.fail = callback.fail || new Function();
$.ajax({
url: location.protocol + '//' + location.host + mw.config.get('wgScriptPath') + '/index.php',
type: "GET",
dataType: "text",
cache: false,
data: $.extend({
'title': title,
'action': 'raw'
}, config),
beforeSend: function beforeSend() {
console.time('获得页面文本耗时');
},
success: function success(data) {
console.timeEnd('获得页面文本耗时');
callback.success(data);
},
error: function error(e) {
callback.fail(throwError('fail_to_get_wikitext'));
}
});
}
/**
* 解析Wikitext
* @param {string} wikitext 维基文本
* @param {object} callback 回调函数
* @param {object} config 设置
*/
}, {
key: 'parseWikiText',
value: function parseWikiText(wikitext, callback, config) {
if (wikitext === undefined) wikitext = '';
if (callback === undefined) callback = {};
callback.success = callback.success || new Function();
callback.fail = callback.fail || new Function();
$.ajax({
type: 'POST',
dataType: 'json',
data: $.extend({
'format': 'json',
'action': 'parse',
'text': wikitext,
'title': this.pageName,
'pst': 'true'
}, config),
url: this.API,
success: function success(data) {
if (data && data.parse && data.parse.text) {
callback.success(data.parse.text['*']);
} else {
callback.fail(throwError('cant_parse_wikitext'));
}
}
});
}
}]);
return Wikipage;
})();
$(document).ready(function () {
var Wikiplus = (function () {
_createClass(Wikiplus, [{
key: 'initQuickEdit',
/**
* 加载快速编辑 第一步 插入页面按钮并绑定入口事件
*/
value: function initQuickEdit() {
var callback = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
var self = this;
callback.success = callback.success || new Function();
callback.fail = callback.fail || new Function();
if (!(mw.config.get('wgIsArticle') && mw.config.get('wgAction') === "view" && mw.config.get('wgIsProbablyEditable'))) {
console.log('该页面无法编辑 快速编辑界面加载终止');
return;
}
//顶部编辑入口
var topBtn = $('<li>').attr('id', 'Wikiplus-Edit-TopBtn').append($('<span>').append($('<a>').attr('href', 'javascript:void(0)').text('' + i18n('quickedit_topbtn')))).data({
number: -1,
target: self.kotori.pageName
});
if ($('#ca-edit').length > 0 && $('#Wikiplus-Edit-TopBtn').length == 0) {
$('#ca-edit').before(topBtn);
}
if ($('.mw-editsection').length > 0) {
self.sectionMap = {};
//段落快速编辑按钮
var sectionBtn = $('<span>').append($('<span>').addClass('mw-editsection-divider').text(' | ')).append($('<a>').addClass('Wikiplus-Edit-SectionBtn').attr('href', 'javascript:void(0)').text(i18n('quickedit_sectionbtn')));
$('.mw-editsection').each(function (i) {
try {
var editURL = $(this).find("a").last().attr('href');
var sectionNumber = editURL.match(/&[ve]*section\=([^&]+)/)[1].replace(/T-/ig, '');
var sectionTargetName = decodeURI(editURL.match(/title=(.+?)&/)[1]);
var cloneNode = $(this).prev().clone();
cloneNode.find('.mw-headline-number').remove();
var sectionName = $.trim(cloneNode.text());
self.sectionMap[sectionNumber] = {
name: sectionName,
target: sectionTargetName
};
var _sectionBtn = sectionBtn.clone();
_sectionBtn.find('.Wikiplus-Edit-SectionBtn').data({
number: sectionNumber,
name: sectionName,
target: sectionTargetName
});
$(this).find('.mw-editsection-bracket').last().before(_sectionBtn);
} catch (e) {
throwError('fail_to_init_quickedit');
}
});
}
$('.Wikiplus-Edit-SectionBtn').click(function () {
self.initQuickEditInterface($(this)); //直接把DOM传递给下一步
});
$('#Wikiplus-Edit-TopBtn').click(function () {
self.initQuickEditInterface($(this));
});
}
/**
* 加载快速编辑主界面相关内容
*/
}, {
key: 'initQuickEditInterface',
value: function initQuickEditInterface(obj) {
var self = this;
var sectionNumber = obj.data('number');
var sectionTargetName = obj.data('target');
if (this.kotori.inited) {
if ($('.noarticletext').length > 0) {
//这是一个空页面
this.preloadData[sectionTargetName + '.-1'] = i18n('create_page_tip');
}
if (mw.config.get('wgCurRevisionId') === mw.config.get('wgRevisionId')) {
if (this.preloadData[sectionTargetName + '.' + sectionNumber] === undefined) {
this.notice.create.success(i18n('loading'));
this.preload(sectionNumber, sectionTargetName, {
success: function success(data) {
obj.data('content', data);
self.notice.empty();
self.displayQuickEditInterface(obj);
},
fail: function fail(e) {
throwError('fail_to_get_wikitext_when_edit');
}
});
} else {
obj.data('content', self.preloadData[sectionTargetName + '.' + sectionNumber]);
self.displayQuickEditInterface(obj);
}
} else {
this.notice.create.warning(i18n('history_edit_warning'));
this.notice.create.success(i18n('loading'));
this.preload(sectionNumber, sectionTargetName, {
success: function success(data) {
obj.data('content', data);
self.notice.empty();
self.displayQuickEditInterface(obj, '' + i18n('history_edit_warning'));
},
fail: function fail(data) {
throwError('fail_to_get_wikitext_when_edit');
}
}, {
'oldid': mw.config.get('wgRevisionId')
});
}
}
}
/**
* 显示快速编辑界面并绑定事件
*/
}, {
key: 'displayQuickEditInterface',
value: function displayQuickEditInterface(obj) {
var message = arguments.length <= 1 || arguments[1] === undefined ? '' : arguments[1];
var self = this;
var isNewPage = $('.noarticletext').length > 0;
var sectionNumber = obj.data('number');
var sectionName = obj.data('name');
var sectionTargetName = obj.data('target');
var sectionContent = obj.data('content');
var summary = self.getSetting('defaultSummary', {
'sectionName': sectionName,
'sectionNumber': sectionNumber,
'sectionTargetName': sectionTargetName
});
if (summary === undefined) {
if (sectionName === undefined) {
summary = '// Edit via Wikiplus';
} else {
summary = '/* ' + sectionName + ' */ // Edit via Wikiplus';
}
}
//DOM定义
var heightBefore = $(document).scrollTop(); //记住当前高度
var backBtn = $('<span>').attr('id', 'Wikiplus-Quickedit-Back').addClass('Wikiplus-Btn').text('' + i18n('back')); //返回按钮
var jumpBtn = $('<span>').attr('id', 'Wikiplus-Quickedit-Jump').addClass('Wikiplus-Btn').append($('<a>').attr('href', '#Wikiplus-Quickedit').text('' + i18n('goto_editbox'))); //到编辑框
var inputBox = $('<textarea>').attr('id', 'Wikiplus-Quickedit'); //主编辑框
var previewBox = $('<div>').attr('id', 'Wikiplus-Quickedit-Preview-Output'); //预览输出
var summaryBox = $('<input>').attr('id', 'Wikiplus-Quickedit-Summary-Input').attr('placeholder', '' + i18n('summary_placehold')); //编辑摘要输入
var editSubmitBtn = $('<button>').attr('id', 'Wikiplus-Quickedit-Submit').text(i18n(isNewPage ? 'publish_page' : 'publish_change') + '(Ctrl+S)'); //提交按钮
var previewSubmitBtn = $('<button>').attr('id', 'Wikiplus-Quickedit-Preview-Submit').text('' + i18n('preview')); //预览按钮
var isMinorEdit = $('<div>').append($('<input>').attr({ 'type': 'checkbox', 'id': 'Wikiplus-Quickedit-MinorEdit' })).append($('<label>').attr('for', 'Wikiplus-Quickedit-MinorEdit').text(i18n('mark_minoredit') + '(Ctrl+Shift+S)')).css({ 'margin': '5px 5px 5px -3px', 'display': 'inline' });
//DOM定义结束
var editBody = $('<div>').append(backBtn, jumpBtn, previewBox, inputBox, summaryBox, $('<br>'), isMinorEdit, editSubmitBtn, previewSubmitBtn);
this.createDialogBox('' + i18n('quickedit_topbtn') + message, editBody, 1000, function () {
$('#Wikiplus-Quickedit').text(sectionContent);
$('#Wikiplus-Quickedit-Summary-Input').val(summary);
//事件绑定
//返回
$("#Wikiplus-Quickedit-Back").click(function () {
$('.Wikiplus-InterBox').fadeOut('fast', function () {
window.onclose = window.onbeforeunload = undefined; //取消页面关闭确认
$(this).remove();
});
});
//预览
var onPreload = $('<div>').addClass('Wikiplus-Banner').text('' + i18n('loading_preview'));
$('#Wikiplus-Quickedit-Preview-Submit').click(function () {
var wikiText = $('#Wikiplus-Quickedit').val();
$(this).prop('disabled', true);
$('#Wikiplus-Quickedit-Preview-Output').fadeOut(100, function () {
$('#Wikiplus-Quickedit-Preview-Output').html('').append(onPreload);
$('#Wikiplus-Quickedit-Preview-Output').fadeIn(100);
});
$('body').animate({ scrollTop: heightBefore }, 200); //返回顶部
self.kotori.parseWikiText(wikiText, {
success: function success(data) {
$('#Wikiplus-Quickedit-Preview-Output').fadeOut('100', function () {
$('#Wikiplus-Quickedit-Preview-Output').html('<hr><div class="mw-body-content">' + data + '</div><hr>');
$('#Wikiplus-Quickedit-Preview-Output').fadeIn('100');
$('#Wikiplus-Quickedit-Preview-Submit').prop('disabled', false);
});
}
});
});
//提交
$('#Wikiplus-Quickedit-Submit').click(function () {
var wikiText = $('#Wikiplus-Quickedit').val();
var summary = $('#Wikiplus-Quickedit-Summary-Input').val();
var timer = new Date().valueOf();
var onEdit = $('<div>').addClass('Wikiplus-Banner').text('' + i18n('submitting_edit'));
var addtionalConfig = {
'summary': summary
};
if (sectionNumber !== -1) {
addtionalConfig['section'] = sectionNumber;
}
if ($('#Wikiplus-Quickedit-MinorEdit').is(':checked')) {
addtionalConfig['minor'] = 'true';
}
//准备编辑 禁用各类按钮 返回顶部 显示信息
$('#Wikiplus-Quickedit-Submit,#Wikiplus-Quickedit,#Wikiplus-Quickedit-Preview-Submit').prop('disabled', true);
$('body').animate({ scrollTop: heightBefore }, 200);
//开始提交编辑
if (sectionTargetName === self.kotori.pageName) {
$('#Wikiplus-Quickedit-Preview-Output').fadeOut(100, function () {
$('#Wikiplus-Quickedit-Preview-Output').html('').append(onEdit);
$('#Wikiplus-Quickedit-Preview-Output').fadeIn(100);
});
self.kotori.edit(wikiText, sectionTargetName, {
success: function success() {
var useTime = new Date().valueOf() - timer;
$('#Wikiplus-Quickedit-Preview-Output').find('.Wikiplus-Banner').css('background', 'rgba(6, 239, 92, 0.44)');
$('#Wikiplus-Quickedit-Preview-Output').find('.Wikiplus-Banner').text(('' + i18n('edit_success')).replace(/\$1/ig, useTime.toString()));
self.sendStatistic(sectionTargetName, useTime);
window.onclose = window.onbeforeunload = undefined; //取消页面关闭确认
setTimeout(function () {
location.reload();
}, 500);
},
fail: function fail(e) {
console.log(e);
$('#Wikiplus-Quickedit-Submit,#Wikiplus-Quickedit,#Wikiplus-Quickedit-Preview-Submit').prop('disabled', false);
$('.Wikiplus-Banner').css('background', 'rgba(218, 142, 167, 0.65)');
$('.Wikiplus-Banner').html(e.message);
}
}, addtionalConfig);
} else {
//编辑目标非当前页面
$('#Wikiplus-Quickedit-Preview-Output').fadeOut(100, function () {
$('#Wikiplus-Quickedit-Preview-Output').html('').append(onEdit.text(i18n('cross_page_edit')));
$('#Wikiplus-Quickedit-Preview-Output').fadeIn(100);
});
self.kotori.reConstruct(sectionTargetName, {
success: function success() {
$('.Wikiplus-Banner').text(i18n('cross_page_edit_submit'));
self.kotori.edit(wikiText, sectionTargetName, {
success: function success() {
var useTime = new Date().valueOf() - timer;
$('#Wikiplus-Quickedit-Preview-Output').find('.Wikiplus-Banner').css('background', 'rgba(6, 239, 92, 0.44)');
$('#Wikiplus-Quickedit-Preview-Output').find('.Wikiplus-Banner').text(('' + i18n('edit_success')).replace(/\$1/ig, '' + useTime));
self.sendStatistic(sectionTargetName, useTime);
window.onclose = window.onbeforeunload = undefined; //取消页面关闭确认
setTimeout(function () {
location.reload();
}, 500);
},
fail: function fail(e) {
$('#Wikiplus-Quickedit-Submit,#Wikiplus-Quickedit,#Wikiplus-Quickedit-Preview-Submit').prop('disabled', false);
$('.Wikiplus-Banner').css('background', 'rgba(218, 142, 167, 0.65)');
$('.Wikiplus-Banner').text(e.message);
}
}, addtionalConfig);
},
fail: function fail(e) {
$('.Wikiplus-Banner').css('background', 'rgba(218, 142, 167, 0.65)');
$('.Wikiplus-Banner').text(i18n('cross_page_edit_error'));
}
});
}
});
//快捷键
//Ctrl+S提交 Ctrl+Shift+S小编辑
$('#Wikiplus-Quickedit,#Wikiplus-Quickedit-Summary-Input,#Wikiplus-Quickedit-MinorEdit').keydown(function (e) {
if (e.ctrlKey && e.which == 83) {
if (e.shiftKey) {
$('#Wikiplus-Quickedit-MinorEdit').click();
}
$('#Wikiplus-Quickedit-Submit').click();
e.preventDefault();
e.stopPropagation();
}
});
//由于是异步提交 Wikiplus即使编辑失败 也不会丢失数据 唯一丢失数据的可能性是手滑关了页面
//第一 关闭页面确认
$('#Wikiplus-Quickedit').keydown(function () {
window.onclose = window.onbeforeunload = function () {
return '' + i18n('onclose_confirm');
};
});
//Esc退出
if (self.getSetting('esc_to_exit_quickedit') === 'true') {
$(document).keydown(function (e) {
if (e.which === 27) {
$("#Wikiplus-Quickedit-Back").click();
}
});
}
// load DotsSyntaxHighlighter
(function() {
"use strict";
//variables that are preserved between function calls
var wpTextbox0;
var wpTextbox1;
var syntaxStyleTextNode;
var lastText;
var maxSpanNumber = -1; //the number of the last span available, used to tell if creating additional spans is necessary
var highlightSyntaxIfNeededIntervalID;
var attributeObserver;
var parentObserver;
/* Define context-specific regexes, one for every common token that ends the
current context.
An attempt has been made to search for the most common syntaxes first,
thus maximizing performance. Syntaxes that begin with the same character
are searched for at the same time.
Supported wiki syntaxes from most common to least common:
[[internal link]] [http:// named external link]
{{template}} {{{template parameter}}} {| table |}
<tag> <!-- comment -->
http:// bare external link
=Heading= * unordered list # ordered list : indent ; small heading ---- horizontal line
''italic'' '''bold'''
three tildes username four tildes signature five tildes timestamp
&entity;
The tag-matching regex follows the XML standard closely so that users
won't feel like they have to escape sequences that MediaWiki will never
consider to be tags.
Only entities for characters which need to be escaped or cannot be
unambiguously represented in a monospace font are highlighted, such as
Greek letters that strongly resemble Latin letters. Use of other entities
is discouraged as a matter of style. For the same reasons, numeric
entities should be in hexadecimal (giving character codes in decimal only
adds confusion).
Newlines are sucked up into ending tokens (including comments, bare
external links, lists, horizontal lines, signatures, entities, etc.) to
avoid creating spans with nothing but newlines in them.
Flags: g for global search, m for make ^ match the beginning of each line
and $ the end of each line
*/
var wgUrlProtocols = mw.config.get("wgUrlProtocols");
var entityRegexBase = "&(?:(?:n(?:bsp|dash)|m(?:dash|inus)|lt|e[mn]sp|thinsp|amp|quot|gt|shy|zwn?j|lrm|rlm|Alpha|Beta|Epsilon|Zeta|Eta|Iota|Kappa|[Mm]u|micro|Nu|[Oo]micron|[Rr]ho|Tau|Upsilon|Chi)|#x[0-9a-fA-F]+);\n*";
var breakerRegexBase = "\\[(?:\\[|(?:" + wgUrlProtocols + "))|\\{(?:\\{\\{?|\\|)|<(?:[:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][:\\w\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD-\\.\u00B7\u0300-\u036F\u203F-\u203F-\u2040]*(?=/?>| |\n)|!--[^]*?-->\n*)|(?:" + wgUrlProtocols.replace("|\\/\\/", "") + ")[^\\s\"<>[\\]{-}]*[^\\s\",\\.:;<>[\\]{-}]\n*|^(?:=|[*#:;]+\n*|-{4,}\n*)|\\\\'\\\\'(?:\\\\')?|~{3,5}\n*|" + entityRegexBase;
function breakerRegexWithPrefix(prefix)
{
//the stop token has to be at the beginning of the regex so that it takes precedence over substrings of itself.
return new RegExp("(" + prefix + ")\n*|" + breakerRegexBase, "gm");
}
function nowikiTagBreakerRegex(tagName)
{
return new RegExp("(</" + tagName + ">)\n*|" + entityRegexBase, "gm");
}
var defaultBreakerRegex = new RegExp(breakerRegexBase, "gm");
var wikilinkBreakerRegex = breakerRegexWithPrefix("]][a-zA-Z]*");
var namedExternalLinkBreakerRegex = breakerRegexWithPrefix("]");
var parameterBreakerRegex = breakerRegexWithPrefix("}}}");
var templateBreakerRegex = breakerRegexWithPrefix("}}");
var tableBreakerRegex = breakerRegexWithPrefix("\\|}");
var headingBreakerRegex = breakerRegexWithPrefix("\n");
var tagBreakerRegexCache = {};
var nowikiTagBreakerRegexCache = {};
function highlightSyntax()
{
lastText = wpTextbox1.value;
/* Backslashes and apostrophes are CSS-escaped at the beginning and all
parsing regexes and functions are designed to match. On the other hand,
newlines are not escaped until written so that in the regexes ^ and $
work for both newlines and the beginning or end of the string. */
var text = lastText.replace(/['\\]/g, "\\$&") + "\n"; //add a newline to fix scrolling and parsing issues
var i = 0; //the location of the parser as it goes through var text
var css = "";
var spanNumber = 0;
var lastColor;
var before = true;
//writes text into to-be-created span elements of wpTextbox0 using :before and :after pseudo-elements
//both :before and :after are used because using two pseudo-elements per span is significantly faster than doubling the number of spans required
function writeText(text, color)
{
//no need to use another span if using the same color
if (color != lastColor)
{
//whitespace is omitted in the hope of increasing performance
css += "'}#s" + spanNumber; //spans will be created with IDs s0 through sN
if (before)
{
css += ":before{";
before = false;
}
else
{
css += ":after{";
before = true;
++spanNumber;
}
if (color)
{
//"background-color" is 6 characters longer than "background" but the browser processes it faster
css += "background-color:" + color + ";";
}
css += "content:'";
lastColor = color;
}
css += text;
}
/* About assumedBold and assumedItalic:
Highlighting bold or italic markup presents a special challenge
because the actual MediaWiki parser uses multiple passes to determine
which ticks represent start tags and which represent end tags.
Because that would be too slow for us here, we instead keep track of
what kinds of unclosed opening ticks have been encountered and use
that to make a good guess as to whether the next ticks encountered
are an opening tag or a closing tag.
The major downsides to this method are that '''apostrophe italic''
and ''italic apostrophe''' are not highlighted correctly, and bold
and italic are both highlighted in the same color.
To permit ''The best<ref>''Reference Title''</ref> book ever'',
assumedBold and assumedItalic are saved on the stack and reset to
undefined (essentially, false) when recursing into a new block. */
function highlightBlock(color, breakerRegex, assumedBold, assumedItalic)
{
var match;
for (breakerRegex.lastIndex = i; match = breakerRegex.exec(text); breakerRegex.lastIndex = i)
{
if (match[1])
{
//end token found
writeText(text.substring(i, breakerRegex.lastIndex), color);
i = breakerRegex.lastIndex;
return;
}
var endIndexOfLastColor = breakerRegex.lastIndex - match[0].length;
if (i < endIndexOfLastColor) //avoid calling writeText with text == "" to improve performance
{
writeText(text.substring(i, endIndexOfLastColor), color);
}
i = breakerRegex.lastIndex;
switch (match[0].charAt(0)) //cases in this switch should be arranged from most common to least common
{
case "[":
if (match[0].charAt(1) == "[")
{
//wikilink
writeText("[[", syntaxHighlighterConfig.wikilinkColor || color);
highlightBlock(syntaxHighlighterConfig.wikilinkColor || color, wikilinkBreakerRegex);
}
else
{
//named external link
writeText(match[0], syntaxHighlighterConfig.externalLinkColor || color);
highlightBlock(syntaxHighlighterConfig.externalLinkColor || color, namedExternalLinkBreakerRegex);
}
break;
case "{":
if (match[0].charAt(1) == "{")
{
if (match[0].length == 3)
{
//parameter
writeText("{{{", syntaxHighlighterConfig.parameterColor || color);
highlightBlock(syntaxHighlighterConfig.parameterColor || color, parameterBreakerRegex);
}
else
{
//template
writeText("{{", syntaxHighlighterConfig.templateColor || color);
highlightBlock(syntaxHighlighterConfig.templateColor || color, templateBreakerRegex);
}
}
else //|
{
//table
writeText("{|", syntaxHighlighterConfig.tableColor || color);
highlightBlock(syntaxHighlighterConfig.tableColor || color, tableBreakerRegex);
}
break;
case "<":
if (match[0].charAt(1) == "!")
{
//comment tag
writeText(match[0], syntaxHighlighterConfig.commentColor || color);
break;
}
else
{
//some other kind of tag, search for its end
//the search is made easier because XML attributes may not contain the character ">"
var tagEnd = text.indexOf(">", i) + 1;
if (tagEnd == 0)
{
//not a tag, just a "<" with some text after it
writeText("<", color);
i = i - match[0].length + 1;
break;
}
if (text.charAt(tagEnd - 2) == "/")
{
//empty tag
writeText(text.substring(i - match[0].length, tagEnd), syntaxHighlighterConfig.tagColor || color);
i = tagEnd;
}
else
{
var tagName = match[0].substring(1);
if (syntaxHighlighterConfig.sourceTags.indexOf(tagName) != -1)
{
//tag that contains text in a different programming language
var stopAfter = "</" + tagName + ">";
var endIndex = text.indexOf(stopAfter, i);
if (endIndex == -1)
{
endIndex = text.length;
}
else
{
endIndex += stopAfter.length;
}
writeText(text.substring(i - match[0].length, endIndex), syntaxHighlighterConfig.tagColor || color);
i = endIndex;
}
else if (syntaxHighlighterConfig.nowikiTags.indexOf(tagName) != -1)
{
//tag that can contain only HTML entities
writeText(text.substring(i - match[0].length, tagEnd), syntaxHighlighterConfig.tagColor || color);
i = tagEnd;
highlightBlock(syntaxHighlighterConfig.tagColor || color, nowikiTagBreakerRegexCache[tagName]);
}
else
{
//ordinary tag
writeText(text.substring(i - match[0].length, tagEnd), syntaxHighlighterConfig.tagColor || color);
i = tagEnd;
if (!tagBreakerRegexCache[tagName])
{
tagBreakerRegexCache[tagName] = breakerRegexWithPrefix("</" + tagName + ">");
}
highlightBlock(syntaxHighlighterConfig.tagColor || color, tagBreakerRegexCache[tagName]);
}
}
}
break;
case "=":
if (/[^=]=+$/.test(text.substring(i, text.indexOf("\n", i)))) //the line begins and ends with an equals sign and has something else in the middle
{
//heading
writeText("=", syntaxHighlighterConfig.headingColor || color);
highlightBlock(syntaxHighlighterConfig.headingColor || color, headingBreakerRegex);
}
else
{
writeText("=", color); //move on, process this line as regular wikitext
}
break;
case "*":
case "#":
case ":":
//unordered list, ordered list, indent, small heading
//just highlight the marker
writeText(match[0], syntaxHighlighterConfig.listOrIndentColor || color);
break;
case ";":
//small heading
writeText(";", syntaxHighlighterConfig.headingColor || color);
highlightBlock(syntaxHighlighterConfig.headingColor || color, headingBreakerRegex);
break;
case "-":
//horizontal line
writeText(match[0], syntaxHighlighterConfig.hrColor || color);
break;
case "\\":
writeText(match[0], syntaxHighlighterConfig.boldOrItalicColor || color);
if (match[0].length == 6)
{
//bold
if (assumedBold)
{
//end tag
if (assumedItalic)
{
//end of bold part of bold-italic block
//block is now italic-only
assumedBold = false;
}
else
{
//end of bold block
return;
}
}
else
{
//start tag
if (assumedItalic)
{
//start of bold part of previously italic-only block
//block is now bold-italic
assumedBold = true;
}
else
{
//start of bold block
highlightBlock(syntaxHighlighterConfig.boldOrItalicColor || color, defaultBreakerRegex, true, false);
}
}
}
else
{
//italic
if (assumedItalic)
{
//end tag
if (assumedBold)
{
//end of italic part of bold-italic block
//block is now bold-only
assumedItalic = false;
}
else
{
//end of italic block
return;
}
}
else
{
//start tag
if (assumedBold)
{
//start of italic part of previously bold-only block
//block is now bold-italic
assumedItalic = true;
}
else
{
//start of italic block
highlightBlock(syntaxHighlighterConfig.boldOrItalicColor || color, defaultBreakerRegex, false, true);
}
}
}
break;
case "&":
//entity
writeText(match[0], syntaxHighlighterConfig.entityColor || color);
break;
case "~":
//username, signature, timestamp
writeText(match[0], syntaxHighlighterConfig.signatureColor || color);
break;
default:
//bare external link
writeText(match[0], syntaxHighlighterConfig.externalLinkColor || color);
}
}
}
//start!
var startTime = Date.now();
highlightBlock("", defaultBreakerRegex);
//output the leftovers (if any) to make sure whitespace etc. matches
if (i < text.length)
{
writeText(text.substring(i), "");
}
//if highlighting took too long, disable it.
var endTime = Date.now();
/*if (typeof(bestTime) == "undefined")
{
window.bestTime = endTime - startTime;
document.title = bestTime;
highlightSyntaxIfNeededIntervalID = setInterval(highlightSyntax, 250);
}
else
{
if (endTime - startTime < bestTime)
{
bestTime = endTime - startTime;
document.title = bestTime;
}
}//*/
if (endTime - startTime > syntaxHighlighterConfig.timeout)
{
clearInterval(highlightSyntaxIfNeededIntervalID);
wpTextbox1.removeEventListener("input", highlightSyntax);
wpTextbox1.removeEventListener("scroll", syncScrollX);
wpTextbox1.removeEventListener("scroll", syncScrollY);
attributeObserver.disconnect();
parentObserver.disconnect();
syntaxStyleTextNode.nodeValue = "";
var errorMessage = {
ca: "S'ha desactivat el remarcar de sintaxi en aquesta pàgina perquè ha trigat massa temps. El temps màxim permès per a remarcar és $1ms, i el vostre ordinador ha trigat $2ms. Proveu tancar algunes pestanyes i programes i fer clic en \"Mostra la previsualització\" o \"Mostra els canvis\". Si no funciona això, proveu un altre navegador web, i si això no funciona, proveu un ordinador més ràpid.",
de: "Die Syntaxhervorhebung wurde auf dieser Seite deaktiviert, da diese zu lange gedauert hat. Die maximal erlaubte Zeit zur Hervorhebung beträgt $1ms und dein Computer benötigte $2ms. Versuche einige Tabs und Programme zu schließen und klicke \"Vorschau zeigen\" oder \"Änderungen zeigen\". Wenn das nicht funktioniert, probiere einen anderen Webbrowser und wenn immer noch nicht, probiere einen schnelleren Computer.",
el: "Η έμφαση σύνταξης έχει απενεργοποιηθεί σε αυτήν τη σελίδα γιατί αργούσε πολύ. Ο μέγιστος επιτρεπτός χρόνος για την έμφαση σύνταξης είναι $1ms και ο υπολογιστής σας έκανε $2ms. Δοκιμάστε να κλείσετε μερικές καρτέλες και προγράμματα και να κάνετε κλικ στην «Εμφάνιση προεπισκόπησης» ή στην «Εμφάνιση αλλαγών». Αν αυτό δεν δουλέψει, δοκιμάστε έναν διαφορετικό περιηγητή και αν ούτε αυτό δουλέψει, δοκιμάστε έναν ταχύτερο υπολογιστή.",
en: "Syntax highlighting on this page was disabled because it took too long. The maximum allowed highlighting time is $1ms, and your computer took $2ms. Try closing some tabs and programs and clicking \"Show preview\" or \"Show changes\". If that doesn't work, try a different web browser, and if that doesn't work, try a faster computer.",
es: "Se desactivó el resaltar de sintaxis en esta página porque tardó demasiado. El tiempo máximo permitido para resaltar es $1ms, y tu ordenador tardó $2ms. Prueba cerrar algunas pestañas y programas y hacer clic en \"Mostrar previsualización\" o \"Mostrar cambios\". Si no funciona esto, prueba otro navegador web, y si eso no funciona, prueba un ordenador más rápido.",
fa: "از آنجایی که زمان زیادی صرف آن میشد، برجستهسازی نحو در این صفحه غیرفعال شده است. بیشینهٔ زمان برجستهسازی برای ابزار $1ms تعریف شده در حالی که رایانهٔ شما $2ms زمان نیاز داشت. میتوانید بستن برخی سربرگها و برنامهها و سپس کلیککردن دکمهٔ «پیشنمایش» یا «نمایش تغییرات» را بیازمایید. اگر جواب نداد مرورگر دیگری را امتحان کنید؛ و اگر باز هم جواب نداد، رایانهٔ سریعتری را بیازمایید.",
fr: "La coloration syntaxique a été désactivée sur cette page en raison d'un temps de chargement trop important ($2ms). Le temps maximum autorisé est $1ms. Vous pouvez essayer de fermer certains onglets et programmes et cliquez sur \"Prévisualisation\" ou \"Voir mes modifications\". Si cela ne fonctionne pas, essayez un autre navigateur web, et si cela ne fonctionne toujours pas, essayez un ordinateur plus rapide.",
hy: "Շարադասության ընդգծումը այս էջում անջատվել է, քանի որ այն չափից շատ է տևել։ Ընդգծման թույլատրելի առավելագույն ժամանակը $1 միլիվայրկյան է, բայց այս էջում տևել է $2 միլիվայրկյան։ Փորձեք անջատել որոշ ներդիրներ կամ ծրագրեր և սեղմել «Նախադիտել» կամ «Կատարված փոփոխությունները»։ Կրկին չաշխատելու դեպքում փորձեք այլ վեբ դիտարկիչ, եթե կրկին չաշխատի, փորձեք ավելի արագ համակարգիչ։",
io: "Sintaxo-hailaitar en ca pagino esis nekapabligata pro ke konsumis tro multa tempo. La maxima permisata hailaitala tempo es $1ms, e tua ordinatro konsumis $2ms. Probez klozar kelka tabi e programi e kliktar \"Previdar\" o \"Montrez chanji\". Se to ne funcionas, probez altra brauzero, e se to ne funcionas, probez plu rapida ordinatro.",
it: "L'evidenziazione delle sintassi su questa pagina è stata disabilitata perché ha richiesto troppo tempo. Il tempo massimo per l'evidenziazione è di $1ms e al tuo computer sono serviti $2ms. Prova a chiudere alcune schede e programmi e ricarica la pagina cliccando su \"Visualizza anteprima\" o \"Mostra modifiche\". Se non funziona ancora, prova con un web browser differente e, in ultima alternativa, prova ad utilizzare un computer più veloce.",
ko: "이 문서에서의 문법 강조가 너무 오래 걸러서 해제되었습니다. 최대로 할당된 강조 시간은 $1ms인데, 당신의 컴퓨터는 $2ms이나 걸렸습니다. 탭과 프로그램을 일부 닫으신 후에 \"미리 보기\"나 \"차이 보기\"를 클릭하시기 바랍니다. 만약 작동하지 않으면 다른 웹 브라우저로 시도해보시고, 그래도 안되면 더 빠른 컴퓨터를 이용하십시오",
pt: "O marcador de sintaxe foi desativado nesta página porque demorou demais. O tempo máximo permitido para marcar é de $1ms, e seu computador demorou $2ms. Tente fechar algumas abas e programas e clique em \"Mostrar previsão\" ou \"Mostrar alterações\". Se isso não funcionar, tente usar um outro navegador web, e se ainda não funcionar, tente em um computador mais rápido.",
ru: "Подсветка синтаксиса на странице была отключена, так как заняла слишком долго. Максимальное допустимое время операции - $1мс, сейчас на вашем компьютере она заняла $2мс. Попробуйте закрыть несколько вкладок и программ, затем нажать «Предварительный просмотр» или «Внесённые изменения». Если это не поможет, попробуйте другой браузер; если и это не поможет, используйте более быстрый компьютер.",
sr: "Истицање синтаксе на овој страници је онемогућено јер се одвија предуго. Максимално дозвољено време истицања је $1ms, а на Вашем рачунару траје $2ms. Покушајте затворити неке картице и програме или кликните на „Прикажи претпреглед” или „Прикажи измене”. Ако то не ради, покушајте са другим веб-прегледачем, а ако и тада не ради, покушајте са бржим рачунаром.",
};
var wgUserLanguage = mw.config.get("wgUserLanguage");
errorMessage = errorMessage[wgUserLanguage] || errorMessage[wgUserLanguage.substring(0, wgUserLanguage.indexOf("-"))] || errorMessage.en;
wpTextbox1.style.backgroundColor = "";
wpTextbox1.style.marginTop = wpTextbox0.style.marginTop;
wpTextbox0.removeAttribute("dir");
wpTextbox0.removeAttribute("lang");
wpTextbox0.setAttribute("style", "color:red; font-size:small");
wpTextbox0.textContent = errorMessage.replace("$1", syntaxHighlighterConfig.timeout).replace("$2", endTime - startTime);
return;
}
//do we have enough span elements to match the generated CSS?
//this step isn't included in the above benchmark because it takes a highly variable amount of time
if (maxSpanNumber < spanNumber)
{
var fragment = document.createDocumentFragment();
do
{
fragment.appendChild(document.createElement("span")).id = "s" + ++maxSpanNumber;
}
while (maxSpanNumber < spanNumber);
wpTextbox0.appendChild(fragment);
}
/* finish CSS: move the extra '} from the beginning to the end and CSS-
escape newlines. CSS ignores the space after the hex code of the
escaped character */
syntaxStyleTextNode.nodeValue = css.substring(2).replace(/\n/g, "\\A ") + "'}";
}
function syncScrollX()
{
wpTextbox0.scrollLeft = wpTextbox1.scrollLeft;
}
function syncScrollY()
{
wpTextbox0.scrollTop = wpTextbox1.scrollTop;
}
function syncTextDirection()
{
wpTextbox0.dir = wpTextbox1.dir;
}
function syncParent()
{
if (wpTextbox1.previousSibling != wpTextbox0)
{
wpTextbox1.parentNode.insertBefore(wpTextbox0, wpTextbox1);
parentObserver.disconnect();
parentObserver.observe(wpTextbox1.parentNode, {childList: true});
}
}
//this function runs once every 500ms to detect changes to wpTextbox1's text that the input event does not catch
//this happens when another script changes the text without knowing that the syntax highlighter needs to be informed
function highlightSyntaxIfNeeded()
{
if (wpTextbox1.value != lastText)
{
highlightSyntax();
}
if (wpTextbox1.scrollLeft != wpTextbox0.scrollLeft)
{
syncScrollX();
}
if (wpTextbox1.scrollTop != wpTextbox0.scrollTop)
{
syncScrollY();
}
if (wpTextbox1.offsetHeight != wpTextbox0.offsetHeight)
{
var height = wpTextbox1.offsetHeight + "px";
wpTextbox0.style.height = height;
wpTextbox1.style.marginTop = "-" + height;
}
}
function setup()
{
function configureColor(parameterName, hardcodedFallback, defaultOk)
{
if (typeof(syntaxHighlighterConfig[parameterName]) == "undefined")
{
syntaxHighlighterConfig[parameterName] = syntaxHighlighterSiteConfig[parameterName];
}
if (syntaxHighlighterConfig[parameterName] == "normal")
{
syntaxHighlighterConfig[parameterName] = hardcodedFallback;
}
else if (typeof(syntaxHighlighterConfig[parameterName]) != "undefined")
{
return;
}
else if (typeof(syntaxHighlighterConfig.defaultColor) != "undefined" && defaultOk)
{
syntaxHighlighterConfig[parameterName] = syntaxHighlighterConfig.defaultColor;
}
else
{
syntaxHighlighterConfig[parameterName] = hardcodedFallback;
}
}
window.syntaxHighlighterSiteConfig = window.syntaxHighlighterSiteConfig || {};
window.syntaxHighlighterConfig = window.syntaxHighlighterConfig || {};
//use 3-digit colors instead of 6-digit colors for performance
configureColor("backgroundColor", "#FFF", false); //white
configureColor("foregroundColor", "#000", false); //black
configureColor("boldOrItalicColor", "#EEE", true); //gray
configureColor("commentColor", "#EFE", true); //green
configureColor("entityColor", "#DFD", true); //green
configureColor("externalLinkColor", "#EFF", true); //cyan
configureColor("headingColor", "#EEE", true); //gray
configureColor("hrColor", "#EEE", true); //gray
configureColor("listOrIndentColor", "#EFE", true); //green
configureColor("parameterColor", "#FC6", true); //orange
configureColor("signatureColor", "#FC6", true); //orange
configureColor("tagColor", "#FEF", true); //pink
configureColor("tableColor", "#FFC", true); //yellow
configureColor("templateColor", "#FFC", true); //yellow
configureColor("wikilinkColor", "#EEF", true); //blue
//tag lists are ordered from most common to least common
syntaxHighlighterConfig.nowikiTags = syntaxHighlighterConfig.nowikiTags || syntaxHighlighterSiteConfig.nowikiTags || ["nowiki", "pre"];
syntaxHighlighterConfig.sourceTags = syntaxHighlighterConfig.sourceTags || syntaxHighlighterSiteConfig.sourceTags || ["math", "syntaxhighlight", "source", "timeline", "hiero"];
syntaxHighlighterConfig.timeout = syntaxHighlighterConfig.timeout || syntaxHighlighterSiteConfig.timeout || 50;
syntaxHighlighterConfig.nowikiTags.forEach(function(tagName) {
nowikiTagBreakerRegexCache[tagName] = nowikiTagBreakerRegex(tagName);
});
wpTextbox0 = document.createElement("div");
wpTextbox1 = document.getElementById("Wikiplus-Quickedit");
var syntaxStyleElement = document.createElement("style");
syntaxStyleTextNode = syntaxStyleElement.appendChild(document.createTextNode(""));
//the styling of the textbox and the background div must be kept very similar
var wpTextbox1Style = window.getComputedStyle(wpTextbox1);
//horizontal resize would look horribly choppy, better to make the user resize the browser window instead
var resize = (wpTextbox1Style.resize == "vertical" || wpTextbox1Style.resize == "both" ? "vertical" : "none");
wpTextbox0.dir = wpTextbox1.dir;
wpTextbox0.id = "wpTextbox0";
wpTextbox0.lang = wpTextbox1.lang; //lang determines which font "monospace" is
wpTextbox0.style.backgroundColor = syntaxHighlighterConfig.backgroundColor;
wpTextbox0.style.border = "1px solid transparent";
wpTextbox0.style.boxSizing = "border-box";
wpTextbox0.style.clear = wpTextbox1Style.clear;
wpTextbox0.style.color = "transparent"; //makes it look just a little bit smoother
wpTextbox0.style.fontFamily = wpTextbox1Style.fontFamily;
wpTextbox0.style.fontSize = wpTextbox1Style.fontSize;
wpTextbox0.style.lineHeight = "normal";
wpTextbox0.style.marginBottom = "0";
wpTextbox0.style.marginLeft = "0";
wpTextbox0.style.marginRight = "0";
wpTextbox0.style.marginTop = wpTextbox1Style.marginTop;
wpTextbox0.style.overflowX = "auto";
wpTextbox0.style.overflowY = "scroll";
wpTextbox0.style.resize = resize;
wpTextbox0.style.tabSize = wpTextbox1Style.tabSize;
wpTextbox0.style.whiteSpace = "pre-wrap";
wpTextbox0.style.width = "100%";
wpTextbox0.style.wordWrap = "normal"; //see below
wpTextbox1.style.backgroundColor = "transparent";
wpTextbox1.style.border = "1px inset gray";
wpTextbox1.style.boxSizing = "border-box";
wpTextbox1.style.color = syntaxHighlighterConfig.foregroundColor;
wpTextbox1.style.fontSize = wpTextbox1Style.fontSize; //resolves alignment problems on mobile chrome
wpTextbox1.style.lineHeight = "normal";
wpTextbox1.style.marginBottom = wpTextbox1Style.marginBottom; //lock to pixel value because the top margin was also locked to a pixel value when it was moved to wpTextbox0
wpTextbox1.style.marginLeft = "0";
wpTextbox1.style.marginRight = "0";
wpTextbox1.style.overflowX = "auto";
wpTextbox1.style.overflowY = "scroll";
wpTextbox1.style.padding = "0";
wpTextbox1.style.resize = resize;
wpTextbox1.style.width = "100%";
wpTextbox1.style.wordWrap = "normal"; //overall more visually appealing
//lock both heights to pixel values so that the browser zoom feature works better
wpTextbox1.style.height = wpTextbox0.style.height = wpTextbox1.offsetHeight + "px";
//insert wpTextbox0 underneath wpTextbox1
wpTextbox1.style.marginTop = -wpTextbox1.offsetHeight + "px";
wpTextbox1.parentNode.insertBefore(wpTextbox0, wpTextbox1);
document.head.appendChild(syntaxStyleElement);
wpTextbox1.addEventListener("input", highlightSyntax);
wpTextbox1.addEventListener("scroll", syncScrollX);
wpTextbox1.addEventListener("scroll", syncScrollY);
attributeObserver = new MutationObserver(syncTextDirection);
attributeObserver.observe(wpTextbox1, {attributes: true});
parentObserver = new MutationObserver(syncParent);
parentObserver.observe(wpTextbox1.parentNode, {childList: true});
highlightSyntaxIfNeededIntervalID = setInterval(highlightSyntaxIfNeeded, 500);
highlightSyntax();
}
//enable the highlighter only when editing wikitext pages
//in the future a separate parser could be added for CSS and JS pages
//blacklist Internet Explorer and Edge, they're just too broken
var wgAction = mw.config.get("wgAction");
var layoutEngine = $.client.profile().layout;
setup();
})();
// end DotsSyntaxHighlighter
});
}
/**
* 编辑设置
*/
}, {
key: 'editSettings',
value: function editSettings() {
var self = this;
self.addFunctionButton(i18n('wikiplus_settings'), 'Wikiplus-Settings-Intro', function () {
var input = $('<textarea>').attr('id', 'Wikiplus-Setting-Input').attr('rows', '10');
var applyBtn = $('<div>').addClass('Wikiplus-InterBox-Btn').attr('id', 'Wikiplus-Setting-Apply').text(i18n('submit'));
var cancelBtn = $('<div>').addClass('Wikiplus-InterBox-Btn').attr('id', 'Wikiplus-Setting-Cancel').text(i18n('cancel'));
var content = $('<div>').append(input).append($('<hr>')).append(applyBtn).append(cancelBtn); //拼接
self.createDialogBox(i18n('wikiplus_settings_desc'), content, 600, function () {
if (localStorage.Wikiplus_Settings) {
$('#Wikiplus-Setting-Input').val(localStorage.Wikiplus_Settings);
} else {
$('#Wikiplus-Setting-Input').attr('placeholder', i18n('wikiplus_settings_placeholder'));
}
$('#Wikiplus-Setting-Apply').click(function () {
var settings = $('#Wikiplus-Setting-Input').val();
try {
settings = JSON.parse(settings);
} catch (e) {
self.notice.create.error(i18n('wikiplus_settings_grammar_error'));
return;
}
localStorage.Wikiplus_Settings = JSON.stringify(settings);
$('.Wikiplus-InterBox-Content').html('').append($('<div>').addClass('Wikiplus-Banner').text(i18n('wikiplus_settings_saved')));
$('.Wikiplus-InterBox').fadeOut(300, function () {
$(this).remove();
});
});
$('#Wikiplus-Setting-Cancel').click(function () {
$('.Wikiplus-InterBox').fadeOut(300, function () {
$(this).remove();
});
});
});
});
}
/**
* 快速重定向页面至此页面
*/
}, {
key: 'simpleRedirector',
value: function simpleRedirector() {
var self = this;
self.addFunctionButton(i18n('redirect_from'), 'Wikiplus-SR-Intro', function () {
var input = $('<input>').addClass('Wikiplus-InterBox-Input');
var applyBtn = $('<div>').addClass('Wikiplus-InterBox-Btn').attr('id', 'Wikiplus-SR-Apply').text(i18n('submit'));
var cancelBtn = $('<div>').addClass('Wikiplus-InterBox-Btn').attr('id', 'Wikiplus-SR-Cancel').text(i18n('cancel'));
var continueBtn = $('<div>').addClass('Wikiplus-InterBox-Btn').attr('id', 'Wikiplus-SR-Continue').text(i18n('continue'));
var content = $('<div>').append(input).append($('<hr>')).append(applyBtn).append(cancelBtn); //拼接
self.createDialogBox(i18n('redirect_desc'), content, 600, function () {
applyBtn.click(function () {
if ($('.Wikiplus-InterBox-Input').val() != '') {
var title = $('.Wikiplus-InterBox-Input').val();
$('.Wikiplus-InterBox-Content').html('<div class="Wikiplus-Banner">' + i18n('submitting_edit') + '</div>');
self.kotori.redirectFrom(title, self.kotori.pageName, {
success: function success() {
$('.Wikiplus-Banner').text(i18n('redirect_saved'));
$('.Wikiplus-InterBox').fadeOut(300);
location.href = mw.config.get('wgArticlePath').replace(/\$1/ig, title);
},
fail: function fail(e) {
$('.Wikiplus-Banner').css('background', 'rgba(218, 142, 167, 0.65)');
$('.Wikiplus-Banner').text(e.message);
if (e.number === 1018) {
// 目标页面已经存在 确认哟
$('.Wikiplus-InterBox-Content').append($('<hr>')).append(continueBtn).append(cancelBtn);
continueBtn.click(function () {
$('.Wikiplus-InterBox-Content').html('<div class="Wikiplus-Banner">' + i18n('submitting_edit') + '</div>');
self.kotori.redirectFrom(title, self.kotori.pageName, {
success: function success() {
$('.Wikiplus-Banner').text(i18n('redirect_saved'));
$('.Wikiplus-InterBox').fadeOut(300);
location.href = mw.config.get('wgArticlePath').replace(/\$1/ig, title);
},
fail: function fail(e) {
$('.Wikiplus-Banner').css('background', 'rgba(218, 142, 167, 0.65)');
$('.Wikiplus-Banner').text(e.message);
}
}, true);
});
cancelBtn.click(function () {
$('.Wikiplus-InterBox-Close').click();
});
}
}
});
} else {
self.showNotice.create.warning(i18n('empty_input'));
}
});
$('#Wikiplus-SR-Cancel').click(function () {
$('.Wikiplus-InterBox').fadeOut(300, function () {
$(this).remove();
});
});
});
});
}
/**
* 预读取相关事件绑定
*/
}, {
key: 'preloadEventBinding',
value: function preloadEventBinding() {
var self = this;
$("#toc").children("ul").find("a").each(function (i) {
$(this).mouseover(function () {
$(this).unbind('mouseover');
self.preload(i + 1);
});
});
}
/**
* 检查多语言定义缓存是否过期
*/
}, {
key: 'checki18nCache',
value: function checki18nCache() {
if (localStorage.Wikiplus_i18nCache) {
try {
var _i18nData = JSON.parse(localStorage.Wikiplus_i18nCache);
for (var languages in _i18nData) {
if (_i18nData[languages]['__version'] === this.langVersion) {
i18nData[_i18nData[languages]['__language']] = _i18nData[languages];
} else {
console.log('多语言文件[' + languages + ']已经过期');
loadLanguage(_i18nData[languages]['__language']); //尝试重新取
}
}
} catch (e) {
throwError('cant_parse_i18ncache');
}
} else {
localStorage.Wikiplus_i18nCache = JSON.stringify(i18nData);
}
}
/**
* 为所有可能的编辑链接加上快速编辑按钮
*/
}, {
key: 'editEveryWhere',
value: function editEveryWhere() {
var self = this;
$('#mw-content-text a.external').each(function (i) {
var url = $(this).attr('href');
var reg = /(([^?&=]+)(?:=([^?&=]*))*)/g;
var params = {},
match;
while (match = reg.exec(url)) {
params[match[2]] = decodeURIComponent(match[3]);
}
if (params.action === 'edit' && params.title !== undefined && params.section !== 'new') {
$(this).after($('<a>').attr({
'href': "javascript:void(0)",
'class': "Wikiplus-Edit-EveryWhereBtn"
}).text('(' + i18n('quickedit_sectionbtn') + ')').data({
'target': decodeURIComponent(params.title),
'number': params.section || -1
}));
}
});
$('.Wikiplus-Edit-EveryWhereBtn').click(function () {
console.log($(this).data());
self.initQuickEditInterface($(this));
});
}
/**
* ===========================
* 以上是功能函数 以下是通用函数
* ===========================
*/
/**
* 创建对话框
* @param {string} title 对话框标题
* @param {HTML} content 内容
* @param {interger} width 宽度 单位像素 默认600px
* @param {function} callback 回调函数
*/
}, {
key: 'createDialogBox',
value: function createDialogBox() {
var title = arguments.length <= 0 || arguments[0] === undefined ? 'Dialog Box' : arguments[0];
var content = arguments.length <= 1 || arguments[1] === undefined ? $('<div>') : arguments[1];
var width = arguments.length <= 2 || arguments[2] === undefined ? 600 : arguments[2];
var callback = arguments.length <= 3 || arguments[3] === undefined ? new Function() : arguments[3];
if ($('.Wikiplus-InterBox').length > 0) {
$('.Wikiplus-InterBox').each(function () {
$(this).remove();
});
}
var clientWidth = document.body.clientWidth;
var clientHeight = document.body.clientHeight;
var diglogBox = $('<div>').addClass('Wikiplus-InterBox').css({
'margin-left': clientWidth / 2 - width / 2,
'top': $(document).scrollTop() + clientHeight * 0.2,
'display': 'none'
}).append($('<div>').addClass('Wikiplus-InterBox-Header').html(title)).append($('<div>').addClass('Wikiplus-InterBox-Content').append(content)).append($('<span>').text('×').addClass('Wikiplus-InterBox-Close'));
$('body').append(diglogBox);
$('.Wikiplus-InterBox').width(width);
$('.Wikiplus-InterBox-Close').click(function () {
$(this).parent().fadeOut('fast', function () {
window.onclose = window.onbeforeunload = undefined; //取消页面关闭确认
$(this).remove();
});
});
//拖曳
var bindDragging = function bindDragging(element) {
element.mousedown(function (e) {
var baseX = e.clientX;
var baseY = e.clientY;
var baseOffsetX = element.parent().offset().left;
var baseOffsetY = element.parent().offset().top;
$(document).mousemove(function (e) {
element.parent().css({
'margin-left': baseOffsetX + e.clientX - baseX,
'top': baseOffsetY + e.clientY - baseY
});
});
$(document).mouseup(function () {
element.unbind('mousedown');
$(document).unbind('mousemove');
$(document).unbind('mouseup');
bindDragging(element);
});
});
};
bindDragging($('.Wikiplus-InterBox-Header'));
$('.Wikiplus-InterBox').fadeIn(500);
callback();
}
/**
* 增加功能按钮
* @param {string} text 按钮名
* @param {string} id 按钮id
* @param {function} clickEvent 点击事件
*/
}, {
key: 'addFunctionButton',
value: function addFunctionButton(text, id, clickEvent) {
var button = $('<li></li>').attr('id', id).append($('<a></a>').attr('href', 'javascript:void(0);').text(text));
if ($('#p-cactions').length > 0) {
$('#p-cactions ul').append(button);
$('#p-cactions ul').find('li').last().click(clickEvent);
} else {
throwError('cant_add_funcbtn');
}
}
/**
* 预读取内容
* @param {interger} section 段落编号 默认为-1即全页
* @param {string} title 页面名 默认为当前页面
* @param {object} callback 回调
*/
}, {
key: 'preload',
value: function preload() {
var section = arguments.length <= 0 || arguments[0] === undefined ? -1 : arguments[0];
var title = arguments.length <= 1 || arguments[1] === undefined ? this.kotori.pageName : arguments[1];
var callback = arguments.length <= 2 || arguments[2] === undefined ? {} : arguments[2];
var config = arguments.length <= 3 || arguments[3] === undefined ? {} : arguments[3];
callback.success = callback.success || new Function();
callback.fail = callback.fail || new Function();
var self = this;
if (config.oldid !== undefined) {
// oldid 优先于 页面名
console.log(typeof config.oldid);
if (this.preloadData[config.oldid + '.' + section]) {
console.log('[修订版本' + config.oldid + '.' + section + ']已经预读取 跳过本次预读取');
callback.success(this.preloadData[config.oldid + '.' + section]);
return;
}
} else {
if (this.preloadData[title + '.' + section]) {
console.log('[' + title + '.' + section + ']已经预读取 跳过本次预读取');
callback.success(this.preloadData[title + '.' + section]);
return;
}
}
this.kotori.getWikiText({
success: function success(data) {
if (config.oldid !== undefined) {
self.preloadData[config.oldid + '.' + section] = data;
console.log('预读取[修订版本' + config.oldid + '.' + section + ']成功');
} else {
self.preloadData[title + '.' + section] = data;
console.log('预读取[' + title + '.' + section + ']成功');
}
callback.success(data);
},
fail: function fail(e) {
if (config.oldid !== undefined) {
console.log('预读取[修订版本' + config.oldid + '.' + section + ']失败');
} else {
console.log('预读取[' + title + '.' + section + ']失败:' + e.message);
}
callback.fail(e);
}
}, title, $.extend({
section: section === -1 ? '' : section
}, config));
}
/**
* 提交统计数据
* @param {string} title 页面名
* @param {interger} useTime 用时 单位毫秒
*/
}, {
key: 'sendStatistic',
value: function sendStatistic(title, useTime) {
if (title === undefined) title = mw.config.get('wgPageName');
if (localStorage.Wikiplus_SendStatistics == 'True') {
$.ajax({
url: scriptPath + '/statistics/api/submit',
type: 'POST',
dataType: 'json',
data: {
'wikiname': mw.config.get('wgSiteName'),
'usetime': useTime,
'username': mw.config.get('wgUserName'),
'pagename': title
},
success: function success(data) {
//提交成功
}
});
}
}
/**
* 检查安装
* @param {function} callback 回调函数
*/
}, {
key: 'checkInstall',
value: function checkInstall(callback) {
var self = this;
if (!localStorage.Wikiplus_Installed || localStorage.Wikiplus_Installed == 'False') {
//安装
var install = function install() {
localStorage.Wikiplus_Installed = 'True'; //标记已安装
localStorage.Wikiplus_Version = self.version;
localStorage.Wikiplus_StartUseAt = new Date().valueOf();
localStorage.Wikiplus_SrartEditCount = mw.config.get('wgUserEditCount');
localStorage.Wikiplus_Settings = JSON.stringify(self.defaultSettings);
$('.Wikiplus-InterBox').fadeOut('fast', function () {
self.notice.create.success(i18n('install_finish'));
$(this).remove();
});
};
var notice = $('<div>').text(i18n('install_tip').replace(/\$1/ig, mw.config.get('wgSiteName'))).attr('id', 'Wikiplus-InterBox-Content');
var applyBtn = $('<div>').addClass('Wikiplus-InterBox-Btn').attr('id', 'Wikiplus-Setting-Apply').text(i18n('accept'));
var cancelBtn = $('<div>').addClass('Wikiplus-InterBox-Btn').attr('id', 'Wikiplus-Setting-Cancel').text(i18n('decline'));
var content = $('<div>').append(notice).append($('<hr>')).append(applyBtn).append(cancelBtn); //拼接
self.createDialogBox('安装Wikiplus', content, 600, function () {
$('#Wikiplus-InterBox-Content').css('text-align', 'left');
$('#Wikiplus-Setting-Apply').click(function () {
localStorage.Wikiplus_SendStatistics = 'True';
install();
});
$('#Wikiplus-Setting-Cancel').click(function () {
localStorage.Wikiplus_SendStatistics = 'False';
install();
});
});
}
}
/**
* 获取设置值
* @param {string} key 键名
* @param {object} object 传入可用参数
*/
}, {
key: 'getSetting',
value: function getSetting(key, object) {
var w = object;
try {
var settings = JSON.parse(localStorage.Wikiplus_Settings);
} catch (e) {
return localStorage.Wikiplus_Settings || '';
}
try {
var _setting = new Function('return ' + settings[key]);
if (typeof _setting == 'function') {
try {
if (_setting()(w) === true) {
return undefined;
} else {
return _setting()(w) || settings[key];
}
} catch (e) {
return settings[key];
}
} else {
return settings[key];
}
} catch (e) {
try {
return settings[key];
} catch (e) {
return undefined;
}
}
}
}, {
key: 'initBasicFunctions',
value: function initBasicFunctions() {
this.initQuickEdit(); //加载快速编辑
this.editSettings(); //编辑设置
this.simpleRedirector(); //快速重定向
this.preloadEventBinding(); //预读取
if (!this.getSetting('disableEditEveryWhere')) {
this.editEveryWhere(); //任意编辑
}
}
}, {
key: 'initRecentChangesPageFunctions',
value: function initRecentChangesPageFunctions() {}
}, {
key: 'initAdvancedFunctions',
value: function initAdvancedFunctions() {}
}]);
function Wikiplus() {
_classCallCheck(this, Wikiplus);
this.version = '2.2.6';
this.langVersion = '208';
this.releaseNote = '调整段落快速编辑位置';
this.notice = new MoeNotification();
this.inValidNameSpaces = [-1, 8964];
this.defaultSettings = {
'key': 'value',
'documatation': 'http://zh.moegirl.org/User:%E5%A6%B9%E7%A9%BA%E9%85%B1/Wikiplus/%E8%AE%BE%E7%BD%AE%E8%AF%B4%E6%98%8E'
};
console.log('正在加载Wikiplus ' + this.version);
//载入CSS
$("head").append("<link>");
$("head").children(":last").attr({
rel: "stylesheet",
type: "text/css",
href: scriptPath + '/wikiplus.css'
});
//一些初始化工作
this.preloadData = {};
this.checkInstall(); //安装检查
//语言检测
var language = this.getSetting('language') && this.getSetting('language').toLowerCase() || window.navigator.language.toLowerCase();
//版本检查
if (!(this.version === localStorage.Wikiplus_Version)) {
localStorage.Wikiplus_Version = this.version;
this.notice.create.success('Wikiplus ' + this.version);
this.notice.create.success(language === 'zh-cn' ? this.releaseNote : 'Minor bug fixes.'); // 避免给其他语言用户不必要的理解困难
}
if (i18nData[language] === undefined) {
loadLanguage(language);
}
//真正的初始化
if (!inArray(mw.config.get('wgNameSpaceNumber'), this.inValidNameSpaces) && mw.config.get('wgIsArticle') && mw.config.get('wgAction') === "view") {
this.kotori = new Wikipage();
this.checki18nCache();
this.initBasicFunctions();
} else {
console.log('不符合加载条件 Wikiplus终止');
}
}
return Wikiplus;
})();
window.Wikiplus = new Wikiplus();
});
});