File modules/editor/codemirror/mode/tiki/tiki.js

Last commit: Sun Dec 17 01:14:09 2017 +0100	Jan Dankert	Integration eines weiteren Code-Editors: Codemirror. Demnächst müssen wir hier mal aufräumen und andere Editoren rauswerfen.
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others 2 // Distributed under an MIT license: http://codemirror.net/LICENSE 3 4 (function(mod) { 5 if (typeof exports == "object" && typeof module == "object") // CommonJS 6 mod(require("../../lib/codemirror")); 7 else if (typeof define == "function" && define.amd) // AMD 8 define(["../../lib/codemirror"], mod); 9 else // Plain browser env 10 mod(CodeMirror); 11 })(function(CodeMirror) { 12 "use strict"; 13 14 CodeMirror.defineMode('tiki', function(config) { 15 function inBlock(style, terminator, returnTokenizer) { 16 return function(stream, state) { 17 while (!stream.eol()) { 18 if (stream.match(terminator)) { 19 state.tokenize = inText; 20 break; 21 } 22 stream.next(); 23 } 24 25 if (returnTokenizer) state.tokenize = returnTokenizer; 26 27 return style; 28 }; 29 } 30 31 function inLine(style) { 32 return function(stream, state) { 33 while(!stream.eol()) { 34 stream.next(); 35 } 36 state.tokenize = inText; 37 return style; 38 }; 39 } 40 41 function inText(stream, state) { 42 function chain(parser) { 43 state.tokenize = parser; 44 return parser(stream, state); 45 } 46 47 var sol = stream.sol(); 48 var ch = stream.next(); 49 50 //non start of line 51 switch (ch) { //switch is generally much faster than if, so it is used here 52 case "{": //plugin 53 stream.eat("/"); 54 stream.eatSpace(); 55 stream.eatWhile(/[^\s\u00a0=\"\'\/?(}]/); 56 state.tokenize = inPlugin; 57 return "tag"; 58 case "_": //bold 59 if (stream.eat("_")) 60 return chain(inBlock("strong", "__", inText)); 61 break; 62 case "'": //italics 63 if (stream.eat("'")) 64 return chain(inBlock("em", "''", inText)); 65 break; 66 case "(":// Wiki Link 67 if (stream.eat("(")) 68 return chain(inBlock("variable-2", "))", inText)); 69 break; 70 case "[":// Weblink 71 return chain(inBlock("variable-3", "]", inText)); 72 break; 73 case "|": //table 74 if (stream.eat("|")) 75 return chain(inBlock("comment", "||")); 76 break; 77 case "-": 78 if (stream.eat("=")) {//titleBar 79 return chain(inBlock("header string", "=-", inText)); 80 } else if (stream.eat("-")) {//deleted 81 return chain(inBlock("error tw-deleted", "--", inText)); 82 } 83 break; 84 case "=": //underline 85 if (stream.match("==")) 86 return chain(inBlock("tw-underline", "===", inText)); 87 break; 88 case ":": 89 if (stream.eat(":")) 90 return chain(inBlock("comment", "::")); 91 break; 92 case "^": //box 93 return chain(inBlock("tw-box", "^")); 94 break; 95 case "~": //np 96 if (stream.match("np~")) 97 return chain(inBlock("meta", "~/np~")); 98 break; 99 } 100 101 //start of line types 102 if (sol) { 103 switch (ch) { 104 case "!": //header at start of line 105 if (stream.match('!!!!!')) { 106 return chain(inLine("header string")); 107 } else if (stream.match('!!!!')) { 108 return chain(inLine("header string")); 109 } else if (stream.match('!!!')) { 110 return chain(inLine("header string")); 111 } else if (stream.match('!!')) { 112 return chain(inLine("header string")); 113 } else { 114 return chain(inLine("header string")); 115 } 116 break; 117 case "*": //unordered list line item, or <li /> at start of line 118 case "#": //ordered list line item, or <li /> at start of line 119 case "+": //ordered list line item, or <li /> at start of line 120 return chain(inLine("tw-listitem bracket")); 121 break; 122 } 123 } 124 125 //stream.eatWhile(/[&{]/); was eating up plugins, turned off to act less like html and more like tiki 126 return null; 127 } 128 129 var indentUnit = config.indentUnit; 130 131 // Return variables for tokenizers 132 var pluginName, type; 133 function inPlugin(stream, state) { 134 var ch = stream.next(); 135 var peek = stream.peek(); 136 137 if (ch == "}") { 138 state.tokenize = inText; 139 //type = ch == ")" ? "endPlugin" : "selfclosePlugin"; inPlugin 140 return "tag"; 141 } else if (ch == "(" || ch == ")") { 142 return "bracket"; 143 } else if (ch == "=") { 144 type = "equals"; 145 146 if (peek == ">") { 147 stream.next(); 148 peek = stream.peek(); 149 } 150 151 //here we detect values directly after equal character with no quotes 152 if (!/[\'\"]/.test(peek)) { 153 state.tokenize = inAttributeNoQuote(); 154 } 155 //end detect values 156 157 return "operator"; 158 } else if (/[\'\"]/.test(ch)) { 159 state.tokenize = inAttribute(ch); 160 return state.tokenize(stream, state); 161 } else { 162 stream.eatWhile(/[^\s\u00a0=\"\'\/?]/); 163 return "keyword"; 164 } 165 } 166 167 function inAttribute(quote) { 168 return function(stream, state) { 169 while (!stream.eol()) { 170 if (stream.next() == quote) { 171 state.tokenize = inPlugin; 172 break; 173 } 174 } 175 return "string"; 176 }; 177 } 178 179 function inAttributeNoQuote() { 180 return function(stream, state) { 181 while (!stream.eol()) { 182 var ch = stream.next(); 183 var peek = stream.peek(); 184 if (ch == " " || ch == "," || /[ )}]/.test(peek)) { 185 state.tokenize = inPlugin; 186 break; 187 } 188 } 189 return "string"; 190 }; 191 } 192 193 var curState, setStyle; 194 function pass() { 195 for (var i = arguments.length - 1; i >= 0; i--) curState.cc.push(arguments[i]); 196 } 197 198 function cont() { 199 pass.apply(null, arguments); 200 return true; 201 } 202 203 function pushContext(pluginName, startOfLine) { 204 var noIndent = curState.context && curState.context.noIndent; 205 curState.context = { 206 prev: curState.context, 207 pluginName: pluginName, 208 indent: curState.indented, 209 startOfLine: startOfLine, 210 noIndent: noIndent 211 }; 212 } 213 214 function popContext() { 215 if (curState.context) curState.context = curState.context.prev; 216 } 217 218 function element(type) { 219 if (type == "openPlugin") {curState.pluginName = pluginName; return cont(attributes, endplugin(curState.startOfLine));} 220 else if (type == "closePlugin") { 221 var err = false; 222 if (curState.context) { 223 err = curState.context.pluginName != pluginName; 224 popContext(); 225 } else { 226 err = true; 227 } 228 if (err) setStyle = "error"; 229 return cont(endcloseplugin(err)); 230 } 231 else if (type == "string") { 232 if (!curState.context || curState.context.name != "!cdata") pushContext("!cdata"); 233 if (curState.tokenize == inText) popContext(); 234 return cont(); 235 } 236 else return cont(); 237 } 238 239 function endplugin(startOfLine) { 240 return function(type) { 241 if ( 242 type == "selfclosePlugin" || 243 type == "endPlugin" 244 ) 245 return cont(); 246 if (type == "endPlugin") {pushContext(curState.pluginName, startOfLine); return cont();} 247 return cont(); 248 }; 249 } 250 251 function endcloseplugin(err) { 252 return function(type) { 253 if (err) setStyle = "error"; 254 if (type == "endPlugin") return cont(); 255 return pass(); 256 }; 257 } 258 259 function attributes(type) { 260 if (type == "keyword") {setStyle = "attribute"; return cont(attributes);} 261 if (type == "equals") return cont(attvalue, attributes); 262 return pass(); 263 } 264 function attvalue(type) { 265 if (type == "keyword") {setStyle = "string"; return cont();} 266 if (type == "string") return cont(attvaluemaybe); 267 return pass(); 268 } 269 function attvaluemaybe(type) { 270 if (type == "string") return cont(attvaluemaybe); 271 else return pass(); 272 } 273 return { 274 startState: function() { 275 return {tokenize: inText, cc: [], indented: 0, startOfLine: true, pluginName: null, context: null}; 276 }, 277 token: function(stream, state) { 278 if (stream.sol()) { 279 state.startOfLine = true; 280 state.indented = stream.indentation(); 281 } 282 if (stream.eatSpace()) return null; 283 284 setStyle = type = pluginName = null; 285 var style = state.tokenize(stream, state); 286 if ((style || type) && style != "comment") { 287 curState = state; 288 while (true) { 289 var comb = state.cc.pop() || element; 290 if (comb(type || style)) break; 291 } 292 } 293 state.startOfLine = false; 294 return setStyle || style; 295 }, 296 indent: function(state, textAfter) { 297 var context = state.context; 298 if (context && context.noIndent) return 0; 299 if (context && /^{\//.test(textAfter)) 300 context = context.prev; 301 while (context && !context.startOfLine) 302 context = context.prev; 303 if (context) return context.indent + indentUnit; 304 else return 0; 305 }, 306 electricChars: "/" 307 }; 308 }); 309 310 CodeMirror.defineMIME("text/tiki", "tiki"); 311 312 });
Download modules/editor/codemirror/mode/tiki/tiki.js
History Sun, 17 Dec 2017 01:14:09 +0100 Jan Dankert Integration eines weiteren Code-Editors: Codemirror. Demnächst müssen wir hier mal aufräumen und andere Editoren rauswerfen.