“MediaWiki:Gadget-DotsSyntaxHighlighter”与“MediaWiki:Gadget-DotsSyntaxHighlighter.js”:页面之间的差异

H萌娘,万物皆可H的百科全书!
(页面间差异)
跳到导航 跳到搜索
imported>=海豚=
无编辑摘要
 
imported>=海豚=
 
第1行: 第1行:
Syntax highlighter* ——<small> 由 Nbdd0121 开发的''' 编辑框代码高亮工具'''。</small>
/* Based on https://www.mediawiki.org/wiki/User:Remember_the_dot/Syntax_highlighter.js */
/* https://www.mediawiki.org/wiki/User:NicoV/Syntax_highlighter.js */
/* This file may be used under the terms of any of the following
  licenses, as well as any later version of the same licenses:
 
  GNU General Public License 2.0
  <https://www.gnu.org/licenses/old-licenses/gpl-2.0.html>
 
  Creative Commons Attribution-ShareAlike 3.0 Unported License
  <https://creativecommons.org/licenses/by-sa/3.0/>
 
  GNU Free Documentation License 1.2
  <https://www.gnu.org/licenses/old-licenses/fdl-1.2.html>
*/
 
mw.loader.using("jquery.client", function() {
   "use strict";
 
   var wpTextbox0;
   var wpTextbox1;
   var syntaxStyleTextNode;
   var lastText;
   var maxSpanNumber = -1;
   var highlightSyntaxIfNeededIntervalID;
   var attributeObserver;
   var parentObserver;
 
   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)
   {
     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;
     var text = lastText.replace(/['\\]/g, "\\$&") + "\n";
     var i = 0;
 
     var css = "";
     var spanNumber = 0;
     var lastColor;
     var before = true;
 
     function writeText(text, color)
     {
       if (color != lastColor)
       {
         css += "'}#s" + spanNumber;
         if (before)
         {
           css += ":before{";
           before = false;
         }
         else
         {
           css += ":after{";
           before = true;
           ++spanNumber;
         }
         if (color)
         {
           css += "background-color:" + color + ";";
         }
         css += "content:'";
         lastColor = color;
       }
       css += text;
     }
 
     function highlightBlock(color, breakerRegex, assumedBold, assumedItalic)
     {
       var match;
 
       for (breakerRegex.lastIndex = i; match = breakerRegex.exec(text); breakerRegex.lastIndex = i)
       {
         if (match[1])
         {
           writeText(text.substring(i, breakerRegex.lastIndex), color);
           i = breakerRegex.lastIndex;
           return;
         }
 
         var endIndexOfLastColor = breakerRegex.lastIndex - match[0].length;
         if (i < endIndexOfLastColor)
         {
           writeText(text.substring(i, endIndexOfLastColor), color);
         }
 
         i = breakerRegex.lastIndex;
 
         switch (match[0].charAt(0))
         {
           case "[":
             if (match[0].charAt(1) == "[")
             {
               writeText("[[", syntaxHighlighterConfig.wikilinkColor || color);
               highlightBlock(syntaxHighlighterConfig.wikilinkColor || color, wikilinkBreakerRegex);
             }
             else
             {
               writeText(match[0], syntaxHighlighterConfig.externalLinkColor || color);
               highlightBlock(syntaxHighlighterConfig.externalLinkColor || color, namedExternalLinkBreakerRegex);
             }
             break;
           case "{":
             if (match[0].charAt(1) == "{")
             {
               if (match[0].length == 3)
               {
                 writeText("{{{", syntaxHighlighterConfig.parameterColor || color);
                 highlightBlock(syntaxHighlighterConfig.parameterColor || color, parameterBreakerRegex);
               }
               else
               {
                 writeText("{{", syntaxHighlighterConfig.templateColor || color);
                 highlightBlock(syntaxHighlighterConfig.templateColor || color, templateBreakerRegex);
               }
             }
             else
             {
               writeText("{|", syntaxHighlighterConfig.tableColor || color);
               highlightBlock(syntaxHighlighterConfig.tableColor || color, tableBreakerRegex);
             }
             break;
           case "<":
             if (match[0].charAt(1) == "!")
             {
               writeText(match[0], syntaxHighlighterConfig.commentColor || color);
               break;
             }
             else
             {
               var tagEnd = text.indexOf(">", i) + 1;
               if (tagEnd == 0)
               {
                 writeText("<", color);
                 i = i - match[0].length + 1;
                 break;
               }
 
               if (text.charAt(tagEnd - 2) == "/" || syntaxHighlighterConfig.voidTags.indexOf(match[0].substring(1)) != -1)
               {
                 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)
                 {
                   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)
                 {
                   writeText(text.substring(i - match[0].length, tagEnd), syntaxHighlighterConfig.tagColor || color);
                   i = tagEnd;
                   highlightBlock(syntaxHighlighterConfig.tagColor || color, nowikiTagBreakerRegexCache[tagName]);
                 }
                 else
                 {
                   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))))
             {
               writeText("=", syntaxHighlighterConfig.headingColor || color);
               highlightBlock(syntaxHighlighterConfig.headingColor || color, headingBreakerRegex);
             }
             else
             {
               writeText("=", color);
             }
             break;
           case "*":
           case "#":
           case ":":
             writeText(match[0], syntaxHighlighterConfig.listOrIndentColor || color);
             break;
           case ";":
             writeText(";", syntaxHighlighterConfig.headingColor || color);
             highlightBlock(syntaxHighlighterConfig.headingColor || color, headingBreakerRegex);
             break;
           case "-":
             writeText(match[0], syntaxHighlighterConfig.hrColor || color);
             break;
           case "\\":
             writeText(match[0], syntaxHighlighterConfig.boldOrItalicColor || color);
             if (match[0].length == 6)
             {
               if (assumedBold)
               {
                 if (assumedItalic)
                 {
                   assumedBold = false;
                 }
                 else
                 {
                   return;
                 }
               }
               else
               {
                 if (assumedItalic)
                 {
                   assumedBold = true;
                 }
                 else
                 {
                   highlightBlock(syntaxHighlighterConfig.boldOrItalicColor || color, defaultBreakerRegex, true, false);
                 }
               }
             }
             else
             {
               if (assumedItalic)
               {
                 if (assumedBold)
                 {
                   assumedItalic = false;
                 }
                 else
                 {
                   return;
                 }
               }
               else
               {
                 if (assumedBold)
                 {
                   assumedItalic = true;
                 }
                 else
                 {
                   highlightBlock(syntaxHighlighterConfig.boldOrItalicColor || color, defaultBreakerRegex, false, true);
                 }
               }
             }
             break;
           case "&":
             writeText(match[0], syntaxHighlighterConfig.entityColor || color);
             break;
           case "~":
             writeText(match[0], syntaxHighlighterConfig.signatureColor || color);
             break;
           default:
             writeText(match[0], syntaxHighlighterConfig.externalLinkColor || color);
         }
       }
     }
 
     var startTime = Date.now();
     highlightBlock("", defaultBreakerRegex);
 
     if (i < text.length)
     {
       writeText(text.substring(i), "");
     }
 
     var endTime = Date.now();
 
     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 = {
       zh: "由于渲染耗时过长, Syntax highlighting 已在本页禁用 在设定中渲染时间被限制在$1毫秒以内,但这次我们耗去了$2毫秒。您可以尝试关闭一些标签页和程序,并点击“显示预览”或“显示更改”。如果这不起作用,请尝试更换一个不同的浏览器。如果这还不起作用,请尝试更换一个更快的电脑=w=。",
         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.",
       };
       var wgUserLanguage = mw.config.get("wgUserLanguage");
 
       errorMessage = errorMessage[wgUserLanguage] || errorMessage[wgUserLanguage.substring(0, wgUserLanguage.indexOf("-"))] || errorMessage.en;
 
       wpTextbox1.style.backgroundColor = "";
       wpTextbox1.style.marginTop = "0";
       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;
     }
 
     if (maxSpanNumber < spanNumber)
     {
       var fragment = document.createDocumentFragment();
       do
       {
         fragment.appendChild(document.createElement("span")).id = "s" + ++maxSpanNumber;
       }
       while (maxSpanNumber < spanNumber);
       wpTextbox0.appendChild(fragment);
     }
 
     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});
     }
   }
 
   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 || {};
 
     configureColor("backgroundColor", "#FFF", false);
     configureColor("foregroundColor", "#000", false);
     configureColor("boldOrItalicColor", "#EEE", true);
     configureColor("commentColor", "#EFE", true);
     configureColor("entityColor", "#DFD", true);
     configureColor("externalLinkColor", "#EFF", true);
     configureColor("headingColor", "#EEE", true);
     configureColor("hrColor", "#EEE", true);
     configureColor("listOrIndentColor", "#EFE", true);
     configureColor("parameterColor", "#FC6", true);
     configureColor("signatureColor", "#FC6", true);
     configureColor("tagColor", "#FEF", true);
     configureColor("tableColor", "#FFC", true);
     configureColor("templateColor", "#FFC", true);
     configureColor("wikilinkColor", "#EEF", true);
     syntaxHighlighterConfig.nowikiTags = syntaxHighlighterConfig.nowikiTags || syntaxHighlighterSiteConfig.nowikiTags || ["nowiki", "pre"];
     syntaxHighlighterConfig.sourceTags = syntaxHighlighterConfig.sourceTags || syntaxHighlighterSiteConfig.sourceTags || ["math", "syntaxhighlight", "source", "timeline", "hiero", "score"];
     syntaxHighlighterConfig.voidTags = syntaxHighlighterConfig.voidTags || syntaxHighlighterSiteConfig.voidTags || ["br", "hr"];
     syntaxHighlighterConfig.timeout = syntaxHighlighterConfig.timeout || syntaxHighlighterSiteConfig.timeout || 50;
 
     syntaxHighlighterConfig.nowikiTags.forEach(function(tagName) {
       nowikiTagBreakerRegexCache[tagName] = nowikiTagBreakerRegex(tagName);
     });
 
     wpTextbox0 = document.createElement("div");
     wpTextbox1 = document.getElementById("wpTextbox1");
 
     var syntaxStyleElement = document.createElement("style");
     syntaxStyleTextNode = syntaxStyleElement.appendChild(document.createTextNode(""));
 
     var wpTextbox1Style = window.getComputedStyle(wpTextbox1);
 
     var resize = (wpTextbox1Style.resize == "vertical" || wpTextbox1Style.resize == "both" ? "vertical" : "none");
 
     wpTextbox0.dir = wpTextbox1.dir;
     wpTextbox0.id = "wpTextbox0";
     wpTextbox0.lang = wpTextbox1.lang;
     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";
     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 = "0";
     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";
    
     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;
     wpTextbox1.style.lineHeight = "normal";
     wpTextbox1.style.marginBottom = wpTextbox1Style.marginBottom;
     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";
     wpTextbox1.style.height = wpTextbox0.style.height = wpTextbox1.offsetHeight + "px";
 
     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();
   }
 
   var wgAction = mw.config.get("wgAction");
   var layoutEngine = $.client.profile().layout;
   if ((wgAction == "edit" || wgAction == "submit") && mw.config.get("wgPageContentModel") == "wikitext" && layoutEngine != "trident" && layoutEngine != "edge")
   {
     if (document.readyState == "complete")
     {
       setup();
     }
     else
     {
       window.addEventListener("load", setup);
     }
   }
});

2020年3月14日 (六) 08:46的版本

/* Based on https://www.mediawiki.org/wiki/User:Remember_the_dot/Syntax_highlighter.js */
/* https://www.mediawiki.org/wiki/User:NicoV/Syntax_highlighter.js */
/* This file may be used under the terms of any of the following
   licenses, as well as any later version of the same licenses:

   GNU General Public License 2.0
   <https://www.gnu.org/licenses/old-licenses/gpl-2.0.html>

   Creative Commons Attribution-ShareAlike 3.0 Unported License
   <https://creativecommons.org/licenses/by-sa/3.0/>

   GNU Free Documentation License 1.2
   <https://www.gnu.org/licenses/old-licenses/fdl-1.2.html>
*/

	mw.loader.using("jquery.client", function() {
    "use strict";

    var wpTextbox0;
    var wpTextbox1;
    var syntaxStyleTextNode;
    var lastText;
    var maxSpanNumber = -1;
    var highlightSyntaxIfNeededIntervalID;
    var attributeObserver;
    var parentObserver;

    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)
    {
        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;
        var text = lastText.replace(/['\\]/g, "\\$&") + "\n";
        var i = 0;

        var css = "";
        var spanNumber = 0;
        var lastColor;
        var before = true;

        function writeText(text, color)
        {
            if (color != lastColor)
            {
                css += "'}#s" + spanNumber;
                if (before)
                {
                    css += ":before{";
                    before = false;
                }
                else
                {
                    css += ":after{";
                    before = true;
                    ++spanNumber;
                }
                if (color)
                {
                    css += "background-color:" + color + ";";
                }
                css += "content:'";
                lastColor = color;
            }
            css += text;
        }

        function highlightBlock(color, breakerRegex, assumedBold, assumedItalic)
        {
            var match;

            for (breakerRegex.lastIndex = i; match = breakerRegex.exec(text); breakerRegex.lastIndex = i)
            {
                if (match[1])
                {
                    writeText(text.substring(i, breakerRegex.lastIndex), color);
                    i = breakerRegex.lastIndex;
                    return;
                }

                var endIndexOfLastColor = breakerRegex.lastIndex - match[0].length;
                if (i < endIndexOfLastColor)
                {
                    writeText(text.substring(i, endIndexOfLastColor), color);
                }

                i = breakerRegex.lastIndex;

                switch (match[0].charAt(0))
                {
                    case "[":
                        if (match[0].charAt(1) == "[")
                        {
                            writeText("[[", syntaxHighlighterConfig.wikilinkColor || color);
                            highlightBlock(syntaxHighlighterConfig.wikilinkColor || color, wikilinkBreakerRegex);
                        }
                        else
                        {
                            writeText(match[0], syntaxHighlighterConfig.externalLinkColor || color);
                            highlightBlock(syntaxHighlighterConfig.externalLinkColor || color, namedExternalLinkBreakerRegex);
                        }
                        break;
                    case "{":
                        if (match[0].charAt(1) == "{")
                        {
                            if (match[0].length == 3)
                            {
                                writeText("{{{", syntaxHighlighterConfig.parameterColor || color);
                                highlightBlock(syntaxHighlighterConfig.parameterColor || color, parameterBreakerRegex);
                            }
                            else
                            {
                                writeText("{{", syntaxHighlighterConfig.templateColor || color);
                                highlightBlock(syntaxHighlighterConfig.templateColor || color, templateBreakerRegex);
                            }
                        }
                        else
                        {
                            writeText("{|", syntaxHighlighterConfig.tableColor || color);
                            highlightBlock(syntaxHighlighterConfig.tableColor || color, tableBreakerRegex);
                        }
                        break;
                    case "<":
                        if (match[0].charAt(1) == "!")
                        {
                            writeText(match[0], syntaxHighlighterConfig.commentColor || color);
                            break;
                        }
                        else
                        {
                            var tagEnd = text.indexOf(">", i) + 1;
                            if (tagEnd == 0)
                            {
                                writeText("<", color);
                                i = i - match[0].length + 1;
                                break;
                            }

                            if (text.charAt(tagEnd - 2) == "/" || syntaxHighlighterConfig.voidTags.indexOf(match[0].substring(1)) != -1)
                            {
                                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)
                                {
                                    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)
                                {
                                    writeText(text.substring(i - match[0].length, tagEnd), syntaxHighlighterConfig.tagColor || color);
                                    i = tagEnd;
                                    highlightBlock(syntaxHighlighterConfig.tagColor || color, nowikiTagBreakerRegexCache[tagName]);
                                }
                                else
                                {
                                    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))))
                        {
                            writeText("=", syntaxHighlighterConfig.headingColor || color);
                            highlightBlock(syntaxHighlighterConfig.headingColor || color, headingBreakerRegex);
                        }
                        else
                        {
                            writeText("=", color);
                        }
                        break;
                    case "*":
                    case "#":
                    case ":":
                        writeText(match[0], syntaxHighlighterConfig.listOrIndentColor || color);
                        break;
                    case ";":
                        writeText(";", syntaxHighlighterConfig.headingColor || color);
                        highlightBlock(syntaxHighlighterConfig.headingColor || color, headingBreakerRegex);
                        break;
                    case "-":
                        writeText(match[0], syntaxHighlighterConfig.hrColor || color);
                        break;
                    case "\\":
                        writeText(match[0], syntaxHighlighterConfig.boldOrItalicColor || color);
                        if (match[0].length == 6)
                        {
                            if (assumedBold)
                            {
                                if (assumedItalic)
                                {
                                    assumedBold = false;
                                }
                                else
                                {
                                    return;
                                }
                            }
                            else
                            {
                                if (assumedItalic)
                                {
                                    assumedBold = true;
                                }
                                else
                                {
                                    highlightBlock(syntaxHighlighterConfig.boldOrItalicColor || color, defaultBreakerRegex, true, false);
                                }
                            }
                        }
                        else
                        {
                            if (assumedItalic)
                            {
                                if (assumedBold)
                                {
                                    assumedItalic = false;
                                }
                                else
                                {
                                    return;
                                }
                            }
                            else
                            {
                                if (assumedBold)
                                {
                                    assumedItalic = true;
                                }
                                else
                                {
                                    highlightBlock(syntaxHighlighterConfig.boldOrItalicColor || color, defaultBreakerRegex, false, true);
                                }
                            }
                        }
                        break;
                    case "&":
                        writeText(match[0], syntaxHighlighterConfig.entityColor || color);
                        break;
                    case "~":
                        writeText(match[0], syntaxHighlighterConfig.signatureColor || color);
                        break;
                    default:
                        writeText(match[0], syntaxHighlighterConfig.externalLinkColor || color);
                }
            }
        }

        var startTime = Date.now();
        highlightBlock("", defaultBreakerRegex);

        if (i < text.length)
        {
            writeText(text.substring(i), "");
        }

        var endTime = Date.now();

        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 = {
            	zh: "由于渲染耗时过长, Syntax highlighting 已在本页禁用。在设定中渲染时间被限制在$1毫秒以内,但这次我们耗去了$2毫秒。您可以尝试关闭一些标签页和程序,并点击“显示预览”或“显示更改”。如果这不起作用,请尝试更换一个不同的浏览器。如果这还不起作用,请尝试更换一个更快的电脑=w=。",
                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.",
            };
            var wgUserLanguage = mw.config.get("wgUserLanguage");

            errorMessage = errorMessage[wgUserLanguage] || errorMessage[wgUserLanguage.substring(0, wgUserLanguage.indexOf("-"))] || errorMessage.en;

            wpTextbox1.style.backgroundColor = "";
            wpTextbox1.style.marginTop = "0";
            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;
        }

        if (maxSpanNumber < spanNumber)
        {
            var fragment = document.createDocumentFragment();
            do
            {
                fragment.appendChild(document.createElement("span")).id = "s" + ++maxSpanNumber;
            }
            while (maxSpanNumber < spanNumber);
            wpTextbox0.appendChild(fragment);
        }

        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});
        }
    }

    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 || {};

        configureColor("backgroundColor", "#FFF", false);
        configureColor("foregroundColor", "#000", false);
        configureColor("boldOrItalicColor", "#EEE", true);
        configureColor("commentColor", "#EFE", true);
        configureColor("entityColor", "#DFD", true);
        configureColor("externalLinkColor", "#EFF", true);
        configureColor("headingColor", "#EEE", true);
        configureColor("hrColor", "#EEE", true);
        configureColor("listOrIndentColor", "#EFE", true);
        configureColor("parameterColor", "#FC6", true);
        configureColor("signatureColor", "#FC6", true);
        configureColor("tagColor", "#FEF", true);
        configureColor("tableColor", "#FFC", true);
        configureColor("templateColor", "#FFC", true);
        configureColor("wikilinkColor", "#EEF", true);
        syntaxHighlighterConfig.nowikiTags = syntaxHighlighterConfig.nowikiTags || syntaxHighlighterSiteConfig.nowikiTags || ["nowiki", "pre"];
        syntaxHighlighterConfig.sourceTags = syntaxHighlighterConfig.sourceTags || syntaxHighlighterSiteConfig.sourceTags || ["math", "syntaxhighlight", "source", "timeline", "hiero", "score"];
        syntaxHighlighterConfig.voidTags = syntaxHighlighterConfig.voidTags || syntaxHighlighterSiteConfig.voidTags || ["br", "hr"];
        syntaxHighlighterConfig.timeout = syntaxHighlighterConfig.timeout || syntaxHighlighterSiteConfig.timeout || 50;

        syntaxHighlighterConfig.nowikiTags.forEach(function(tagName) {
            nowikiTagBreakerRegexCache[tagName] = nowikiTagBreakerRegex(tagName);
        });

        wpTextbox0 = document.createElement("div");
        wpTextbox1 = document.getElementById("wpTextbox1");

        var syntaxStyleElement = document.createElement("style");
        syntaxStyleTextNode = syntaxStyleElement.appendChild(document.createTextNode(""));

        var wpTextbox1Style = window.getComputedStyle(wpTextbox1);

        var resize = (wpTextbox1Style.resize == "vertical" || wpTextbox1Style.resize == "both" ? "vertical" : "none");

        wpTextbox0.dir = wpTextbox1.dir;
        wpTextbox0.id = "wpTextbox0";
        wpTextbox0.lang = wpTextbox1.lang;
        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";
        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 = "0";
        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";
        
        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;
        wpTextbox1.style.lineHeight = "normal";
        wpTextbox1.style.marginBottom = wpTextbox1Style.marginBottom;
        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";
        wpTextbox1.style.height = wpTextbox0.style.height = wpTextbox1.offsetHeight + "px";

        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();
    }

    var wgAction = mw.config.get("wgAction");
    var layoutEngine = $.client.profile().layout;
    if ((wgAction == "edit" || wgAction == "submit") && mw.config.get("wgPageContentModel") == "wikitext" && layoutEngine != "trident" && layoutEngine != "edge")
    {
        if (document.readyState == "complete")
        {
            setup();
        }
        else
        {
            window.addEventListener("load", setup);
        }
    }
});