Mercurial
comparison .cms/lib/codemirror/mode/tiki/tiki.js @ 0:78edf6b517a0 draft
24.10
author | Coffee CMS <info@coffee-cms.ru> |
---|---|
date | Fri, 11 Oct 2024 22:40:23 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:78edf6b517a0 |
---|---|
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others | |
2 // Distributed under an MIT license: https://codemirror.net/5/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 }); |