/* 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"); });