180 lines
5.5 KiB
JavaScript
180 lines
5.5 KiB
JavaScript
/* HTMLMode */
|
|
|
|
// 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"), require("../../addon/mode/overlay"));
|
|
// else if (typeof define == "function" && define.amd) // AMD
|
|
// define(["../../lib/codemirror", "../../addon/mode/overlay"], mod);
|
|
// else // Plain browser env
|
|
mod(CodeMirror);
|
|
})(function(CodeMirror) {
|
|
"use strict";
|
|
|
|
//jsStartState.localVars && globalVars
|
|
|
|
CodeMirror.defineMode("htmlmode", function(config, parserConfig) {
|
|
// var htmlmode = CodeMirror.getMode(config, {
|
|
// name: "htmlmode-tags",
|
|
// helperType: 'htmlmode'
|
|
// });
|
|
var htmlmode = CodeMirror.getMode(config, {});
|
|
const jsmode = CodeMirror.getMode({}, "javascript");
|
|
const jsStartState = jsmode.startState();
|
|
const operator_regex = /#(if|else|endif|each|endeach|reactive|endreactive|variant|endvariant|translate|browser|endbrowser)|idPortlet/;
|
|
if (!parserConfig || !parserConfig.base) return htmlmode;
|
|
/**
|
|
* End current expression from stream.pos to "}}".
|
|
* Used for comment and ctrl expression
|
|
* @param {*} stream
|
|
*/
|
|
var endExpression = function(stream) {
|
|
let ch;
|
|
let end = false;
|
|
while ((ch = stream.next()) != null && !end){
|
|
if (ch == "}" && stream.next() == "}") {
|
|
stream.eat("}");
|
|
end = true;
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* Match expression close and inner JS syntax
|
|
* @param {Object} stream
|
|
* @param {Object} stack
|
|
* @returns {Object}
|
|
*/
|
|
var expression = function (stream, stack) {
|
|
let ch;
|
|
let end = false;
|
|
let start = stream.start;
|
|
while ((ch = stream.peek()) != null && !end ){
|
|
/**
|
|
* Caso di errore con una {{ all'interno di un espressione
|
|
*/
|
|
if( ch == '{' && stream.match(/{{/) ) {
|
|
let before = stream.pos;
|
|
stream.eatWhile(/}}/);
|
|
stack.push({
|
|
token: "undefined",
|
|
pos: stream.pos,
|
|
string: stream.string.substring(before, stream.pos)
|
|
})
|
|
}
|
|
else if (ch == "}" && stream.match(/}}/)) {
|
|
stream.eat("}}");
|
|
end = true;
|
|
let before = stream.pos;
|
|
stack.push({
|
|
token: "close-bracket",
|
|
pos: stream.pos,
|
|
string: stream.string.substring(before, stream.pos)
|
|
})
|
|
// riposiziono lo start
|
|
stream.start = start;
|
|
} else if ( stream.match(operator_regex, false) ) {
|
|
let before = stream.pos;
|
|
// posiziono lo start per il parser JS
|
|
stream.start = before;
|
|
stream.match(operator_regex);
|
|
stack.push({
|
|
token: "macro",
|
|
pos: stream.pos,
|
|
string: stream.string.substring(before, stream.pos)
|
|
})
|
|
} else {
|
|
let before = stream.pos;
|
|
// posiziono lo start per il parser JS
|
|
stream.start = before;
|
|
stack.push({
|
|
token: jsmode.token(stream, jsStartState),
|
|
pos: stream.pos,
|
|
string: stream.string.substring(before, stream.pos)
|
|
})
|
|
}
|
|
}
|
|
return stack;
|
|
}
|
|
|
|
function getTokens() {
|
|
let stack = [];
|
|
return {
|
|
name: "htmlmode-tags",
|
|
helperType: 'htmlmode',
|
|
token: function(stream,state) {
|
|
// aggiorno lo stack in caso di richiesta di token parziale con la tokenAt
|
|
if( stream.pos == 0 ) {
|
|
stack = [];
|
|
}
|
|
let ch;
|
|
/**
|
|
* start expresison
|
|
* - {{
|
|
* - {{!
|
|
* - {{!--
|
|
*/
|
|
if ( !stack.length && stream.match( /{{/ )) {
|
|
stream.eatSpace();
|
|
ch = stream.peek();
|
|
/**
|
|
* Comment
|
|
*/
|
|
if( ch == "!" ) {
|
|
endExpression(stream);
|
|
return "comment";
|
|
} else {
|
|
/** Expresison or @ctrl
|
|
* {{ exp
|
|
* {{ @ctrl
|
|
*/
|
|
if( ch == "@" && stream.match( /@[A-Za-z_]\w*/ ) ) {
|
|
/**
|
|
* Identify {{ @ctrl_name }}
|
|
*/
|
|
endExpression(stream);
|
|
return "ctrl"
|
|
} else {
|
|
let tempPos = stack.length ? stack[stack.length - 1].pos : stream.pos;
|
|
/**
|
|
* Evaluate all expression and make stack of token
|
|
*/
|
|
stack = expression(stream, stack);
|
|
/**
|
|
* Return to first token, the other are in stack and where
|
|
* used in next loop
|
|
*/
|
|
stream.pos = tempPos;
|
|
stream.start = 0;
|
|
return "open-bracket";
|
|
}
|
|
|
|
}
|
|
}
|
|
if( stack.length ){
|
|
let state = stack.shift();
|
|
stream.pos = state.pos;
|
|
return state.token;
|
|
}
|
|
while (stream.next() != null && !stream.match(/{{/, false)) {}
|
|
return null;
|
|
},
|
|
blockCommentStart: "{{!--",
|
|
blockCommentEnd: "--}}"
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Overload htmlmixed with htmlmode syntax. Read from {{ to }}.
|
|
* Use stack to store token
|
|
*/
|
|
htmlmode = CodeMirror.overlayMode( CodeMirror.getMode(config, parserConfig.base), getTokens());
|
|
return htmlmode;
|
|
});
|
|
|
|
CodeMirror.defineMIME("text/x-htmlmode-template", "htmlmode");
|
|
});
|