// 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) // Plain browser env else 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
at start of line case '#': //ordered list line item, or at start of line case '+': //ordered list line item, or 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') })