mirror of https://github.com/avecms/AVE.cms.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
173 lines
5.6 KiB
173 lines
5.6 KiB
/** |
|
* @file smartymixed.js |
|
* @brief Smarty Mixed Codemirror mode (Smarty + Mixed HTML) |
|
* @author Ruslan Osmanov <rrosmanov at gmail dot com> |
|
* @version 3.0 |
|
* @date 05.07.2013 |
|
*/ |
|
CodeMirror.defineMode("smartymixed", function(config) { |
|
var settings, regs, helpers, parsers, |
|
htmlMixedMode = CodeMirror.getMode(config, "htmlmixed"), |
|
smartyMode = CodeMirror.getMode(config, "smarty"), |
|
|
|
settings = { |
|
rightDelimiter: '}', |
|
leftDelimiter: '{' |
|
}; |
|
|
|
if (config.hasOwnProperty("leftDelimiter")) { |
|
settings.leftDelimiter = config.leftDelimiter; |
|
} |
|
if (config.hasOwnProperty("rightDelimiter")) { |
|
settings.rightDelimiter = config.rightDelimiter; |
|
} |
|
|
|
regs = { |
|
smartyComment: new RegExp("^" + settings.leftDelimiter + "\\*"), |
|
literalOpen: new RegExp(settings.leftDelimiter + "literal" + settings.rightDelimiter), |
|
literalClose: new RegExp(settings.leftDelimiter + "\/literal" + settings.rightDelimiter), |
|
hasLeftDelimeter: new RegExp(".*" + settings.leftDelimiter), |
|
htmlHasLeftDelimeter: new RegExp("[^<>]*" + settings.leftDelimiter) |
|
}; |
|
|
|
helpers = { |
|
chain: function(stream, state, parser) { |
|
state.tokenize = parser; |
|
return parser(stream, state); |
|
}, |
|
|
|
cleanChain: function(stream, state, parser) { |
|
state.tokenize = null; |
|
state.localState = null; |
|
state.localMode = null; |
|
return (typeof parser == "string") ? (parser ? parser : null) : parser(stream, state); |
|
}, |
|
|
|
maybeBackup: function(stream, pat, style) { |
|
var cur = stream.current(); |
|
var close = cur.search(pat), |
|
m; |
|
if (close > - 1) stream.backUp(cur.length - close); |
|
else if (m = cur.match(/<\/?$/)) { |
|
stream.backUp(cur.length); |
|
if (!stream.match(pat, false)) stream.match(cur[0]); |
|
} |
|
return style; |
|
} |
|
}; |
|
|
|
parsers = { |
|
html: function(stream, state) { |
|
if (!state.inLiteral && stream.match(regs.htmlHasLeftDelimeter, false) && state.htmlMixedState.htmlState.tagName === null) { |
|
state.tokenize = parsers.smarty; |
|
state.localMode = smartyMode; |
|
state.localState = smartyMode.startState(htmlMixedMode.indent(state.htmlMixedState, "")); |
|
return helpers.maybeBackup(stream, settings.leftDelimiter, smartyMode.token(stream, state.localState)); |
|
} else if (!state.inLiteral && stream.match(settings.leftDelimiter, false)) { |
|
state.tokenize = parsers.smarty; |
|
state.localMode = smartyMode; |
|
state.localState = smartyMode.startState(htmlMixedMode.indent(state.htmlMixedState, "")); |
|
return helpers.maybeBackup(stream, settings.leftDelimiter, smartyMode.token(stream, state.localState)); |
|
} |
|
return htmlMixedMode.token(stream, state.htmlMixedState); |
|
}, |
|
|
|
smarty: function(stream, state) { |
|
if (stream.match(settings.leftDelimiter, false)) { |
|
if (stream.match(regs.smartyComment, false)) { |
|
return helpers.chain(stream, state, parsers.inBlock("comment", "*" + settings.rightDelimiter)); |
|
} |
|
} else if (stream.match(settings.rightDelimiter, false)) { |
|
stream.eat(settings.rightDelimiter); |
|
state.tokenize = parsers.html; |
|
state.localMode = htmlMixedMode; |
|
state.localState = state.htmlMixedState; |
|
return "tag"; |
|
} |
|
|
|
return helpers.maybeBackup(stream, settings.rightDelimiter, smartyMode.token(stream, state.localState)); |
|
}, |
|
|
|
inBlock: function(style, terminator) { |
|
return function(stream, state) { |
|
while (!stream.eol()) { |
|
if (stream.match(terminator)) { |
|
helpers.cleanChain(stream, state, ""); |
|
break; |
|
} |
|
stream.next(); |
|
} |
|
return style; |
|
}; |
|
} |
|
}; |
|
|
|
return { |
|
startState: function() { |
|
var state = htmlMixedMode.startState(); |
|
return { |
|
token: parsers.html, |
|
localMode: null, |
|
localState: null, |
|
htmlMixedState: state, |
|
tokenize: null, |
|
inLiteral: false |
|
}; |
|
}, |
|
|
|
copyState: function(state) { |
|
var local = null, tok = (state.tokenize || state.token); |
|
if (state.localState) { |
|
local = CodeMirror.copyState((tok != parsers.html ? smartyMode : htmlMixedMode), state.localState); |
|
} |
|
return { |
|
token: state.token, |
|
tokenize: state.tokenize, |
|
localMode: state.localMode, |
|
localState: local, |
|
htmlMixedState: CodeMirror.copyState(htmlMixedMode, state.htmlMixedState), |
|
inLiteral: state.inLiteral |
|
}; |
|
}, |
|
|
|
token: function(stream, state) { |
|
if (stream.match(settings.leftDelimiter, false)) { |
|
if (!state.inLiteral && stream.match(regs.literalOpen, true)) { |
|
state.inLiteral = true; |
|
return "keyword"; |
|
} else if (state.inLiteral && stream.match(regs.literalClose, true)) { |
|
state.inLiteral = false; |
|
return "keyword"; |
|
} |
|
} |
|
if (state.inLiteral && state.localState != state.htmlMixedState) { |
|
state.tokenize = parsers.html; |
|
state.localMode = htmlMixedMode; |
|
state.localState = state.htmlMixedState; |
|
} |
|
|
|
var style = (state.tokenize || state.token)(stream, state); |
|
return style; |
|
}, |
|
|
|
indent: function(state, textAfter) { |
|
if (state.localMode == smartyMode |
|
|| (state.inLiteral && !state.localMode) |
|
|| regs.hasLeftDelimeter.test(textAfter)) { |
|
return CodeMirror.Pass; |
|
} |
|
return htmlMixedMode.indent(state.htmlMixedState, textAfter); |
|
}, |
|
|
|
innerMode: function(state) { |
|
return { |
|
state: state.localState || state.htmlMixedState, |
|
mode: state.localMode || htmlMixedMode |
|
}; |
|
} |
|
}; |
|
}, |
|
"htmlmixed"); |
|
|
|
CodeMirror.defineMIME("text/x-smarty", "smartymixed"); |
|
// vim: et ts=2 sts=2 sw=2
|