diff --git a/applications/admin/static/codemirror/addon/edit/closebrackets.js b/applications/admin/static/codemirror/addon/edit/closebrackets.js index f6b42f02..ff4bb3f7 100644 --- a/applications/admin/static/codemirror/addon/edit/closebrackets.js +++ b/applications/admin/static/codemirror/addon/edit/closebrackets.js @@ -10,6 +10,7 @@ mod(CodeMirror); })(function(CodeMirror) { var DEFAULT_BRACKETS = "()[]{}''\"\""; + var DEFAULT_TRIPLES = "'\""; var DEFAULT_EXPLODE_ON_ENTER = "[]{}"; var SPACE_CHAR_REGEX = /\s/; @@ -19,13 +20,14 @@ if (old != CodeMirror.Init && old) cm.removeKeyMap("autoCloseBrackets"); if (!val) return; - var pairs = DEFAULT_BRACKETS, explode = DEFAULT_EXPLODE_ON_ENTER; + var pairs = DEFAULT_BRACKETS, triples = DEFAULT_TRIPLES, explode = DEFAULT_EXPLODE_ON_ENTER; if (typeof val == "string") pairs = val; else if (typeof val == "object") { if (val.pairs != null) pairs = val.pairs; + if (val.triples != null) triples = val.triples; if (val.explode != null) explode = val.explode; } - var map = buildKeymap(pairs); + var map = buildKeymap(pairs, triples); if (explode) map.Enter = buildExplodeHandler(explode); cm.addKeyMap(map); }); @@ -52,7 +54,7 @@ } } - function buildKeymap(pairs) { + function buildKeymap(pairs, triples) { var map = { name : "autoCloseBrackets", Backspace: function(cm) { @@ -85,7 +87,7 @@ curType = "skipThree"; else curType = "skip"; - } else if (left == right && cur.ch > 1 && + } else if (left == right && cur.ch > 1 && triples.indexOf(left) >= 0 && cm.getRange(Pos(cur.line, cur.ch - 2), cur) == left + left && (cur.ch <= 2 || cm.getRange(Pos(cur.line, cur.ch - 3), Pos(cur.line, cur.ch - 2)) != left)) { curType = "addFour"; diff --git a/applications/admin/static/codemirror/addon/edit/closetag.js b/applications/admin/static/codemirror/addon/edit/closetag.js index 369bea30..e68d52d9 100644 --- a/applications/admin/static/codemirror/addon/edit/closetag.js +++ b/applications/admin/static/codemirror/addon/edit/closetag.js @@ -131,7 +131,7 @@ function autoCloseSlash(cm) { if (cm.getOption("disableInput")) return CodeMirror.Pass; - autoCloseCurrent(cm, true); + return autoCloseCurrent(cm, true); } CodeMirror.commands.closeTag = function(cm) { return autoCloseCurrent(cm); }; diff --git a/applications/admin/static/codemirror/addon/fold/foldgutter.js b/applications/admin/static/codemirror/addon/fold/foldgutter.js index 33594767..199120c7 100644 --- a/applications/admin/static/codemirror/addon/fold/foldgutter.js +++ b/applications/admin/static/codemirror/addon/fold/foldgutter.js @@ -94,20 +94,26 @@ } function onGutterClick(cm, line, gutter) { - var opts = cm.state.foldGutter.options; + var state = cm.state.foldGutter; + if (!state) return; + var opts = state.options; if (gutter != opts.gutter) return; cm.foldCode(Pos(line, 0), opts.rangeFinder); } function onChange(cm) { - var state = cm.state.foldGutter, opts = cm.state.foldGutter.options; + var state = cm.state.foldGutter; + if (!state) return; + var opts = state.options; state.from = state.to = 0; clearTimeout(state.changeUpdate); state.changeUpdate = setTimeout(function() { updateInViewport(cm); }, opts.foldOnChangeTimeSpan || 600); } function onViewportChange(cm) { - var state = cm.state.foldGutter, opts = cm.state.foldGutter.options; + var state = cm.state.foldGutter; + if (!state) return; + var opts = state.options; clearTimeout(state.changeUpdate); state.changeUpdate = setTimeout(function() { var vp = cm.getViewport(); @@ -129,7 +135,9 @@ } function onFold(cm, from) { - var state = cm.state.foldGutter, line = from.line; + var state = cm.state.foldGutter; + if (!state) return; + var line = from.line; if (line >= state.from && line < state.to) updateFoldInfo(cm, line, line + 1); } diff --git a/applications/admin/static/codemirror/addon/hint/show-hint.js b/applications/admin/static/codemirror/addon/hint/show-hint.js index fda5ffaa..f5446194 100644 --- a/applications/admin/static/codemirror/addon/hint/show-hint.js +++ b/applications/admin/static/codemirror/addon/hint/show-hint.js @@ -24,6 +24,18 @@ return cm.showHint(newOpts); }; + var asyncRunID = 0; + function retrieveHints(getter, cm, options, then) { + if (getter.async) { + var id = ++asyncRunID; + getter(cm, function(hints) { + if (asyncRunID == id) then(hints); + }, options); + } else { + then(getter(cm, options)); + } + } + CodeMirror.defineExtension("showHint", function(options) { // We want a single cursor position. if (this.listSelections().length > 1 || this.somethingSelected()) return; @@ -34,10 +46,7 @@ if (!getHints) return; CodeMirror.signal(this, "startCompletion", this); - if (getHints.async) - getHints(this, function(hints) { completion.showHints(hints); }, completion.options); - else - return completion.showHints(getHints(this, completion.options)); + return retrieveHints(getHints, this, completion.options, function(hints) { completion.showHints(hints); }); }); function Completion(cm, options) { @@ -102,11 +111,7 @@ function update() { if (finished) return; CodeMirror.signal(data, "update"); - var getHints = completion.options.hint; - if (getHints.async) - getHints(completion.cm, finishUpdate, completion.options); - else - finishUpdate(getHints(completion.cm, completion.options)); + retrieveHints(completion.options.hint, completion.cm, completion.options, finishUpdate); } function finishUpdate(data_) { data = data_; diff --git a/applications/admin/static/codemirror/addon/hint/sql-hint.js b/applications/admin/static/codemirror/addon/hint/sql-hint.js index 92c889e1..5b0cc769 100644 --- a/applications/admin/static/codemirror/addon/hint/sql-hint.js +++ b/applications/admin/static/codemirror/addon/hint/sql-hint.js @@ -26,9 +26,26 @@ return CodeMirror.resolveMode(mode).keywords; } + function getText(item) { + return typeof item == "string" ? item : item.text; + } + + function getItem(list, item) { + if (!list.slice) return list[item]; + for (var i = list.length - 1; i >= 0; i--) if (getText(list[i]) == item) + return list[i]; + } + + function shallowClone(object) { + var result = {}; + for (var key in object) if (object.hasOwnProperty(key)) + result[key] = object[key]; + return result; + } + function match(string, word) { var len = string.length; - var sub = word.substr(0, len); + var sub = getText(word).substr(0, len); return string.toUpperCase() === sub.toUpperCase(); } @@ -44,53 +61,81 @@ } } - function nameCompletion(cur, token, result, editor) { - var useBacktick = (token.string.charAt(0) == "`"); - var string = token.string.substr(1); - var prevToken = editor.getTokenAt(Pos(cur.line, token.start)); - if (token.string.charAt(0) == "." || prevToken.string == "."){ - //Suggest colunm names - if (prevToken.string == ".") { - var prevToken = editor.getTokenAt(Pos(cur.line, token.start - 1)); - } - var table = prevToken.string; - //Check if backtick is used in table name. If yes, use it for columns too. - var useBacktickTable = false; - if (table.match(/`/g)) { - useBacktickTable = true; - table = table.replace(/`/g, ""); - } - //Check if table is available. If not, find table by Alias - if (!tables.hasOwnProperty(table)) - table = findTableByAlias(table, editor); - var columns = tables[table]; - if (!columns) return; + function cleanName(name) { + // Get rid name from backticks(`) and preceding dot(.) + if (name.charAt(0) == ".") { + name = name.substr(1); + } + return name.replace(/`/g, ""); + } - if (useBacktick) { - addMatches(result, string, columns, function(w) {return "`" + w + "`";}); - } - else if(useBacktickTable) { - addMatches(result, string, columns, function(w) {return ".`" + w + "`";}); - } - else { - addMatches(result, string, columns, function(w) {return "." + w;}); + function insertBackticks(name) { + var nameParts = getText(name).split("."); + for (var i = 0; i < nameParts.length; i++) + nameParts[i] = "`" + nameParts[i] + "`"; + var escaped = nameParts.join("."); + if (typeof name == "string") return escaped; + name = shallowClone(name); + name.text = escaped; + return name; + } + + function nameCompletion(cur, token, result, editor) { + // Try to complete table, colunm names and return start position of completion + var useBacktick = false; + var nameParts = []; + var start = token.start; + var cont = true; + while (cont) { + cont = (token.string.charAt(0) == "."); + useBacktick = useBacktick || (token.string.charAt(0) == "`"); + + start = token.start; + nameParts.unshift(cleanName(token.string)); + + token = editor.getTokenAt(Pos(cur.line, token.start)); + if (token.string == ".") { + cont = true; + token = editor.getTokenAt(Pos(cur.line, token.start)); } } - else { - //Suggest table names or colums in defaultTable - while (token.start && string.charAt(0) == ".") { - token = editor.getTokenAt(Pos(cur.line, token.start - 1)); - string = token.string + string; - } - if (useBacktick) { - addMatches(result, string, tables, function(w) {return "`" + w + "`";}); - addMatches(result, string, defaultTable, function(w) {return "`" + w + "`";}); - } - else { - addMatches(result, string, tables, function(w) {return w;}); - addMatches(result, string, defaultTable, function(w) {return w;}); - } + + // Try to complete table names + var string = nameParts.join("."); + addMatches(result, string, tables, function(w) { + return useBacktick ? insertBackticks(w) : w; + }); + + // Try to complete columns from defaultTable + addMatches(result, string, defaultTable, function(w) { + return useBacktick ? insertBackticks(w) : w; + }); + + // Try to complete columns + string = nameParts.pop(); + var table = nameParts.join("."); + + // Check if table is available. If not, find table by Alias + if (!getItem(tables, table)) + table = findTableByAlias(table, editor); + + var columns = getItem(tables, table); + if (columns && Array.isArray(tables) && columns.columns) + columns = columns.columns; + + if (columns) { + addMatches(result, string, columns, function(w) { + if (typeof w == "string") { + w = table + "." + w; + } else { + w = shallowClone(w); + w.text = table + "." + w.text; + } + return useBacktick ? insertBackticks(w) : w; + }); } + + return start; } function eachWord(lineText, f) { @@ -150,12 +195,10 @@ var lineText = query[i]; eachWord(lineText, function(word) { var wordUpperCase = word.toUpperCase(); - if (wordUpperCase === aliasUpperCase && tables.hasOwnProperty(previousWord)) { - table = previousWord; - } - if (wordUpperCase !== CONS.ALIAS_KEYWORD) { + if (wordUpperCase === aliasUpperCase && getItem(tables, previousWord)) + table = previousWord; + if (wordUpperCase !== CONS.ALIAS_KEYWORD) previousWord = word; - } }); if (table) break; } @@ -165,7 +208,7 @@ CodeMirror.registerHelper("hint", "sql", function(editor, options) { tables = (options && options.tables) || {}; var defaultTableName = options && options.defaultTable; - defaultTable = (defaultTableName && tables[defaultTableName] || []); + defaultTable = (defaultTableName && getItem(tables, defaultTableName)) || []; keywords = keywords || getKeywords(editor); var cur = editor.getCursor(); @@ -185,7 +228,7 @@ search = ""; } if (search.charAt(0) == "." || search.charAt(0) == "`") { - nameCompletion(cur, token, result, editor); + start = nameCompletion(cur, token, result, editor); } else { addMatches(result, search, tables, function(w) {return w;}); addMatches(result, search, defaultTable, function(w) {return w;}); diff --git a/applications/admin/static/codemirror/addon/search/matchesonscrollbar.js b/applications/admin/static/codemirror/addon/search/matchesonscrollbar.js index 937d3f78..dbd67a4a 100644 --- a/applications/admin/static/codemirror/addon/search/matchesonscrollbar.js +++ b/applications/admin/static/codemirror/addon/search/matchesonscrollbar.js @@ -11,13 +11,18 @@ })(function(CodeMirror) { "use strict"; - CodeMirror.defineExtension("showMatchesOnScrollbar", function(query, caseFold, className) { - return new SearchAnnotation(this, query, caseFold, className); + CodeMirror.defineExtension("showMatchesOnScrollbar", function(query, caseFold, options) { + if (typeof options == "string") options = {className: options}; + if (!options) options = {}; + return new SearchAnnotation(this, query, caseFold, options); }); - function SearchAnnotation(cm, query, caseFold, className) { + function SearchAnnotation(cm, query, caseFold, options) { this.cm = cm; - this.annotation = cm.annotateScrollbar(className || "CodeMirror-search-match"); + var annotateOptions = {listenForChanges: false}; + for (var prop in options) annotateOptions[prop] = options[prop]; + if (!annotateOptions.className) annotateOptions.className = "CodeMirror-search-match"; + this.annotation = cm.annotateScrollbar(annotateOptions); this.query = query; this.caseFold = caseFold; this.gap = {from: cm.firstLine(), to: cm.lastLine() + 1}; diff --git a/applications/admin/static/codemirror/addon/selection/selection-pointer.js b/applications/admin/static/codemirror/addon/selection/selection-pointer.js index 8cc0fc68..ef5e404a 100644 --- a/applications/admin/static/codemirror/addon/selection/selection-pointer.js +++ b/applications/admin/static/codemirror/addon/selection/selection-pointer.js @@ -16,6 +16,7 @@ if (data) { CodeMirror.off(cm.getWrapperElement(), "mousemove", data.mousemove); CodeMirror.off(cm.getWrapperElement(), "mouseout", data.mouseout); + CodeMirror.off(window, "scroll", data.windowScroll); cm.off("cursorActivity", reset); cm.off("scroll", reset); cm.state.selectionPointer = null; @@ -26,12 +27,14 @@ value: typeof val == "string" ? val : "default", mousemove: function(event) { mousemove(cm, event); }, mouseout: function(event) { mouseout(cm, event); }, + windowScroll: function() { reset(cm); }, rects: null, mouseX: null, mouseY: null, willUpdate: false }; CodeMirror.on(cm.getWrapperElement(), "mousemove", data.mousemove); CodeMirror.on(cm.getWrapperElement(), "mouseout", data.mouseout); + CodeMirror.on(window, "scroll", data.windowScroll); cm.on("cursorActivity", reset); cm.on("scroll", reset); } diff --git a/applications/admin/static/codemirror/keymap/vim.js b/applications/admin/static/codemirror/keymap/vim.js index 88a404a2..682eb7a8 100644 --- a/applications/admin/static/codemirror/keymap/vim.js +++ b/applications/admin/static/codemirror/keymap/vim.js @@ -776,7 +776,16 @@ }, handleEx: function(cm, input) { exCommandDispatcher.processCommand(cm, input); - } + }, + + defineMotion: defineMotion, + defineAction: defineAction, + defineOperator: defineOperator, + mapCommand: mapCommand, + _mapCommand: _mapCommand, + + exitVisualMode: exitVisualMode, + exitInsertMode: exitInsertMode }; // Represents the current input state. @@ -1449,7 +1458,7 @@ var operatorMoveTo = operators[operator]( cm, operatorArgs, cmSel.ranges, oldAnchor, newHead); if (vim.visualMode) { - exitVisualMode(cm); + exitVisualMode(cm, operatorMoveTo != null); } if (operatorMoveTo) { cm.setCursor(operatorMoveTo); @@ -1817,6 +1826,10 @@ } }; + function defineMotion(name, fn) { + motions[name] = fn; + } + function fillArray(val, times) { var arr = []; for (var i = 0; i < times; i++) { @@ -1899,7 +1912,7 @@ vimGlobalState.registerController.pushText( args.registerName, 'delete', text, args.linewise, vim.visualBlock); - return finalHead; + return clipCursorToContent(cm, finalHead); }, indent: function(cm, args, ranges) { var vim = cm.state.vim; @@ -1967,6 +1980,10 @@ } }; + function defineOperator(name, fn) { + operators[name] = fn; + } + var actions = { jumpListWalk: function(cm, actionArgs, vim) { if (vim.visualMode) { @@ -2183,6 +2200,11 @@ if (vim.visualMode) { curStart = cm.getCursor('anchor'); curEnd = cm.getCursor('head'); + if (cursorIsBefore(curEnd, curStart)) { + var tmp = curEnd; + curEnd = curStart; + curStart = tmp; + } curEnd.ch = lineLength(cm, curEnd.line) - 1; } else { // Repeat is the number of lines to join. Minimum 2 lines. @@ -2201,10 +2223,10 @@ cm.replaceRange(text, curStart, tmp); } var curFinalPos = Pos(curStart.line, finalCh); - cm.setCursor(curFinalPos); if (vim.visualMode) { - exitVisualMode(cm); + exitVisualMode(cm, false); } + cm.setCursor(curFinalPos); }, newLineAndEnterInsertMode: function(cm, actionArgs, vim) { vim.insertMode = true; @@ -2367,7 +2389,7 @@ } } if (vim.visualMode) { - exitVisualMode(cm); + exitVisualMode(cm, false); } cm.setCursor(curPosFinal); }, @@ -2425,7 +2447,7 @@ curStart = cursorIsBefore(selections[0].anchor, selections[0].head) ? selections[0].anchor : selections[0].head; cm.setCursor(curStart); - exitVisualMode(cm); + exitVisualMode(cm, false); } else { cm.setCursor(offsetCursor(curEnd, 0, -1)); } @@ -2473,6 +2495,10 @@ exitInsertMode: exitInsertMode }; + function defineAction(name, fn) { + actions[name] = fn; + } + /* * Below are miscellaneous utility functions used by vim.js */ @@ -4627,6 +4653,19 @@ } } + function _mapCommand(command) { + defaultKeymap.push(command); + } + + function mapCommand(keys, type, name, args, extra) { + var command = {keys: keys, type: type}; + command[type] = name; + command[type + "Args"] = args; + for (var key in extra) + command[key] = extra[key]; + _mapCommand(command); + } + // The timeout in milliseconds for the two-character ESC keymap should be // adjusted according to your typing speed to prevent false positives. defineOption('insertModeEscKeysTimeout', 200, 'number'); diff --git a/applications/admin/static/codemirror/lib/codemirror.js b/applications/admin/static/codemirror/lib/codemirror.js index 03a34dbb..0e3d0192 100644 --- a/applications/admin/static/codemirror/lib/codemirror.js +++ b/applications/admin/static/codemirror/lib/codemirror.js @@ -110,6 +110,7 @@ for (var opt in optionHandlers) if (optionHandlers.hasOwnProperty(opt)) optionHandlers[opt](this, options[opt], Init); maybeUpdateLineNumberWidth(this); + if (options.finishInit) options.finishInit(this); for (var i = 0; i < initHooks.length; ++i) initHooks[i](this); endOperation(this); // Suppress optimizelegibility in Webkit, since it breaks text @@ -649,8 +650,18 @@ this.oldDisplayWidth = displayWidth(cm); this.force = force; this.dims = getDimensions(cm); + this.events = []; } + DisplayUpdate.prototype.signal = function(emitter, type) { + if (hasHandler(emitter, type)) + this.events.push(arguments); + }; + DisplayUpdate.prototype.finish = function() { + for (var i = 0; i < this.events.length; i++) + signal.apply(null, this.events[i]); + }; + function maybeClipScrollbars(cm) { var display = cm.display; if (!display.scrollbarsClipped && display.scroller.offsetWidth) { @@ -761,9 +772,9 @@ updateScrollbars(cm, barMeasure); } - signalLater(cm, "update", cm); + update.signal(cm, "update", cm); if (cm.display.viewFrom != cm.display.reportedViewFrom || cm.display.viewTo != cm.display.reportedViewTo) { - signalLater(cm, "viewportChange", cm, cm.display.viewFrom, cm.display.viewTo); + update.signal(cm, "viewportChange", cm, cm.display.viewFrom, cm.display.viewTo); cm.display.reportedViewFrom = cm.display.viewFrom; cm.display.reportedViewTo = cm.display.viewTo; } } @@ -777,6 +788,7 @@ updateSelection(cm); setDocumentHeight(cm, barMeasure); updateScrollbars(cm, barMeasure); + update.finish(); } } @@ -2237,6 +2249,8 @@ // Fire change events, and delayed event handlers if (op.changeObjs) signal(cm, "changes", cm, op.changeObjs); + if (op.update) + op.update.finish(); } // Run the given function in an operation @@ -2611,8 +2625,10 @@ } function focusInput(cm) { - if (cm.options.readOnly != "nocursor" && (!mobile || activeElt() != cm.display.input)) - cm.display.input.focus(); + if (cm.options.readOnly != "nocursor" && (!mobile || activeElt() != cm.display.input)) { + try { cm.display.input.focus(); } + catch (e) {} // IE8 will throw if the textarea is display: none or not in DOM + } } function ensureFocus(cm) { @@ -5121,7 +5137,7 @@ // FROMTEXTAREA CodeMirror.fromTextArea = function(textarea, options) { - if (!options) options = {}; + options = options ? copyObj(options) : {}; options.value = textarea.value; if (!options.tabindex && textarea.tabindex) options.tabindex = textarea.tabindex; @@ -5152,23 +5168,26 @@ } } + options.finishInit = function(cm) { + cm.save = save; + cm.getTextArea = function() { return textarea; }; + cm.toTextArea = function() { + cm.toTextArea = isNaN; // Prevent this from being ran twice + save(); + textarea.parentNode.removeChild(cm.getWrapperElement()); + textarea.style.display = ""; + if (textarea.form) { + off(textarea.form, "submit", save); + if (typeof textarea.form.submit == "function") + textarea.form.submit = realSubmit; + } + }; + }; + textarea.style.display = "none"; var cm = CodeMirror(function(node) { textarea.parentNode.insertBefore(node, textarea.nextSibling); }, options); - cm.save = save; - cm.getTextArea = function() { return textarea; }; - cm.toTextArea = function() { - cm.toTextArea = isNaN; // Prevent this from being ran twice - save(); - textarea.parentNode.removeChild(cm.getWrapperElement()); - textarea.style.display = ""; - if (textarea.form) { - off(textarea.form, "submit", save); - if (typeof textarea.form.submit == "function") - textarea.form.submit = realSubmit; - } - }; return cm; }; @@ -6179,6 +6198,7 @@ function defaultSpecialCharPlaceholder(ch) { var token = elt("span", "\u2022", "cm-invalidchar"); token.title = "\\u" + ch.charCodeAt(0).toString(16); + token.setAttribute("aria-label", token.title); return token; } @@ -6212,6 +6232,7 @@ if (m[0] == "\t") { var tabSize = builder.cm.options.tabSize, tabWidth = tabSize - builder.col % tabSize; var txt = content.appendChild(elt("span", spaceStr(tabWidth), "cm-tab")); + txt.setAttribute("role", "presentation"); builder.col += tabWidth; } else { var txt = builder.cm.options.specialCharPlaceholder(m[0]); @@ -7576,12 +7597,14 @@ return removeChildren(parent).appendChild(e); } - function contains(parent, child) { + var contains = CodeMirror.contains = function(parent, child) { if (parent.contains) return parent.contains(child); - while (child = child.parentNode) + while (child = child.parentNode) { + if (child.nodeType == 11) child = child.host; if (child == parent) return true; - } + } + }; function activeElt() { return document.activeElement; } // Older versions of IE throws unspecified error when touching @@ -8039,7 +8062,7 @@ // THE END - CodeMirror.version = "4.12.0"; + CodeMirror.version = "4.13.0"; return CodeMirror; }); diff --git a/applications/admin/static/codemirror/mode/css/css.js b/applications/admin/static/codemirror/mode/css/css.js index 3f02907e..34355aaa 100644 --- a/applications/admin/static/codemirror/mode/css/css.js +++ b/applications/admin/static/codemirror/mode/css/css.js @@ -16,13 +16,15 @@ CodeMirror.defineMode("css", function(config, parserConfig) { var indentUnit = config.indentUnit, tokenHooks = parserConfig.tokenHooks, + documentTypes = parserConfig.documentTypes || {}, mediaTypes = parserConfig.mediaTypes || {}, mediaFeatures = parserConfig.mediaFeatures || {}, propertyKeywords = parserConfig.propertyKeywords || {}, nonStandardPropertyKeywords = parserConfig.nonStandardPropertyKeywords || {}, + fontProperties = parserConfig.fontProperties || {}, + counterDescriptors = parserConfig.counterDescriptors || {}, colorKeywords = parserConfig.colorKeywords || {}, valueKeywords = parserConfig.valueKeywords || {}, - fontProperties = parserConfig.fontProperties || {}, allowNested = parserConfig.allowNested; var type, override; @@ -57,6 +59,11 @@ CodeMirror.defineMode("css", function(config, parserConfig) { if (/[\d.]/.test(stream.peek())) { stream.eatWhile(/[\w.%]/); return ret("number", "unit"); + } else if (stream.match(/^-[\w\\\-]+/)) { + stream.eatWhile(/[\w\\\-]/); + if (stream.match(/^\s*:/, false)) + return ret("variable-2", "variable-definition"); + return ret("variable-2", "variable"); } else if (stream.match(/^\w+-/)) { return ret("meta", "meta"); } @@ -66,7 +73,9 @@ CodeMirror.defineMode("css", function(config, parserConfig) { return ret("qualifier", "qualifier"); } else if (/[:;{}\[\]\(\)]/.test(ch)) { return ret(null, ch); - } else if (ch == "u" && stream.match("rl(")) { + } else if ((ch == "u" && stream.match(/rl(-prefix)?\(/)) || + (ch == "d" && stream.match("omain(")) || + (ch == "r" && stream.match("egexp("))) { stream.backUp(1); state.tokenize = tokenParenthesized; return ret("property", "word"); @@ -148,10 +157,11 @@ CodeMirror.defineMode("css", function(config, parserConfig) { return pushContext(state, stream, "block"); } else if (type == "}" && state.context.prev) { return popContext(state); - } else if (type == "@media") { - return pushContext(state, stream, "media"); - } else if (type == "@font-face") { - return "font_face_before"; + } else if (/@(media|supports|(-moz-)?document)/.test(type)) { + return pushContext(state, stream, "atBlock"); + } else if (/@(font-face|counter-style)/.test(type)) { + state.stateArg = type; + return "restricted_atBlock_before"; } else if (/^@(-(moz|ms|o|webkit)-)?keyframes$/.test(type)) { return "keyframes"; } else if (type && type.charAt(0) == "@") { @@ -241,47 +251,63 @@ CodeMirror.defineMode("css", function(config, parserConfig) { return pass(type, stream, state); }; - states.media = function(type, stream, state) { - if (type == "(") return pushContext(state, stream, "media_parens"); + states.atBlock = function(type, stream, state) { + if (type == "(") return pushContext(state, stream, "atBlock_parens"); if (type == "}") return popAndPass(type, stream, state); if (type == "{") return popContext(state) && pushContext(state, stream, allowNested ? "block" : "top"); if (type == "word") { var word = stream.current().toLowerCase(); - if (word == "only" || word == "not" || word == "and") + if (word == "only" || word == "not" || word == "and" || word == "or") override = "keyword"; + else if (documentTypes.hasOwnProperty(word)) + override = "tag"; else if (mediaTypes.hasOwnProperty(word)) override = "attribute"; else if (mediaFeatures.hasOwnProperty(word)) override = "property"; + else if (propertyKeywords.hasOwnProperty(word)) + override = "property"; + else if (nonStandardPropertyKeywords.hasOwnProperty(word)) + override = "string-2"; + else if (valueKeywords.hasOwnProperty(word)) + override = "atom"; else override = "error"; } return state.context.type; }; - states.media_parens = function(type, stream, state) { + states.atBlock_parens = function(type, stream, state) { if (type == ")") return popContext(state); if (type == "{" || type == "}") return popAndPass(type, stream, state, 2); - return states.media(type, stream, state); + return states.atBlock(type, stream, state); }; - states.font_face_before = function(type, stream, state) { + states.restricted_atBlock_before = function(type, stream, state) { if (type == "{") - return pushContext(state, stream, "font_face"); + return pushContext(state, stream, "restricted_atBlock"); + if (type == "word" && state.stateArg == "@counter-style") { + override = "variable"; + return "restricted_atBlock_before"; + } return pass(type, stream, state); }; - states.font_face = function(type, stream, state) { - if (type == "}") return popContext(state); + states.restricted_atBlock = function(type, stream, state) { + if (type == "}") { + state.stateArg = null; + return popContext(state); + } if (type == "word") { - if (!fontProperties.hasOwnProperty(stream.current().toLowerCase())) + if ((state.stateArg == "@font-face" && !fontProperties.hasOwnProperty(stream.current().toLowerCase())) || + (state.stateArg == "@counter-style" && !counterDescriptors.hasOwnProperty(stream.current().toLowerCase()))) override = "error"; else override = "property"; return "maybeprop"; } - return "font_face"; + return "restricted_atBlock"; }; states.keyframes = function(type, stream, state) { @@ -309,6 +335,7 @@ CodeMirror.defineMode("css", function(config, parserConfig) { startState: function(base) { return {tokenize: null, state: "top", + stateArg: null, context: new Context("top", base || 0, null)}; }, @@ -329,9 +356,9 @@ CodeMirror.defineMode("css", function(config, parserConfig) { var indent = cx.indent; if (cx.type == "prop" && (ch == "}" || ch == ")")) cx = cx.prev; if (cx.prev && - (ch == "}" && (cx.type == "block" || cx.type == "top" || cx.type == "interpolation" || cx.type == "font_face") || - ch == ")" && (cx.type == "parens" || cx.type == "media_parens") || - ch == "{" && (cx.type == "at" || cx.type == "media"))) { + (ch == "}" && (cx.type == "block" || cx.type == "top" || cx.type == "interpolation" || cx.type == "restricted_atBlock") || + ch == ")" && (cx.type == "parens" || cx.type == "atBlock_parens") || + ch == "{" && (cx.type == "at" || cx.type == "atBlock"))) { indent = cx.indent - indentUnit; cx = cx.prev; } @@ -353,6 +380,10 @@ CodeMirror.defineMode("css", function(config, parserConfig) { return keys; } + var documentTypes_ = [ + "domain", "regexp", "url", "url-prefix" + ], documentTypes = keySet(documentTypes_); + var mediaTypes_ = [ "all", "aural", "braille", "handheld", "print", "projection", "screen", "tty", "tv", "embossed" @@ -469,6 +500,16 @@ CodeMirror.defineMode("css", function(config, parserConfig) { "searchfield-results-decoration", "zoom" ], nonStandardPropertyKeywords = keySet(nonStandardPropertyKeywords_); + var fontProperties_ = [ + "font-family", "src", "unicode-range", "font-variant", "font-feature-settings", + "font-stretch", "font-weight", "font-style" + ], fontProperties = keySet(fontProperties_); + + var counterDescriptors_ = [ + "additive-symbols", "fallback", "negative", "pad", "prefix", "range", + "speak-as", "suffix", "symbols", "system" + ], counterDescriptors = keySet(counterDescriptors_); + var colorKeywords_ = [ "aliceblue", "antiquewhite", "aqua", "aquamarine", "azure", "beige", "bisque", "black", "blanchedalmond", "blue", "blueviolet", "brown", @@ -499,32 +540,33 @@ CodeMirror.defineMode("css", function(config, parserConfig) { ], colorKeywords = keySet(colorKeywords_); var valueKeywords_ = [ - "above", "absolute", "activeborder", "activecaption", "afar", - "after-white-space", "ahead", "alias", "all", "all-scroll", "alternate", + "above", "absolute", "activeborder", "additive", "activecaption", "afar", + "after-white-space", "ahead", "alias", "all", "all-scroll", "alphabetic", "alternate", "always", "amharic", "amharic-abegede", "antialiased", "appworkspace", - "arabic-indic", "armenian", "asterisks", "auto", "avoid", "avoid-column", "avoid-page", + "arabic-indic", "armenian", "asterisks", "attr", "auto", "avoid", "avoid-column", "avoid-page", "avoid-region", "background", "backwards", "baseline", "below", "bidi-override", "binary", "bengali", "blink", "block", "block-axis", "bold", "bolder", "border", "border-box", - "both", "bottom", "break", "break-all", "break-word", "button", "button-bevel", - "buttonface", "buttonhighlight", "buttonshadow", "buttontext", "cambodian", + "both", "bottom", "break", "break-all", "break-word", "bullets", "button", "button-bevel", + "buttonface", "buttonhighlight", "buttonshadow", "buttontext", "calc", "cambodian", "capitalize", "caps-lock-indicator", "caption", "captiontext", "caret", - "cell", "center", "checkbox", "circle", "cjk-earthly-branch", + "cell", "center", "checkbox", "circle", "cjk-decimal", "cjk-earthly-branch", "cjk-heavenly-stem", "cjk-ideographic", "clear", "clip", "close-quote", "col-resize", "collapse", "column", "compact", "condensed", "contain", "content", - "content-box", "context-menu", "continuous", "copy", "cover", "crop", - "cross", "crosshair", "currentcolor", "cursive", "dashed", "decimal", + "content-box", "context-menu", "continuous", "copy", "counter", "counters", "cover", "crop", + "cross", "crosshair", "currentcolor", "cursive", "cyclic", "dashed", "decimal", "decimal-leading-zero", "default", "default-button", "destination-atop", "destination-in", "destination-out", "destination-over", "devanagari", - "disc", "discard", "document", "dot-dash", "dot-dot-dash", "dotted", - "double", "down", "e-resize", "ease", "ease-in", "ease-in-out", "ease-out", + "disc", "discard", "disclosure-closed", "disclosure-open", "document", + "dot-dash", "dot-dot-dash", + "dotted", "double", "down", "e-resize", "ease", "ease-in", "ease-in-out", "ease-out", "element", "ellipse", "ellipsis", "embed", "end", "ethiopic", "ethiopic-abegede", "ethiopic-abegede-am-et", "ethiopic-abegede-gez", "ethiopic-abegede-ti-er", "ethiopic-abegede-ti-et", "ethiopic-halehame-aa-er", "ethiopic-halehame-aa-et", "ethiopic-halehame-am-et", "ethiopic-halehame-gez", "ethiopic-halehame-om-et", "ethiopic-halehame-sid-et", "ethiopic-halehame-so-et", - "ethiopic-halehame-ti-er", "ethiopic-halehame-ti-et", - "ethiopic-halehame-tig", "ew-resize", "expanded", "extra-condensed", + "ethiopic-halehame-ti-er", "ethiopic-halehame-ti-et", "ethiopic-halehame-tig", + "ethiopic-numeric", "ew-resize", "expanded", "extends", "extra-condensed", "extra-expanded", "fantasy", "fast", "fill", "fixed", "flat", "flex", "footnotes", "forwards", "from", "geometricPrecision", "georgian", "graytext", "groove", "gujarati", "gurmukhi", "hand", "hangul", "hangul-consonant", "hebrew", @@ -533,12 +575,14 @@ CodeMirror.defineMode("css", function(config, parserConfig) { "inactiveborder", "inactivecaption", "inactivecaptiontext", "infinite", "infobackground", "infotext", "inherit", "initial", "inline", "inline-axis", "inline-block", "inline-flex", "inline-table", "inset", "inside", "intrinsic", "invert", - "italic", "justify", "kannada", "katakana", "katakana-iroha", "keep-all", "khmer", + "italic", "japanese-formal", "japanese-informal", "justify", "kannada", + "katakana", "katakana-iroha", "keep-all", "khmer", + "korean-hangul-formal", "korean-hanja-formal", "korean-hanja-informal", "landscape", "lao", "large", "larger", "left", "level", "lighter", - "line-through", "linear", "lines", "list-item", "listbox", "listitem", + "line-through", "linear", "linear-gradient", "lines", "list-item", "listbox", "listitem", "local", "logical", "loud", "lower", "lower-alpha", "lower-armenian", "lower-greek", "lower-hexadecimal", "lower-latin", "lower-norwegian", - "lower-roman", "lowercase", "ltr", "malayalam", "match", + "lower-roman", "lowercase", "ltr", "malayalam", "match", "matrix", "matrix3d", "media-controls-background", "media-current-time-display", "media-fullscreen-button", "media-mute-button", "media-play-button", "media-return-to-realtime-button", "media-rewind-button", @@ -550,45 +594,48 @@ CodeMirror.defineMode("css", function(config, parserConfig) { "mix", "mongolian", "monospace", "move", "multiple", "myanmar", "n-resize", "narrower", "ne-resize", "nesw-resize", "no-close-quote", "no-drop", "no-open-quote", "no-repeat", "none", "normal", "not-allowed", "nowrap", - "ns-resize", "nw-resize", "nwse-resize", "oblique", "octal", "open-quote", + "ns-resize", "numbers", "numeric", "nw-resize", "nwse-resize", "oblique", "octal", "open-quote", "optimizeLegibility", "optimizeSpeed", "oriya", "oromo", "outset", "outside", "outside-shape", "overlay", "overline", "padding", "padding-box", - "painted", "page", "paused", "persian", "plus-darker", "plus-lighter", "pointer", - "polygon", "portrait", "pre", "pre-line", "pre-wrap", "preserve-3d", "progress", "push-button", - "radio", "read-only", "read-write", "read-write-plaintext-only", "rectangle", "region", - "relative", "repeat", "repeat-x", "repeat-y", "reset", "reverse", "rgb", "rgba", - "ridge", "right", "round", "row-resize", "rtl", "run-in", "running", - "s-resize", "sans-serif", "scroll", "scrollbar", "se-resize", "searchfield", + "painted", "page", "paused", "persian", "perspective", "plus-darker", "plus-lighter", + "pointer", "polygon", "portrait", "pre", "pre-line", "pre-wrap", "preserve-3d", + "progress", "push-button", "radial-gradient", "radio", "read-only", + "read-write", "read-write-plaintext-only", "rectangle", "region", + "relative", "repeat", "repeating-linear-gradient", + "repeating-radial-gradient", "repeat-x", "repeat-y", "reset", "reverse", + "rgb", "rgba", "ridge", "right", "rotate", "rotate3d", "rotateX", "rotateY", + "rotateZ", "round", "row-resize", "rtl", "run-in", "running", + "s-resize", "sans-serif", "scale", "scale3d", "scaleX", "scaleY", "scaleZ", + "scroll", "scrollbar", "se-resize", "searchfield", "searchfield-cancel-button", "searchfield-decoration", "searchfield-results-button", "searchfield-results-decoration", "semi-condensed", "semi-expanded", "separate", "serif", "show", "sidama", - "single", "skip-white-space", "slide", "slider-horizontal", + "simp-chinese-formal", "simp-chinese-informal", "single", + "skew", "skewX", "skewY", "skip-white-space", "slide", "slider-horizontal", "slider-vertical", "sliderthumb-horizontal", "sliderthumb-vertical", "slow", "small", "small-caps", "small-caption", "smaller", "solid", "somali", - "source-atop", "source-in", "source-out", "source-over", "space", "square", - "square-button", "start", "static", "status-bar", "stretch", "stroke", - "sub", "subpixel-antialiased", "super", "sw-resize", "table", + "source-atop", "source-in", "source-out", "source-over", "space", "spell-out", "square", + "square-button", "start", "static", "status-bar", "stretch", "stroke", "sub", + "subpixel-antialiased", "super", "sw-resize", "symbolic", "symbols", "table", "table-caption", "table-cell", "table-column", "table-column-group", "table-footer-group", "table-header-group", "table-row", "table-row-group", + "tamil", "telugu", "text", "text-bottom", "text-top", "textarea", "textfield", "thai", "thick", "thin", "threeddarkshadow", "threedface", "threedhighlight", "threedlightshadow", "threedshadow", "tibetan", "tigre", "tigrinya-er", "tigrinya-er-abegede", "tigrinya-et", "tigrinya-et-abegede", "to", "top", + "trad-chinese-formal", "trad-chinese-informal", + "translate", "translate3d", "translateX", "translateY", "translateZ", "transparent", "ultra-condensed", "ultra-expanded", "underline", "up", "upper-alpha", "upper-armenian", "upper-greek", "upper-hexadecimal", "upper-latin", "upper-norwegian", "upper-roman", "uppercase", "urdu", "url", - "vertical", "vertical-text", "visible", "visibleFill", "visiblePainted", + "var", "vertical", "vertical-text", "visible", "visibleFill", "visiblePainted", "visibleStroke", "visual", "w-resize", "wait", "wave", "wider", - "window", "windowframe", "windowtext", "x-large", "x-small", "xor", + "window", "windowframe", "windowtext", "words", "x-large", "x-small", "xor", "xx-large", "xx-small" ], valueKeywords = keySet(valueKeywords_); - var fontProperties_ = [ - "font-family", "src", "unicode-range", "font-variant", "font-feature-settings", - "font-stretch", "font-weight", "font-style" - ], fontProperties = keySet(fontProperties_); - - var allWords = mediaTypes_.concat(mediaFeatures_).concat(propertyKeywords_) + var allWords = documentTypes_.concat(mediaTypes_).concat(mediaFeatures_).concat(propertyKeywords_) .concat(nonStandardPropertyKeywords_).concat(colorKeywords_).concat(valueKeywords_); CodeMirror.registerHelper("hintWords", "css", allWords); @@ -615,13 +662,15 @@ CodeMirror.defineMode("css", function(config, parserConfig) { } CodeMirror.defineMIME("text/css", { + documentTypes: documentTypes, mediaTypes: mediaTypes, mediaFeatures: mediaFeatures, propertyKeywords: propertyKeywords, nonStandardPropertyKeywords: nonStandardPropertyKeywords, + fontProperties: fontProperties, + counterDescriptors: counterDescriptors, colorKeywords: colorKeywords, valueKeywords: valueKeywords, - fontProperties: fontProperties, tokenHooks: { "<": function(stream, state) { if (!stream.match("!--")) return false; diff --git a/applications/admin/static/codemirror/mode/css/test.js b/applications/admin/static/codemirror/mode/css/test.js index d236e2a7..bef71561 100644 --- a/applications/admin/static/codemirror/mode/css/test.js +++ b/applications/admin/static/codemirror/mode/css/test.js @@ -126,10 +126,70 @@ MT("parens", "[qualifier .foo] {", " [property background-image]: [variable fade]([atom #000], [number 20%]);", - " [property border-image]: [variable linear-gradient](", + " [property border-image]: [atom linear-gradient](", " [atom to] [atom bottom],", " [variable fade]([atom #000], [number 20%]) [number 0%],", " [variable fade]([atom #000], [number 20%]) [number 100%]", " );", "}"); + + MT("css_variable", + ":[variable-3 root] {", + " [variable-2 --main-color]: [atom #06c];", + "}", + "[tag h1][builtin #foo] {", + " [property color]: [atom var]([variable-2 --main-color]);", + "}"); + + MT("supports", + "[def @supports] ([keyword not] (([property text-align-last]: [atom justify]) [keyword or] ([meta -moz-][property text-align-last]: [atom justify])) {", + " [property text-align-last]: [atom justify];", + "}"); + + MT("document", + "[def @document] [tag url]([string http://blah]),", + " [tag url-prefix]([string https://]),", + " [tag domain]([string blah.com]),", + " [tag regexp]([string \".*blah.+\"]) {", + " [builtin #id] {", + " [property background-color]: [keyword white];", + " }", + " [tag foo] {", + " [property font-family]: [variable Verdana], [atom sans-serif];", + " }", + " }"); + + MT("document_url", + "[def @document] [tag url]([string http://blah]) { [qualifier .class] { } }"); + + MT("document_urlPrefix", + "[def @document] [tag url-prefix]([string https://]) { [builtin #id] { } }"); + + MT("document_domain", + "[def @document] [tag domain]([string blah.com]) { [tag foo] { } }"); + + MT("document_regexp", + "[def @document] [tag regexp]([string \".*blah.+\"]) { [builtin #id] { } }"); + + MT("counter-style", + "[def @counter-style] [variable binary] {", + " [property system]: [atom numeric];", + " [property symbols]: [number 0] [number 1];", + " [property suffix]: [string \".\"];", + " [property range]: [atom infinite];", + " [property speak-as]: [atom numeric];", + "}"); + + MT("counter-style-additive-symbols", + "[def @counter-style] [variable simple-roman] {", + " [property system]: [atom additive];", + " [property additive-symbols]: [number 10] [variable X], [number 5] [variable V], [number 1] [variable I];", + " [property range]: [number 1] [number 49];", + "}"); + + MT("counter-style-use", + "[tag ol][qualifier .roman] { [property list-style]: [variable simple-roman]; }"); + + MT("counter-style-symbols", + "[tag ol] { [property list-style]: [atom symbols]([atom cyclic] [string \"*\"] [string \"\\2020\"] [string \"\\2021\"] [string \"\\A7\"]); }"); })(); diff --git a/applications/admin/static/codemirror/mode/javascript/javascript.js b/applications/admin/static/codemirror/mode/javascript/javascript.js index 93df06d1..3f05ac46 100644 --- a/applications/admin/static/codemirror/mode/javascript/javascript.js +++ b/applications/admin/static/codemirror/mode/javascript/javascript.js @@ -118,7 +118,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) { } else if (state.lastType == "operator" || state.lastType == "keyword c" || state.lastType == "sof" || /^[\[{}\(,;:]$/.test(state.lastType)) { readRegexp(stream); - stream.eatWhile(/[gimy]/); // 'y' is "sticky" option in Mozilla + stream.match(/^\b(([gimyu])(?![gimyu]*\2))+\b/); return ret("regexp", "string-2"); } else { stream.eatWhile(isOperatorChar); diff --git a/applications/admin/static/codemirror/theme/colorforth.css b/applications/admin/static/codemirror/theme/colorforth.css new file mode 100644 index 00000000..73fbf808 --- /dev/null +++ b/applications/admin/static/codemirror/theme/colorforth.css @@ -0,0 +1,33 @@ +.cm-s-colorforth.CodeMirror { background: #000000; color: #f8f8f8; } +.cm-s-colorforth .CodeMirror-gutters { background: #0a001f; border-right: 1px solid #aaa; } +.cm-s-colorforth .CodeMirror-guttermarker { color: #FFBD40; } +.cm-s-colorforth .CodeMirror-guttermarker-subtle { color: #78846f; } +.cm-s-colorforth .CodeMirror-linenumber { color: #bababa; } +.cm-s-colorforth .CodeMirror-cursor { border-left: 1px solid white !important; } + +.cm-s-colorforth span.cm-comment { color: #ededed; } +.cm-s-colorforth span.cm-def { color: #ff1c1c; font-weight:bold; } +.cm-s-colorforth span.cm-keyword { color: #ffd900; } +.cm-s-colorforth span.cm-builtin { color: #00d95a; } +.cm-s-colorforth span.cm-variable { color: #73ff00; } +.cm-s-colorforth span.cm-string { color: #007bff; } +.cm-s-colorforth span.cm-number { color: #00c4ff; } +.cm-s-colorforth span.cm-atom { color: #606060; } + +.cm-s-colorforth span.cm-variable-2 { color: #EEE; } +.cm-s-colorforth span.cm-variable-3 { color: #DDD; } +.cm-s-colorforth span.cm-property {} +.cm-s-colorforth span.cm-operator {} + +.cm-s-colorforth span.cm-meta { color: yellow; } +.cm-s-colorforth span.cm-qualifier { color: #FFF700; } +.cm-s-colorforth span.cm-bracket { color: #cc7; } +.cm-s-colorforth span.cm-tag { color: #FFBD40; } +.cm-s-colorforth span.cm-attribute { color: #FFF700; } +.cm-s-colorforth span.cm-error { color: #f00; } + +.cm-s-colorforth .CodeMirror-selected { background: #333d53 !important; } + +.cm-s-colorforth span.cm-compilation { background: rgba(255, 255, 255, 0.12); } + +.cm-s-colorforth .CodeMirror-activeline-background {background: #253540 !important;}