LaravelTest
356 строк · 11.5 Кб
1// CodeMirror, copyright (c) by Marijn Haverbeke and others
2// Distributed under an MIT license: https://codemirror.net/LICENSE
3
4(function(mod) {5if (typeof exports == "object" && typeof module == "object") // CommonJS6mod(require("../../lib/codemirror"), require("../htmlmixed/htmlmixed"),7require("../../addon/mode/overlay"));8else if (typeof define == "function" && define.amd) // AMD9define(["../../lib/codemirror", "../htmlmixed/htmlmixed",10"../../addon/mode/overlay"], mod);11else // Plain browser env12mod(CodeMirror);13})(function(CodeMirror) {14"use strict";15
16CodeMirror.defineMode("django:inner", function() {17var keywords = ["block", "endblock", "for", "endfor", "true", "false", "filter", "endfilter",18"loop", "none", "self", "super", "if", "elif", "endif", "as", "else", "import",19"with", "endwith", "without", "context", "ifequal", "endifequal", "ifnotequal",20"endifnotequal", "extends", "include", "load", "comment", "endcomment",21"empty", "url", "static", "trans", "blocktrans", "endblocktrans", "now",22"regroup", "lorem", "ifchanged", "endifchanged", "firstof", "debug", "cycle",23"csrf_token", "autoescape", "endautoescape", "spaceless", "endspaceless",24"ssi", "templatetag", "verbatim", "endverbatim", "widthratio"],25filters = ["add", "addslashes", "capfirst", "center", "cut", "date",26"default", "default_if_none", "dictsort",27"dictsortreversed", "divisibleby", "escape", "escapejs",28"filesizeformat", "first", "floatformat", "force_escape",29"get_digit", "iriencode", "join", "last", "length",30"length_is", "linebreaks", "linebreaksbr", "linenumbers",31"ljust", "lower", "make_list", "phone2numeric", "pluralize",32"pprint", "random", "removetags", "rjust", "safe",33"safeseq", "slice", "slugify", "stringformat", "striptags",34"time", "timesince", "timeuntil", "title", "truncatechars",35"truncatechars_html", "truncatewords", "truncatewords_html",36"unordered_list", "upper", "urlencode", "urlize",37"urlizetrunc", "wordcount", "wordwrap", "yesno"],38operators = ["==", "!=", "<", ">", "<=", ">="],39wordOperators = ["in", "not", "or", "and"];40
41keywords = new RegExp("^\\b(" + keywords.join("|") + ")\\b");42filters = new RegExp("^\\b(" + filters.join("|") + ")\\b");43operators = new RegExp("^\\b(" + operators.join("|") + ")\\b");44wordOperators = new RegExp("^\\b(" + wordOperators.join("|") + ")\\b");45
46// We have to return "null" instead of null, in order to avoid string47// styling as the default, when using Django templates inside HTML48// element attributes49function tokenBase (stream, state) {50// Attempt to identify a variable, template or comment tag respectively51if (stream.match("{{")) {52state.tokenize = inVariable;53return "tag";54} else if (stream.match("{%")) {55state.tokenize = inTag;56return "tag";57} else if (stream.match("{#")) {58state.tokenize = inComment;59return "comment";60}61
62// Ignore completely any stream series that do not match the63// Django template opening tags.64while (stream.next() != null && !stream.match(/\{[{%#]/, false)) {}65return null;66}67
68// A string can be included in either single or double quotes (this is69// the delimiter). Mark everything as a string until the start delimiter70// occurs again.71function inString (delimiter, previousTokenizer) {72return function (stream, state) {73if (!state.escapeNext && stream.eat(delimiter)) {74state.tokenize = previousTokenizer;75} else {76if (state.escapeNext) {77state.escapeNext = false;78}79
80var ch = stream.next();81
82// Take into account the backslash for escaping characters, such as83// the string delimiter.84if (ch == "\\") {85state.escapeNext = true;86}87}88
89return "string";90};91}92
93// Apply Django template variable syntax highlighting94function inVariable (stream, state) {95// Attempt to match a dot that precedes a property96if (state.waitDot) {97state.waitDot = false;98
99if (stream.peek() != ".") {100return "null";101}102
103// Dot followed by a non-word character should be considered an error.104if (stream.match(/\.\W+/)) {105return "error";106} else if (stream.eat(".")) {107state.waitProperty = true;108return "null";109} else {110throw Error ("Unexpected error while waiting for property.");111}112}113
114// Attempt to match a pipe that precedes a filter115if (state.waitPipe) {116state.waitPipe = false;117
118if (stream.peek() != "|") {119return "null";120}121
122// Pipe followed by a non-word character should be considered an error.123if (stream.match(/\.\W+/)) {124return "error";125} else if (stream.eat("|")) {126state.waitFilter = true;127return "null";128} else {129throw Error ("Unexpected error while waiting for filter.");130}131}132
133// Highlight properties134if (state.waitProperty) {135state.waitProperty = false;136if (stream.match(/\b(\w+)\b/)) {137state.waitDot = true; // A property can be followed by another property138state.waitPipe = true; // A property can be followed by a filter139return "property";140}141}142
143// Highlight filters144if (state.waitFilter) {145state.waitFilter = false;146if (stream.match(filters)) {147return "variable-2";148}149}150
151// Ignore all white spaces152if (stream.eatSpace()) {153state.waitProperty = false;154return "null";155}156
157// Identify numbers158if (stream.match(/\b\d+(\.\d+)?\b/)) {159return "number";160}161
162// Identify strings163if (stream.match("'")) {164state.tokenize = inString("'", state.tokenize);165return "string";166} else if (stream.match('"')) {167state.tokenize = inString('"', state.tokenize);168return "string";169}170
171// Attempt to find the variable172if (stream.match(/\b(\w+)\b/) && !state.foundVariable) {173state.waitDot = true;174state.waitPipe = true; // A property can be followed by a filter175return "variable";176}177
178// If found closing tag reset179if (stream.match("}}")) {180state.waitProperty = null;181state.waitFilter = null;182state.waitDot = null;183state.waitPipe = null;184state.tokenize = tokenBase;185return "tag";186}187
188// If nothing was found, advance to the next character189stream.next();190return "null";191}192
193function inTag (stream, state) {194// Attempt to match a dot that precedes a property195if (state.waitDot) {196state.waitDot = false;197
198if (stream.peek() != ".") {199return "null";200}201
202// Dot followed by a non-word character should be considered an error.203if (stream.match(/\.\W+/)) {204return "error";205} else if (stream.eat(".")) {206state.waitProperty = true;207return "null";208} else {209throw Error ("Unexpected error while waiting for property.");210}211}212
213// Attempt to match a pipe that precedes a filter214if (state.waitPipe) {215state.waitPipe = false;216
217if (stream.peek() != "|") {218return "null";219}220
221// Pipe followed by a non-word character should be considered an error.222if (stream.match(/\.\W+/)) {223return "error";224} else if (stream.eat("|")) {225state.waitFilter = true;226return "null";227} else {228throw Error ("Unexpected error while waiting for filter.");229}230}231
232// Highlight properties233if (state.waitProperty) {234state.waitProperty = false;235if (stream.match(/\b(\w+)\b/)) {236state.waitDot = true; // A property can be followed by another property237state.waitPipe = true; // A property can be followed by a filter238return "property";239}240}241
242// Highlight filters243if (state.waitFilter) {244state.waitFilter = false;245if (stream.match(filters)) {246return "variable-2";247}248}249
250// Ignore all white spaces251if (stream.eatSpace()) {252state.waitProperty = false;253return "null";254}255
256// Identify numbers257if (stream.match(/\b\d+(\.\d+)?\b/)) {258return "number";259}260
261// Identify strings262if (stream.match("'")) {263state.tokenize = inString("'", state.tokenize);264return "string";265} else if (stream.match('"')) {266state.tokenize = inString('"', state.tokenize);267return "string";268}269
270// Attempt to match an operator271if (stream.match(operators)) {272return "operator";273}274
275// Attempt to match a word operator276if (stream.match(wordOperators)) {277return "keyword";278}279
280// Attempt to match a keyword281var keywordMatch = stream.match(keywords);282if (keywordMatch) {283if (keywordMatch[0] == "comment") {284state.blockCommentTag = true;285}286return "keyword";287}288
289// Attempt to match a variable290if (stream.match(/\b(\w+)\b/)) {291state.waitDot = true;292state.waitPipe = true; // A property can be followed by a filter293return "variable";294}295
296// If found closing tag reset297if (stream.match("%}")) {298state.waitProperty = null;299state.waitFilter = null;300state.waitDot = null;301state.waitPipe = null;302// If the tag that closes is a block comment tag, we want to mark the303// following code as comment, until the tag closes.304if (state.blockCommentTag) {305state.blockCommentTag = false; // Release the "lock"306state.tokenize = inBlockComment;307} else {308state.tokenize = tokenBase;309}310return "tag";311}312
313// If nothing was found, advance to the next character314stream.next();315return "null";316}317
318// Mark everything as comment inside the tag and the tag itself.319function inComment (stream, state) {320if (stream.match(/^.*?#\}/)) state.tokenize = tokenBase321else stream.skipToEnd()322return "comment";323}324
325// Mark everything as a comment until the `blockcomment` tag closes.326function inBlockComment (stream, state) {327if (stream.match(/\{%\s*endcomment\s*%\}/, false)) {328state.tokenize = inTag;329stream.match("{%");330return "tag";331} else {332stream.next();333return "comment";334}335}336
337return {338startState: function () {339return {tokenize: tokenBase};340},341token: function (stream, state) {342return state.tokenize(stream, state);343},344blockCommentStart: "{% comment %}",345blockCommentEnd: "{% endcomment %}"346};347});348
349CodeMirror.defineMode("django", function(config) {350var htmlBase = CodeMirror.getMode(config, "text/html");351var djangoInner = CodeMirror.getMode(config, "django:inner");352return CodeMirror.overlayMode(htmlBase, djangoInner);353});354
355CodeMirror.defineMIME("text/x-django", "django");356});357