313 lines
		
	
	
		
			8.3 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			313 lines
		
	
	
		
			8.3 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| // CodeMirror, copyright (c) by Marijn Haverbeke and others
 | |
| // Distributed under an MIT license: https://codemirror.net/LICENSE
 | |
| 
 | |
| (function(mod) {
 | |
|   if (typeof exports == "object" && typeof module == "object") // CommonJS
 | |
|     mod(require("../../lib/codemirror"));
 | |
|   else if (typeof define == "function" && define.amd) // AMD
 | |
|     define(["../../lib/codemirror"], mod);
 | |
|   else // Plain browser env
 | |
|     mod(CodeMirror);
 | |
| })(function(CodeMirror) {
 | |
| "use strict";
 | |
| 
 | |
| CodeMirror.defineMode('tiki', function(config) {
 | |
|   function inBlock(style, terminator, returnTokenizer) {
 | |
|     return function(stream, state) {
 | |
|       while (!stream.eol()) {
 | |
|         if (stream.match(terminator)) {
 | |
|           state.tokenize = inText;
 | |
|           break;
 | |
|         }
 | |
|         stream.next();
 | |
|       }
 | |
| 
 | |
|       if (returnTokenizer) state.tokenize = returnTokenizer;
 | |
| 
 | |
|       return style;
 | |
|     };
 | |
|   }
 | |
| 
 | |
|   function inLine(style) {
 | |
|     return function(stream, state) {
 | |
|       while(!stream.eol()) {
 | |
|         stream.next();
 | |
|       }
 | |
|       state.tokenize = inText;
 | |
|       return style;
 | |
|     };
 | |
|   }
 | |
| 
 | |
|   function inText(stream, state) {
 | |
|     function chain(parser) {
 | |
|       state.tokenize = parser;
 | |
|       return parser(stream, state);
 | |
|     }
 | |
| 
 | |
|     var sol = stream.sol();
 | |
|     var ch = stream.next();
 | |
| 
 | |
|     //non start of line
 | |
|     switch (ch) { //switch is generally much faster than if, so it is used here
 | |
|     case "{": //plugin
 | |
|       stream.eat("/");
 | |
|       stream.eatSpace();
 | |
|       stream.eatWhile(/[^\s\u00a0=\"\'\/?(}]/);
 | |
|       state.tokenize = inPlugin;
 | |
|       return "tag";
 | |
|     case "_": //bold
 | |
|       if (stream.eat("_"))
 | |
|         return chain(inBlock("strong", "__", inText));
 | |
|       break;
 | |
|     case "'": //italics
 | |
|       if (stream.eat("'"))
 | |
|         return chain(inBlock("em", "''", inText));
 | |
|       break;
 | |
|     case "(":// Wiki Link
 | |
|       if (stream.eat("("))
 | |
|         return chain(inBlock("variable-2", "))", inText));
 | |
|       break;
 | |
|     case "[":// Weblink
 | |
|       return chain(inBlock("variable-3", "]", inText));
 | |
|       break;
 | |
|     case "|": //table
 | |
|       if (stream.eat("|"))
 | |
|         return chain(inBlock("comment", "||"));
 | |
|       break;
 | |
|     case "-":
 | |
|       if (stream.eat("=")) {//titleBar
 | |
|         return chain(inBlock("header string", "=-", inText));
 | |
|       } else if (stream.eat("-")) {//deleted
 | |
|         return chain(inBlock("error tw-deleted", "--", inText));
 | |
|       }
 | |
|       break;
 | |
|     case "=": //underline
 | |
|       if (stream.match("=="))
 | |
|         return chain(inBlock("tw-underline", "===", inText));
 | |
|       break;
 | |
|     case ":":
 | |
|       if (stream.eat(":"))
 | |
|         return chain(inBlock("comment", "::"));
 | |
|       break;
 | |
|     case "^": //box
 | |
|       return chain(inBlock("tw-box", "^"));
 | |
|       break;
 | |
|     case "~": //np
 | |
|       if (stream.match("np~"))
 | |
|         return chain(inBlock("meta", "~/np~"));
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|     //start of line types
 | |
|     if (sol) {
 | |
|       switch (ch) {
 | |
|       case "!": //header at start of line
 | |
|         if (stream.match('!!!!!')) {
 | |
|           return chain(inLine("header string"));
 | |
|         } else if (stream.match('!!!!')) {
 | |
|           return chain(inLine("header string"));
 | |
|         } else if (stream.match('!!!')) {
 | |
|           return chain(inLine("header string"));
 | |
|         } else if (stream.match('!!')) {
 | |
|           return chain(inLine("header string"));
 | |
|         } else {
 | |
|           return chain(inLine("header string"));
 | |
|         }
 | |
|         break;
 | |
|       case "*": //unordered list line item, or <li /> at start of line
 | |
|       case "#": //ordered list line item, or <li /> at start of line
 | |
|       case "+": //ordered list line item, or <li /> at start of line
 | |
|         return chain(inLine("tw-listitem bracket"));
 | |
|         break;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     //stream.eatWhile(/[&{]/); was eating up plugins, turned off to act less like html and more like tiki
 | |
|     return null;
 | |
|   }
 | |
| 
 | |
|   var indentUnit = config.indentUnit;
 | |
| 
 | |
|   // Return variables for tokenizers
 | |
|   var pluginName, type;
 | |
|   function inPlugin(stream, state) {
 | |
|     var ch = stream.next();
 | |
|     var peek = stream.peek();
 | |
| 
 | |
|     if (ch == "}") {
 | |
|       state.tokenize = inText;
 | |
|       //type = ch == ")" ? "endPlugin" : "selfclosePlugin"; inPlugin
 | |
|       return "tag";
 | |
|     } else if (ch == "(" || ch == ")") {
 | |
|       return "bracket";
 | |
|     } else if (ch == "=") {
 | |
|       type = "equals";
 | |
| 
 | |
|       if (peek == ">") {
 | |
|         stream.next();
 | |
|         peek = stream.peek();
 | |
|       }
 | |
| 
 | |
|       //here we detect values directly after equal character with no quotes
 | |
|       if (!/[\'\"]/.test(peek)) {
 | |
|         state.tokenize = inAttributeNoQuote();
 | |
|       }
 | |
|       //end detect values
 | |
| 
 | |
|       return "operator";
 | |
|     } else if (/[\'\"]/.test(ch)) {
 | |
|       state.tokenize = inAttribute(ch);
 | |
|       return state.tokenize(stream, state);
 | |
|     } else {
 | |
|       stream.eatWhile(/[^\s\u00a0=\"\'\/?]/);
 | |
|       return "keyword";
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   function inAttribute(quote) {
 | |
|     return function(stream, state) {
 | |
|       while (!stream.eol()) {
 | |
|         if (stream.next() == quote) {
 | |
|           state.tokenize = inPlugin;
 | |
|           break;
 | |
|         }
 | |
|       }
 | |
|       return "string";
 | |
|     };
 | |
|   }
 | |
| 
 | |
|   function inAttributeNoQuote() {
 | |
|     return function(stream, state) {
 | |
|       while (!stream.eol()) {
 | |
|         var ch = stream.next();
 | |
|         var peek = stream.peek();
 | |
|         if (ch == " " || ch == "," || /[ )}]/.test(peek)) {
 | |
|       state.tokenize = inPlugin;
 | |
|       break;
 | |
|     }
 | |
|   }
 | |
|   return "string";
 | |
| };
 | |
|                      }
 | |
| 
 | |
| var curState, setStyle;
 | |
| function pass() {
 | |
|   for (var i = arguments.length - 1; i >= 0; i--) curState.cc.push(arguments[i]);
 | |
| }
 | |
| 
 | |
| function cont() {
 | |
|   pass.apply(null, arguments);
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| function pushContext(pluginName, startOfLine) {
 | |
|   var noIndent = curState.context && curState.context.noIndent;
 | |
|   curState.context = {
 | |
|     prev: curState.context,
 | |
|     pluginName: pluginName,
 | |
|     indent: curState.indented,
 | |
|     startOfLine: startOfLine,
 | |
|     noIndent: noIndent
 | |
|   };
 | |
| }
 | |
| 
 | |
| function popContext() {
 | |
|   if (curState.context) curState.context = curState.context.prev;
 | |
| }
 | |
| 
 | |
| function element(type) {
 | |
|   if (type == "openPlugin") {curState.pluginName = pluginName; return cont(attributes, endplugin(curState.startOfLine));}
 | |
|   else if (type == "closePlugin") {
 | |
|     var err = false;
 | |
|     if (curState.context) {
 | |
|       err = curState.context.pluginName != pluginName;
 | |
|       popContext();
 | |
|     } else {
 | |
|       err = true;
 | |
|     }
 | |
|     if (err) setStyle = "error";
 | |
|     return cont(endcloseplugin(err));
 | |
|   }
 | |
|   else if (type == "string") {
 | |
|     if (!curState.context || curState.context.name != "!cdata") pushContext("!cdata");
 | |
|     if (curState.tokenize == inText) popContext();
 | |
|     return cont();
 | |
|   }
 | |
|   else return cont();
 | |
| }
 | |
| 
 | |
| function endplugin(startOfLine) {
 | |
|   return function(type) {
 | |
|     if (
 | |
|       type == "selfclosePlugin" ||
 | |
|         type == "endPlugin"
 | |
|     )
 | |
|       return cont();
 | |
|     if (type == "endPlugin") {pushContext(curState.pluginName, startOfLine); return cont();}
 | |
|     return cont();
 | |
|   };
 | |
| }
 | |
| 
 | |
| function endcloseplugin(err) {
 | |
|   return function(type) {
 | |
|     if (err) setStyle = "error";
 | |
|     if (type == "endPlugin") return cont();
 | |
|     return pass();
 | |
|   };
 | |
| }
 | |
| 
 | |
| function attributes(type) {
 | |
|   if (type == "keyword") {setStyle = "attribute"; return cont(attributes);}
 | |
|   if (type == "equals") return cont(attvalue, attributes);
 | |
|   return pass();
 | |
| }
 | |
| function attvalue(type) {
 | |
|   if (type == "keyword") {setStyle = "string"; return cont();}
 | |
|   if (type == "string") return cont(attvaluemaybe);
 | |
|   return pass();
 | |
| }
 | |
| function attvaluemaybe(type) {
 | |
|   if (type == "string") return cont(attvaluemaybe);
 | |
|   else return pass();
 | |
| }
 | |
| return {
 | |
|   startState: function() {
 | |
|     return {tokenize: inText, cc: [], indented: 0, startOfLine: true, pluginName: null, context: null};
 | |
|   },
 | |
|   token: function(stream, state) {
 | |
|     if (stream.sol()) {
 | |
|       state.startOfLine = true;
 | |
|       state.indented = stream.indentation();
 | |
|     }
 | |
|     if (stream.eatSpace()) return null;
 | |
| 
 | |
|     setStyle = type = pluginName = null;
 | |
|     var style = state.tokenize(stream, state);
 | |
|     if ((style || type) && style != "comment") {
 | |
|       curState = state;
 | |
|       while (true) {
 | |
|         var comb = state.cc.pop() || element;
 | |
|         if (comb(type || style)) break;
 | |
|       }
 | |
|     }
 | |
|     state.startOfLine = false;
 | |
|     return setStyle || style;
 | |
|   },
 | |
|   indent: function(state, textAfter) {
 | |
|     var context = state.context;
 | |
|     if (context && context.noIndent) return 0;
 | |
|     if (context && /^{\//.test(textAfter))
 | |
|         context = context.prev;
 | |
|     while (context && !context.startOfLine)
 | |
|         context = context.prev;
 | |
|     if (context) return context.indent + indentUnit;
 | |
|     else return 0;
 | |
|   },
 | |
|   electricChars: "/"
 | |
| };
 | |
| });
 | |
| 
 | |
| CodeMirror.defineMIME("text/tiki", "tiki");
 | |
| 
 | |
| });
 | 
