From 9d2f415138647fe79119ff183dc551f3997201a4 Mon Sep 17 00:00:00 2001 From: betateilchen Date: Fri, 25 Apr 2014 20:58:29 +0000 Subject: [PATCH] codemirror: update to version 3.24 git-svn-id: svn://svn.code.sf.net/p/fhem/code/trunk@5647 2b470e98-0d58-463d-a4d8-8e2adae1ed80 --- fhem/www/codemirror/LICENSE | 2 +- fhem/www/codemirror/codemirror.css | 30 ++-- fhem/www/codemirror/codemirror.js | 251 +++++++++++++++++++---------- fhem/www/codemirror/css.js | 29 +++- fhem/www/codemirror/show-hint.js | 44 ++--- fhem/www/codemirror/xml.js | 106 ++++++++---- 6 files changed, 306 insertions(+), 156 deletions(-) diff --git a/fhem/www/codemirror/LICENSE b/fhem/www/codemirror/LICENSE index 442d11cdc..d21bbea5a 100644 --- a/fhem/www/codemirror/LICENSE +++ b/fhem/www/codemirror/LICENSE @@ -1,4 +1,4 @@ -Copyright (C) 2013 by Marijn Haverbeke and others +Copyright (C) 2014 by Marijn Haverbeke and others Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/fhem/www/codemirror/codemirror.css b/fhem/www/codemirror/codemirror.css index 23eaf74d4..6cf5bae38 100644 --- a/fhem/www/codemirror/codemirror.css +++ b/fhem/www/codemirror/codemirror.css @@ -36,6 +36,8 @@ min-width: 20px; text-align: right; color: #999; + -moz-box-sizing: content-box; + box-sizing: content-box; } /* CURSOR */ @@ -59,17 +61,23 @@ .cm-tab { display: inline-block; } +.CodeMirror-ruler { + border-left: 1px solid #ccc; + position: absolute; +} + /* DEFAULT THEME */ .cm-s-default .cm-keyword {color: #708;} .cm-s-default .cm-atom {color: #219;} .cm-s-default .cm-number {color: #164;} .cm-s-default .cm-def {color: #00f;} -.cm-s-default .cm-variable {color: black;} +.cm-s-default .cm-variable, +.cm-s-default .cm-punctuation, +.cm-s-default .cm-property, +.cm-s-default .cm-operator {} .cm-s-default .cm-variable-2 {color: #05a;} .cm-s-default .cm-variable-3 {color: #085;} -.cm-s-default .cm-property {color: black;} -.cm-s-default .cm-operator {color: black;} .cm-s-default .cm-comment {color: #a50;} .cm-s-default .cm-string {color: #a11;} .cm-s-default .cm-string-2 {color: #f50;} @@ -114,7 +122,7 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;} /* 30px is the magic margin used to hide the element's real scrollbars */ /* See overflow: hidden in .CodeMirror */ margin-bottom: -30px; margin-right: -30px; - padding-bottom: 30px; padding-right: 30px; + padding-bottom: 30px; height: 100%; outline: none; /* Prevent dragging from highlighting the element */ position: relative; @@ -123,6 +131,9 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;} } .CodeMirror-sizer { position: relative; + border-right: 30px solid transparent; + -moz-box-sizing: content-box; + box-sizing: content-box; } /* The fake, visible scrollbars. Used to force redraw during scrolling @@ -197,16 +208,7 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;} white-space: pre-wrap; word-break: normal; } -.CodeMirror-code pre { - border-right: 30px solid transparent; - width: -webkit-fit-content; - width: -moz-fit-content; - width: fit-content; -} -.CodeMirror-wrap .CodeMirror-code pre { - border-right: none; - width: auto; -} + .CodeMirror-linebackground { position: absolute; left: 0; right: 0; top: 0; bottom: 0; diff --git a/fhem/www/codemirror/codemirror.js b/fhem/www/codemirror/codemirror.js index d82bd143c..3d450b35a 100644 --- a/fhem/www/codemirror/codemirror.js +++ b/fhem/www/codemirror/codemirror.js @@ -1,5 +1,3 @@ -// CodeMirror version 3.21 -// // CodeMirror is the only global var we claim window.CodeMirror = (function() { "use strict"; @@ -15,6 +13,7 @@ window.CodeMirror = (function() { var old_ie = /MSIE \d/.test(navigator.userAgent); var ie_lt8 = old_ie && (document.documentMode == null || document.documentMode < 8); var ie_lt9 = old_ie && (document.documentMode == null || document.documentMode < 9); + var ie_lt10 = old_ie && (document.documentMode == null || document.documentMode < 10); var ie_gt10 = /Trident\/([7-9]|\d{2,})\./.test(navigator.userAgent); var ie = old_ie || ie_gt10; var webkit = /WebKit\//.test(navigator.userAgent); @@ -38,7 +37,7 @@ window.CodeMirror = (function() { if (opera_version && opera_version >= 15) { opera = false; webkit = true; } // Some browsers use the wrong event properties to signal cmd/ctrl on OS X var flipCtrlCmd = mac && (qtwebkit || opera && (opera_version == null || opera_version < 12.11)); - var captureMiddleClick = gecko || (old_ie && !ie_lt9); + var captureMiddleClick = gecko || (ie && !ie_lt9); // Optimize some code when these features are not used var sawReadOnlySpans = false, sawCollapsedSpans = false; @@ -101,7 +100,7 @@ window.CodeMirror = (function() { function makeDisplay(place, docStart) { var d = {}; - var input = d.input = elt("textarea", null, null, "position: absolute; padding: 0; width: 1px; height: 1em; outline: none; font-size: 4px;"); + var input = d.input = elt("textarea", null, null, "position: absolute; padding: 0; width: 1px; height: 1em; outline: none"); if (webkit) input.style.width = "1000px"; else input.setAttribute("wrap", "off"); // if border: 0; -- iOS fails to open keyboard (issue #1287) @@ -111,8 +110,8 @@ window.CodeMirror = (function() { // Wraps and hides input textarea d.inputDiv = elt("div", [input], null, "overflow: hidden; position: relative; width: 3px; height: 0px;"); // The actual fake scrollbars. - d.scrollbarH = elt("div", [elt("div", null, null, "height: 1px")], "CodeMirror-hscrollbar"); - d.scrollbarV = elt("div", [elt("div", null, null, "width: 1px")], "CodeMirror-vscrollbar"); + d.scrollbarH = elt("div", [elt("div", null, null, "height: 100%; min-height: 1px")], "CodeMirror-hscrollbar"); + d.scrollbarV = elt("div", [elt("div", null, null, "min-width: 1px")], "CodeMirror-vscrollbar"); d.scrollbarFiller = elt("div", null, "CodeMirror-scrollbar-filler"); d.gutterFiller = elt("div", null, "CodeMirror-gutter-filler"); // DIVs containing the selection and the actual code @@ -173,7 +172,7 @@ window.CodeMirror = (function() { // Self-resetting timeout for the poller d.poll = new Delayed(); - d.cachedCharWidth = d.cachedTextHeight = null; + d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null; d.measureLineCache = []; d.measureLineCachePos = 0; @@ -231,12 +230,17 @@ window.CodeMirror = (function() { var th = textHeight(cm.display), wrapping = cm.options.lineWrapping; var perLine = wrapping && Math.max(5, cm.display.scroller.clientWidth / charWidth(cm.display) - 3); return function(line) { - if (lineIsHidden(cm.doc, line)) - return 0; - else if (wrapping) - return (Math.ceil(line.text.length / perLine) || 1) * th; + if (lineIsHidden(cm.doc, line)) return 0; + + var widgetsHeight = 0; + if (line.widgets) for (var i = 0; i < line.widgets.length; i++) { + if (line.widgets[i].height) widgetsHeight += line.widgets[i].height; + } + + if (wrapping) + return widgetsHeight + (Math.ceil(line.text.length / perLine) || 1) * th; else - return th; + return widgetsHeight + th; }; } @@ -334,13 +338,14 @@ window.CodeMirror = (function() { d.sizer.style.minHeight = d.heightForcer.style.top = totalHeight + "px"; d.gutters.style.height = Math.max(totalHeight, d.scroller.clientHeight - scrollerCutOff) + "px"; var scrollHeight = Math.max(totalHeight, d.scroller.scrollHeight); - var needsH = d.scroller.scrollWidth > (d.scroller.clientWidth + 1); - var needsV = scrollHeight > (d.scroller.clientHeight + 1); + var needsH = d.scroller.scrollWidth > d.scroller.clientWidth; + var needsV = scrollHeight > d.scroller.clientHeight; if (needsV) { d.scrollbarV.style.display = "block"; d.scrollbarV.style.bottom = needsH ? scrollbarWidth(d.measure) + "px" : "0"; + // A bug in IE8 can cause this value to be negative, so guard it. d.scrollbarV.firstChild.style.height = - (scrollHeight - d.scroller.clientHeight + d.scrollbarV.clientHeight) + "px"; + Math.max(0, scrollHeight - d.scroller.clientHeight + d.scrollbarV.clientHeight) + "px"; } else { d.scrollbarV.style.display = ""; d.scrollbarV.firstChild.style.height = "0"; @@ -366,7 +371,12 @@ window.CodeMirror = (function() { if (mac_geLion && scrollbarWidth(d.measure) === 0) { d.scrollbarV.style.minWidth = d.scrollbarH.style.minHeight = mac_geMountainLion ? "18px" : "12px"; - d.scrollbarV.style.pointerEvents = d.scrollbarH.style.pointerEvents = "none"; + var barMouseDown = function(e) { + if (e_target(e) != d.scrollbarV && e_target(e) != d.scrollbarH) + operation(cm, onMouseDown)(e); + }; + on(d.scrollbarV, "mousedown", barMouseDown); + on(d.scrollbarH, "mousedown", barMouseDown); } } @@ -820,12 +830,12 @@ window.CodeMirror = (function() { function updateSelectionRange(cm) { var display = cm.display, doc = cm.doc, sel = cm.doc.sel; var fragment = document.createDocumentFragment(); - var clientWidth = display.lineSpace.offsetWidth, pl = paddingLeft(cm.display); + var padding = paddingH(cm.display), leftSide = padding.left, rightSide = display.lineSpace.offsetWidth - padding.right; function add(left, top, width, bottom) { if (top < 0) top = 0; fragment.appendChild(elt("div", null, "CodeMirror-selected", "position: absolute; left: " + left + - "px; top: " + top + "px; width: " + (width == null ? clientWidth - left : width) + + "px; top: " + top + "px; width: " + (width == null ? rightSide - left : width) + "px; height: " + (bottom - top) + "px")); } @@ -848,18 +858,18 @@ window.CodeMirror = (function() { left = leftPos.left; right = rightPos.right; } - if (fromArg == null && from == 0) left = pl; + if (fromArg == null && from == 0) left = leftSide; if (rightPos.top - leftPos.top > 3) { // Different lines, draw top part add(left, leftPos.top, null, leftPos.bottom); - left = pl; + left = leftSide; if (leftPos.bottom < rightPos.top) add(left, leftPos.bottom, null, rightPos.top); } - if (toArg == null && to == lineLen) right = clientWidth; + if (toArg == null && to == lineLen) right = rightSide; if (!start || leftPos.top < start.top || leftPos.top == start.top && leftPos.left < start.left) start = leftPos; if (!end || rightPos.bottom > end.bottom || rightPos.bottom == end.bottom && rightPos.right > end.right) end = rightPos; - if (left < pl + 1) left = pl; + if (left < leftSide + 1) left = leftSide; add(left, rightPos.top, right - left, rightPos.bottom); }); return {start: start, end: end}; @@ -875,13 +885,13 @@ window.CodeMirror = (function() { if (singleVLine) { if (leftEnd.top < rightStart.top - 2) { add(leftEnd.right, leftEnd.top, null, leftEnd.bottom); - add(pl, rightStart.top, rightStart.left, rightStart.bottom); + add(leftSide, rightStart.top, rightStart.left, rightStart.bottom); } else { add(leftEnd.right, leftEnd.top, rightStart.left - leftEnd.right, leftEnd.bottom); } } if (leftEnd.bottom < rightStart.top) - add(pl, leftEnd.bottom, null, rightStart.top); + add(leftSide, leftEnd.bottom, null, rightStart.top); } removeChildrenAndAdd(display.selectionDiv, fragment); @@ -984,9 +994,12 @@ window.CodeMirror = (function() { function paddingTop(display) {return display.lineSpace.offsetTop;} function paddingVert(display) {return display.mover.offsetHeight - display.lineSpace.offsetHeight;} - function paddingLeft(display) { - var e = removeChildrenAndAdd(display.measure, elt("pre", null, null, "text-align: left")).appendChild(elt("span", "x")); - return e.offsetLeft; + function paddingH(display) { + if (display.cachedPaddingH) return display.cachedPaddingH; + var e = removeChildrenAndAdd(display.measure, elt("pre", "x")); + var style = window.getComputedStyle ? window.getComputedStyle(e) : e.currentStyle; + return display.cachedPaddingH = {left: parseInt(style.paddingLeft), + right: parseInt(style.paddingRight)}; } function measureChar(cm, line, ch, data, bias) { @@ -1155,12 +1168,17 @@ window.CodeMirror = (function() { var pre = buildLineContent(cm, line, null, true).pre; var end = pre.appendChild(zeroWidthElement(cm.display.measure)); removeChildrenAndAdd(cm.display.measure, pre); - return getRect(end).right - getRect(cm.display.lineDiv).left; + var rect = getRect(end); + if (rect.right == 0 && rect.bottom == 0) { + end = pre.appendChild(elt("span", "\u00a0")); + rect = getRect(end); + } + return rect.left - getRect(cm.display.lineDiv).left; } function clearCaches(cm) { cm.display.measureLineCache.length = cm.display.measureLineCachePos = 0; - cm.display.cachedCharWidth = cm.display.cachedTextHeight = null; + cm.display.cachedCharWidth = cm.display.cachedTextHeight = cm.display.cachedPaddingH = null; if (!cm.options.lineWrapping) cm.display.maxLineChanged = true; cm.display.lineNumChars = null; } @@ -1376,7 +1394,7 @@ window.CodeMirror = (function() { if (op.updateMaxLine) computeMaxLength(cm); if (display.maxLineChanged && !cm.options.lineWrapping && display.maxLine) { var width = measureLineWidth(cm, display.maxLine); - display.sizer.style.minWidth = Math.max(0, width + 3 + scrollerCutOff) + "px"; + display.sizer.style.minWidth = Math.max(0, width + 3) + "px"; display.maxLineChanged = false; var maxScrollLeft = Math.max(0, display.sizer.offsetLeft + display.sizer.offsetWidth - display.scroller.clientWidth); if (maxScrollLeft < doc.scrollLeft && !op.updateScrollPos) @@ -1490,10 +1508,6 @@ window.CodeMirror = (function() { function readInput(cm) { var input = cm.display.input, prevInput = cm.display.prevInput, doc = cm.doc, sel = doc.sel; if (!cm.state.focused || hasSelection(input) || isReadOnly(cm) || cm.options.disableInput) return false; - if (cm.state.pasteIncoming && cm.state.fakedLastChar) { - input.value = input.value.substring(0, input.value.length - 1); - cm.state.fakedLastChar = false; - } var text = input.value; if (text == prevInput && posEq(sel.from, sel.to)) return false; if (ie && !ie_lt9 && cm.display.inputHasSelection === text) { @@ -1558,6 +1572,10 @@ window.CodeMirror = (function() { cm.display.input.focus(); } + function ensureFocus(cm) { + if (!cm.state.focused) { focusInput(cm); onFocus(cm); } + } + function isReadOnly(cm) { return cm.options.readOnly || cm.doc.cantEdit; } @@ -1614,7 +1632,7 @@ window.CodeMirror = (function() { if (resizeTimer == null) resizeTimer = setTimeout(function() { resizeTimer = null; // Might be a text scaling operation, clear size caches. - d.cachedCharWidth = d.cachedTextHeight = knownScrollbarWidth = null; + d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = knownScrollbarWidth = null; clearCaches(cm); runInOp(cm, bind(regChange, cm)); }, 100); @@ -1630,10 +1648,7 @@ window.CodeMirror = (function() { } setTimeout(unregister, 5000); - on(d.input, "keyup", operation(cm, function(e) { - if (signalDOMEvent(cm, e) || cm.options.onKeyEvent && cm.options.onKeyEvent(cm, addStop(e))) return; - if (e.keyCode == 16) cm.doc.sel.shift = false; - })); + on(d.input, "keyup", operation(cm, onKeyUp)); on(d.input, "input", function() { if (ie && !ie_lt9 && cm.display.inputHasSelection) cm.display.inputHasSelection = null; fastPoll(cm); @@ -1659,16 +1674,6 @@ window.CodeMirror = (function() { fastPoll(cm); }); on(d.input, "paste", function() { - // Workaround for webkit bug https://bugs.webkit.org/show_bug.cgi?id=90206 - // Add a char to the end of textarea before paste occur so that - // selection doesn't span to the end of textarea. - if (webkit && !cm.state.fakedLastChar && !(new Date - cm.state.lastMiddleDown < 200)) { - var start = d.input.selectionStart, end = d.input.selectionEnd; - d.input.value += "$"; - d.input.selectionStart = start; - d.input.selectionEnd = end; - cm.state.fakedLastChar = true; - } cm.state.pasteIncoming = true; fastPoll(cm); }); @@ -1702,8 +1707,7 @@ window.CodeMirror = (function() { var display = cm.display; if (!liberal) { var target = e_target(e); - if (target == display.scrollbarH || target == display.scrollbarH.firstChild || - target == display.scrollbarV || target == display.scrollbarV.firstChild || + if (target == display.scrollbarH || target == display.scrollbarV || target == display.scrollbarFiller || target == display.gutterFiller) return null; } var x, y, space = getRect(display.lineSpace); @@ -1727,6 +1731,7 @@ window.CodeMirror = (function() { } if (clickInGutter(cm, e)) return; var start = posFromMouse(cm, e); + window.focus(); switch (e_button(e)) { case 3: @@ -1744,7 +1749,7 @@ window.CodeMirror = (function() { // selection. if (!start) {if (e_target(e) == display.scroller) e_preventDefault(e); return;} - if (!cm.state.focused) onFocus(cm); + setTimeout(bind(ensureFocus, cm), 0); var now = +new Date, type = "single"; if (lastDoubleClick && lastDoubleClick.time > now - 400 && posEq(lastDoubleClick.pos, start)) { @@ -1824,7 +1829,7 @@ window.CodeMirror = (function() { var cur = posFromMouse(cm, e, true); if (!cur) return; if (!posEq(cur, last)) { - if (!cm.state.focused) onFocus(cm); + ensureFocus(cm); last = cur; doSelect(cur); var visible = visibleLines(display, doc); @@ -1849,7 +1854,7 @@ window.CodeMirror = (function() { } var move = operation(cm, function(e) { - if (!old_ie && !e_button(e)) done(e); + if ((ie && !ie_lt10) ? !e.buttons : !e_button(e)) done(e); else extend(e); }); var up = operation(cm, done); @@ -1994,7 +1999,7 @@ window.CodeMirror = (function() { // know one. These don't have to be accurate -- the result of them // being wrong would just be a slight flicker on the first wheel // scroll (if it is large enough). - if (old_ie) wheelPixelsPerUnit = -.53; + if (ie) wheelPixelsPerUnit = -.53; else if (gecko) wheelPixelsPerUnit = 15; else if (chrome) wheelPixelsPerUnit = -.7; else if (safari) wheelPixelsPerUnit = -1/3; @@ -2143,10 +2148,16 @@ window.CodeMirror = (function() { return handled; } + function onKeyUp(e) { + var cm = this; + if (signalDOMEvent(cm, e) || cm.options.onKeyEvent && cm.options.onKeyEvent(cm, addStop(e))) return; + if (e.keyCode == 16) cm.doc.sel.shift = false; + } + var lastStoppedKey = null; function onKeyDown(e) { var cm = this; - if (!cm.state.focused) onFocus(cm); + ensureFocus(cm); if (signalDOMEvent(cm, e) || cm.options.onKeyEvent && cm.options.onKeyEvent(cm, addStop(e))) return; if (old_ie && e.keyCode == 27) e.returnValue = false; var code = e.keyCode; @@ -2217,8 +2228,9 @@ window.CodeMirror = (function() { var oldCSS = display.input.style.cssText; display.inputDiv.style.position = "absolute"; display.input.style.cssText = "position: fixed; width: 30px; height: 30px; top: " + (e.clientY - 5) + - "px; left: " + (e.clientX - 5) + "px; z-index: 1000; background: transparent; outline: none;" + - "border-width: 0; outline: none; overflow: hidden; opacity: .05; -ms-opacity: .05; filter: alpha(opacity=5);"; + "px; left: " + (e.clientX - 5) + "px; z-index: 1000; background: " + + (ie ? "rgba(255, 255, 255, .05)" : "transparent") + + "; outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);"; focusInput(cm); resetInput(cm, true); // Adds "Select all" to context menu in FF @@ -2239,7 +2251,7 @@ window.CodeMirror = (function() { // Try to detect the user choosing select-all if (display.input.selectionStart != null) { - if (!old_ie || ie_lt9) prepareSelectAllHack(); + if (!ie || ie_lt9) prepareSelectAllHack(); clearTimeout(detectingSelectAll); var i = 0, poll = function(){ if (display.prevInput == "\u200b" && display.input.selectionStart == 0) @@ -2251,7 +2263,7 @@ window.CodeMirror = (function() { } } - if (old_ie && !ie_lt9) prepareSelectAllHack(); + if (ie && !ie_lt9) prepareSelectAllHack(); if (captureMiddleClick) { e_stop(e); var mouseup = function() { @@ -2748,15 +2760,16 @@ window.CodeMirror = (function() { // API UTILITIES function indentLine(cm, n, how, aggressive) { - var doc = cm.doc; + var doc = cm.doc, state; if (how == null) how = "add"; if (how == "smart") { if (!cm.doc.mode.indent) how = "prev"; - else var state = getStateBefore(cm, n); + else state = getStateBefore(cm, n); } var tabSize = cm.options.tabSize; var line = getLine(doc, n), curSpace = countColumn(line.text, null, tabSize); + if (line.stateAfter) line.stateAfter = null; var curSpaceString = line.text.match(/^\s*/)[0], indentation; if (!aggressive && !/\S/.test(line.text)) { indentation = 0; @@ -2798,7 +2811,6 @@ window.CodeMirror = (function() { else no = lineNo(handle); if (no == null) return null; if (op(line, no)) regChange(cm, no, no + 1); - else return null; return line; } @@ -2831,13 +2843,15 @@ window.CodeMirror = (function() { if (dir < 0 && !moveOnce(!first)) break; var cur = lineObj.text.charAt(ch) || "\n"; var type = isWordChar(cur) ? "w" - : !group ? null - : /\s/.test(cur) ? null + : group && cur == "\n" ? "n" + : !group || /\s/.test(cur) ? null : "p"; + if (group && !first && !type) type = "s"; if (sawType && sawType != type) { if (dir < 0) {dir = 1; moveOnce();} break; } + if (type) sawType = type; if (dir > 0 && !moveOnce(!first)) break; } @@ -3048,7 +3062,7 @@ window.CodeMirror = (function() { else if (line > last) { line = last; end = true; } var lineObj = getLine(this.doc, line); return intoCoordSystem(this, getLine(this.doc, line), {top: 0, left: 0}, mode || "page").top + - (end ? lineObj.height : 0); + (end ? this.doc.height - heightAtLine(this, lineObj) : 0); }, defaultTextHeight: function() { return textHeight(this.display); }, @@ -3158,6 +3172,8 @@ window.CodeMirror = (function() { }, triggerOnKeyDown: operation(null, onKeyDown), + triggerOnKeyPress: operation(null, onKeyPress), + triggerOnKeyUp: operation(null, onKeyUp), execCommand: function(cmd) { if (commands.hasOwnProperty(cmd)) @@ -3224,8 +3240,10 @@ window.CodeMirror = (function() { this.display.cursor.className += " CodeMirror-overwrite"; else this.display.cursor.className = this.display.cursor.className.replace(" CodeMirror-overwrite", ""); + + signal(this, "overwriteToggle", this, this.state.overwrite); }, - hasFocus: function() { return this.state.focused; }, + hasFocus: function() { return document.activeElement == this.display.input; }, scrollTo: operation(null, function(x, y) { updateScrollPos(this, x, y); @@ -3266,16 +3284,19 @@ window.CodeMirror = (function() { if (this.options.lineWrapping) this.display.measureLineCache.length = this.display.measureLineCachePos = 0; this.curOp.forceUpdate = true; + signal(this, "refresh", this); }), operation: function(f){return runInOp(this, f);}, refresh: operation(null, function() { - var badHeight = this.display.cachedTextHeight == null; + var oldHeight = this.display.cachedTextHeight; clearCaches(this); updateScrollPos(this, this.doc.scrollLeft, this.doc.scrollTop); regChange(this); - if (badHeight) estimateLineHeights(this); + if (oldHeight == null || Math.abs(oldHeight - textHeight(this.display)) > .5) + estimateLineHeights(this); + signal(this, "refresh", this); }), swapDoc: operation(null, function(doc) { @@ -3426,6 +3447,7 @@ window.CodeMirror = (function() { spec = mimeModes[spec]; } else if (spec && typeof spec.name == "string" && mimeModes.hasOwnProperty(spec.name)) { var found = mimeModes[spec.name]; + if (typeof found == "string") found = {name: found}; spec = createObj(found, spec); spec.name = found.name; } else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+xml$/.test(spec)) { @@ -3538,7 +3560,7 @@ window.CodeMirror = (function() { }, deleteLine: function(cm) { var l = cm.getCursor().line; - cm.replaceRange("", Pos(l, 0), Pos(l), "+delete"); + cm.replaceRange("", Pos(l, 0), Pos(l + 1, 0), "+delete"); }, delLineLeft: function(cm) { var cur = cm.getCursor(); @@ -3596,6 +3618,11 @@ window.CodeMirror = (function() { insertTab: function(cm) { cm.replaceSelection("\t", "end", "+input"); }, + insertSoftTab: function(cm) { + var pos = cm.getCursor("from"), tabSize = cm.options.tabSize; + var col = countColumn(cm.getLine(pos.line), pos.ch, tabSize); + cm.replaceSelection(new Array(tabSize - col % tabSize + 1).join(" "), "end", "+input"); + }, defaultTab: function(cm) { if (cm.somethingSelected()) cm.indentSelection("add"); else cm.replaceSelection("\t", "end", "+input"); @@ -3629,7 +3656,7 @@ window.CodeMirror = (function() { // default. Unknown commands are simply ignored. keyMap.pcDefault = { "Ctrl-A": "selectAll", "Ctrl-D": "deleteLine", "Ctrl-Z": "undo", "Shift-Ctrl-Z": "redo", "Ctrl-Y": "redo", - "Ctrl-Home": "goDocStart", "Alt-Up": "goDocStart", "Ctrl-End": "goDocEnd", "Ctrl-Down": "goDocEnd", + "Ctrl-Home": "goDocStart", "Ctrl-Up": "goDocStart", "Ctrl-End": "goDocEnd", "Ctrl-Down": "goDocEnd", "Ctrl-Left": "goGroupLeft", "Ctrl-Right": "goGroupRight", "Alt-Left": "goLineStart", "Alt-Right": "goLineEnd", "Ctrl-Backspace": "delGroupBefore", "Ctrl-Delete": "delGroupAfter", "Ctrl-S": "save", "Ctrl-F": "find", "Ctrl-G": "findNext", "Shift-Ctrl-G": "findPrev", "Shift-Ctrl-F": "replace", "Shift-Ctrl-R": "replaceAll", @@ -3881,7 +3908,9 @@ window.CodeMirror = (function() { this.doc.cantEdit = false; if (cm) reCheckSelection(cm); } + if (cm) signalLater(cm, "markerCleared", cm, this); if (withOp) endOperation(cm); + if (this.parent) this.parent.clear(); }; TextMarker.prototype.find = function(bothSides) { @@ -3939,7 +3968,7 @@ window.CodeMirror = (function() { if (doc.cm && !doc.cm.curOp) return operation(doc.cm, markText)(doc, from, to, options, type); var marker = new TextMarker(doc, type); - if (options) copyObj(options, marker); + if (options) copyObj(options, marker, false); if (posLess(to, from) || posEq(from, to) && marker.clearWhenEmpty !== false) return marker; if (marker.replacedWith) { @@ -3989,6 +4018,7 @@ window.CodeMirror = (function() { if (marker.className || marker.title || marker.startStyle || marker.endStyle || marker.collapsed) regChange(cm, from.line, to.line + 1); if (marker.atomic) reCheckSelection(cm); + signalLater(cm, "markerAdded", cm, marker); } return marker; } @@ -3998,10 +4028,8 @@ window.CodeMirror = (function() { function SharedTextMarker(markers, primary) { this.markers = markers; this.primary = primary; - for (var i = 0, me = this; i < markers.length; ++i) { + for (var i = 0; i < markers.length; ++i) markers[i].parent = this; - on(markers[i], "clear", function(){me.clear();}); - } } CodeMirror.SharedTextMarker = SharedTextMarker; eventMixin(SharedTextMarker); @@ -4032,6 +4060,37 @@ window.CodeMirror = (function() { return new SharedTextMarker(markers, primary); } + function findSharedMarkers(doc) { + return doc.findMarks(Pos(doc.first, 0), doc.clipPos(Pos(doc.lastLine())), + function(m) { return m.parent; }); + } + + function copySharedMarkers(doc, markers) { + for (var i = 0; i < markers.length; i++) { + var marker = markers[i], pos = marker.find(); + var mFrom = doc.clipPos(pos.from), mTo = doc.clipPos(pos.to); + if (cmp(mFrom, mTo)) { + var subMark = markText(doc, mFrom, mTo, marker.primary, marker.primary.type); + marker.markers.push(subMark); + subMark.parent = marker; + } + } + } + + function detachSharedMarkers(markers) { + for (var i = 0; i < markers.length; i++) { + var marker = markers[i], linked = [marker.primary.doc];; + linkedDocs(marker.primary.doc, function(d) { linked.push(d); }); + for (var j = 0; j < marker.markers.length; j++) { + var subMarker = marker.markers[j]; + if (indexOf(linked, subMarker.doc) == -1) { + subMarker.parent = null; + marker.markers.splice(j--, 1); + } + } + } + } + // TEXTMARKER SPANS function getMarkedSpanFor(spans, marker) { @@ -4314,6 +4373,7 @@ window.CodeMirror = (function() { if (!ws.length) this.line.widgets = null; var aboveVisible = heightAtLine(this.cm, this.line) < this.cm.doc.scrollTop; updateLineHeight(this.line, Math.max(0, this.line.height - widgetHeight(this))); + this.cm.curOp.forceUpdate = true; if (aboveVisible) addToScrollPos(this.cm, 0, -this.height); regChange(this.cm, no, no + 1); }); @@ -4323,6 +4383,7 @@ window.CodeMirror = (function() { var diff = widgetHeight(this) - oldH; if (!diff) return; updateLineHeight(this.line, this.line.height + diff); + this.cm.curOp.forceUpdate = true; var no = lineNo(this.line); regChange(this.cm, no, no + 1); }); @@ -4346,6 +4407,7 @@ window.CodeMirror = (function() { var aboveVisible = heightAtLine(cm, line) < cm.doc.scrollTop; updateLineHeight(line, line.height + widgetHeight(widget)); if (aboveVisible) addToScrollPos(cm, 0, widget.height); + cm.curOp.forceUpdate = true; } return true; }); @@ -4477,7 +4539,7 @@ window.CodeMirror = (function() { function interpretTokenStyle(style, builder) { if (!style) return null; for (;;) { - var lineClass = style.match(/(?:^|\s)line-(background-)?(\S+)/); + var lineClass = style.match(/(?:^|\s+)line-(background-)?(\S+)/); if (!lineClass) break; style = style.slice(0, lineClass.index) + style.slice(lineClass.index + lineClass[0].length); var prop = lineClass[1] ? "bgClass" : "textClass"; @@ -4486,9 +4548,10 @@ window.CodeMirror = (function() { else if (!(new RegExp("(?:^|\s)" + lineClass[2] + "(?:$|\s)")).test(builder[prop])) builder[prop] += " " + lineClass[2]; } + if (/^\s*$/.test(style)) return null; var cache = builder.cm.options.addModeClass ? styleToClassCacheWithMode : styleToClassCache; return cache[style] || - (cache[style] = "cm-" + style.replace(/ +/g, " cm-")); + (cache[style] = style.replace(/\S+/g, "cm-$&")); } function buildLineContent(cm, realLine, measure, copyWidgets) { @@ -4505,7 +4568,7 @@ window.CodeMirror = (function() { builder.measure = line == realLine && measure; builder.pos = 0; builder.addToken = builder.measure ? buildTokenMeasure : buildToken; - if ((old_ie || webkit) && cm.getOption("lineWrapping")) + if ((ie || webkit) && cm.getOption("lineWrapping")) builder.addToken = buildTokenSplitSpaces(builder.addToken); var next = insertLineContent(line, builder, getLineStyles(cm, line)); if (measure && line == realLine && !builder.measuredSomething) { @@ -4998,6 +5061,7 @@ window.CodeMirror = (function() { redo: docOperation(function() {makeChangeFromHistory(this, "redo");}), setExtending: function(val) {this.sel.extend = val;}, + getExtending: function() {return this.sel.extend;}, historySize: function() { var hist = this.history; @@ -5048,6 +5112,23 @@ window.CodeMirror = (function() { } return markers; }, + findMarks: function(from, to, filter) { + from = clipPos(this, from); to = clipPos(this, to); + var found = [], lineNo = from.line; + this.iter(from.line, to.line + 1, function(line) { + var spans = line.markedSpans; + if (spans) for (var i = 0; i < spans.length; i++) { + var span = spans[i]; + if (!(lineNo == from.line && from.ch > span.to || + span.from == null && lineNo != from.line|| + lineNo == to.line && span.from > to.ch) && + (!filter || filter(span.marker))) + found.push(span.marker.parent || span.marker); + } + ++lineNo; + }); + return found; + }, getAllMarks: function() { var markers = []; this.iter(function(line) { @@ -5099,6 +5180,7 @@ window.CodeMirror = (function() { if (options.sharedHist) copy.history = this.history; (this.linked || (this.linked = [])).push({doc: copy, sharedHist: options.sharedHist}); copy.linked = [{doc: this, isParent: true, sharedHist: options.sharedHist}]; + copySharedMarkers(copy, findSharedMarkers(this)); return copy; }, unlinkDoc: function(other) { @@ -5108,6 +5190,7 @@ window.CodeMirror = (function() { if (link.doc != other) continue; this.linked.splice(i, 1); other.unlinkDoc(this); + detachSharedMarkers(findSharedMarkers(this)); break; } // If the histories were shared, split them again @@ -5321,6 +5404,8 @@ window.CodeMirror = (function() { hist.lastTime = time; hist.lastOp = opId; hist.lastOrigin = change.origin; + + if (!last) signal(doc, "historyAdded"); } function removeClearedSpans(spans) { @@ -5586,9 +5671,11 @@ window.CodeMirror = (function() { return inst; } - function copyObj(obj, target) { + function copyObj(obj, target, overwrite) { if (!target) target = {}; - for (var prop in obj) if (obj.hasOwnProperty(prop)) target[prop] = obj[prop]; + for (var prop in obj) + if (obj.hasOwnProperty(prop) && (overwrite !== false || !target.hasOwnProperty(prop))) + target[prop] = obj[prop]; return target; } @@ -5602,7 +5689,7 @@ window.CodeMirror = (function() { return function(){return f.apply(null, args);}; } - var nonASCIISingleCaseWordChar = /[\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/; + var nonASCIISingleCaseWordChar = /[\u00df\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/; function isWordChar(ch) { return /\w/.test(ch) || ch > "\x80" && (ch.toUpperCase() != ch.toLowerCase() || nonASCIISingleCaseWordChar.test(ch)); @@ -6043,7 +6130,7 @@ window.CodeMirror = (function() { // THE END - CodeMirror.version = "3.21.0"; + CodeMirror.version = "3.24.0"; return CodeMirror; })(); diff --git a/fhem/www/codemirror/css.js b/fhem/www/codemirror/css.js index 6cc4b71b0..28b0f3356 100644 --- a/fhem/www/codemirror/css.js +++ b/fhem/www/codemirror/css.js @@ -8,6 +8,7 @@ CodeMirror.defineMode("css", function(config, parserConfig) { mediaTypes = parserConfig.mediaTypes || {}, mediaFeatures = parserConfig.mediaFeatures || {}, propertyKeywords = parserConfig.propertyKeywords || {}, + nonStandardPropertyKeywords = parserConfig.nonStandardPropertyKeywords || {}, colorKeywords = parserConfig.colorKeywords || {}, valueKeywords = parserConfig.valueKeywords || {}, fontProperties = parserConfig.fontProperties || {}, @@ -83,7 +84,7 @@ CodeMirror.defineMode("css", function(config, parserConfig) { function tokenParenthesized(stream, state) { stream.next(); // Must be '(' - if (!stream.match(/\s*[\"\']/, false)) + if (!stream.match(/\s*[\"\')]/, false)) state.tokenize = tokenString(")"); else state.tokenize = null; @@ -162,9 +163,13 @@ CodeMirror.defineMode("css", function(config, parserConfig) { states.block = function(type, stream, state) { if (type == "word") { - if (propertyKeywords.hasOwnProperty(stream.current().toLowerCase())) { + var word = stream.current().toLowerCase(); + if (propertyKeywords.hasOwnProperty(word)) { override = "property"; return "maybeprop"; + } else if (nonStandardPropertyKeywords.hasOwnProperty(word)) { + override = "string-2"; + return "maybeprop"; } else if (allowNested) { override = stream.match(/^\s*:/, false) ? "property" : "tag"; return "block"; @@ -437,19 +442,27 @@ CodeMirror.defineMode("css", function(config, parserConfig) { "vertical-align", "visibility", "voice-balance", "voice-duration", "voice-family", "voice-pitch", "voice-range", "voice-rate", "voice-stress", "voice-volume", "volume", "white-space", "widows", "width", "word-break", - "word-spacing", "word-wrap", "z-index", "zoom", + "word-spacing", "word-wrap", "z-index", // SVG-specific "clip-path", "clip-rule", "mask", "enable-background", "filter", "flood-color", "flood-opacity", "lighting-color", "stop-color", "stop-opacity", "pointer-events", - "color-interpolation", "color-interpolation-filters", "color-profile", + "color-interpolation", "color-interpolation-filters", "color-rendering", "fill", "fill-opacity", "fill-rule", "image-rendering", "marker", "marker-end", "marker-mid", "marker-start", "shape-rendering", "stroke", "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", "stroke-width", "text-rendering", "baseline-shift", "dominant-baseline", "glyph-orientation-horizontal", - "glyph-orientation-vertical", "kerning", "text-anchor", "writing-mode" + "glyph-orientation-vertical", "text-anchor", "writing-mode" ], propertyKeywords = keySet(propertyKeywords_); + var nonStandardPropertyKeywords = [ + "scrollbar-arrow-color", "scrollbar-base-color", "scrollbar-dark-shadow-color", + "scrollbar-face-color", "scrollbar-highlight-color", "scrollbar-shadow-color", + "scrollbar-3d-light-color", "scrollbar-track-color", "shape-inside", + "searchfield-cancel-button", "searchfield-decoration", "searchfield-results-button", + "searchfield-results-decoration", "zoom" + ], nonStandardPropertyKeywords = keySet(nonStandardPropertyKeywords); + var colorKeywords_ = [ "aliceblue", "antiquewhite", "aqua", "aquamarine", "azure", "beige", "bisque", "black", "blanchedalmond", "blue", "blueviolet", "brown", @@ -569,7 +582,8 @@ CodeMirror.defineMode("css", function(config, parserConfig) { "font-stretch", "font-weight", "font-style" ], fontProperties = keySet(fontProperties_); - var allWords = mediaTypes_.concat(mediaFeatures_).concat(propertyKeywords_).concat(colorKeywords_).concat(valueKeywords_); + var allWords = mediaTypes_.concat(mediaFeatures_).concat(propertyKeywords_) + .concat(nonStandardPropertyKeywords).concat(colorKeywords_).concat(valueKeywords_); CodeMirror.registerHelper("hintWords", "css", allWords); function tokenCComment(stream, state) { @@ -598,6 +612,7 @@ CodeMirror.defineMode("css", function(config, parserConfig) { mediaTypes: mediaTypes, mediaFeatures: mediaFeatures, propertyKeywords: propertyKeywords, + nonStandardPropertyKeywords: nonStandardPropertyKeywords, colorKeywords: colorKeywords, valueKeywords: valueKeywords, fontProperties: fontProperties, @@ -620,6 +635,7 @@ CodeMirror.defineMode("css", function(config, parserConfig) { mediaTypes: mediaTypes, mediaFeatures: mediaFeatures, propertyKeywords: propertyKeywords, + nonStandardPropertyKeywords: nonStandardPropertyKeywords, colorKeywords: colorKeywords, valueKeywords: valueKeywords, fontProperties: fontProperties, @@ -660,6 +676,7 @@ CodeMirror.defineMode("css", function(config, parserConfig) { mediaTypes: mediaTypes, mediaFeatures: mediaFeatures, propertyKeywords: propertyKeywords, + nonStandardPropertyKeywords: nonStandardPropertyKeywords, colorKeywords: colorKeywords, valueKeywords: valueKeywords, fontProperties: fontProperties, diff --git a/fhem/www/codemirror/show-hint.js b/fhem/www/codemirror/show-hint.js index 7e03d1139..c9f2dd1ef 100644 --- a/fhem/www/codemirror/show-hint.js +++ b/fhem/www/codemirror/show-hint.js @@ -46,7 +46,7 @@ pick: function(data, i) { var completion = data.list[i]; if (completion.hint) completion.hint(this.cm, data, completion); - else this.cm.replaceRange(getText(completion), data.from, data.to); + else this.cm.replaceRange(getText(completion), completion.from||data.from, completion.to||data.to); CodeMirror.signal(data, "pick", completion); this.close(); }, @@ -93,6 +93,7 @@ data = data_; if (finished) return; if (!data || !data.list.length) return done(); + if (completion.widget) completion.widget.close(); completion.widget = new Widget(completion, data); } @@ -193,8 +194,24 @@ var winW = window.innerWidth || Math.max(document.body.offsetWidth, document.documentElement.offsetWidth); var winH = window.innerHeight || Math.max(document.body.offsetHeight, document.documentElement.offsetHeight); (options.container || document.body).appendChild(hints); - var box = hints.getBoundingClientRect(); - var overlapX = box.right - winW, overlapY = box.bottom - winH; + var box = hints.getBoundingClientRect(), overlapY = box.bottom - winH; + if (overlapY > 0) { + var height = box.bottom - box.top, curTop = box.top - (pos.bottom - pos.top); + if (curTop - height > 0) { // Fits above cursor + hints.style.top = (top = curTop - height) + "px"; + below = false; + } else if (height > winH) { + hints.style.height = (winH - 5) + "px"; + hints.style.top = (top = pos.bottom - box.top) + "px"; + var cursor = cm.getCursor(); + if (data.from.ch != cursor.ch) { + pos = cm.cursorCoords(cursor); + hints.style.left = (left = pos.left) + "px"; + box = hints.getBoundingClientRect(); + } + } + } + var overlapX = box.left - winW; if (overlapX > 0) { if (box.right - box.left > winW) { hints.style.width = (winW - 5) + "px"; @@ -202,17 +219,6 @@ } hints.style.left = (left = pos.left - overlapX) + "px"; } - if (overlapY > 0) { - var height = box.bottom - box.top; - if (box.top - (pos.bottom - pos.top) - height > 0) { - overlapY = height + (pos.bottom - pos.top); - below = false; - } else if (height > winH) { - hints.style.height = (winH - 5) + "px"; - overlapY -= height - winH; - } - hints.style.top = (top = pos.bottom - overlapY) + "px"; - } cm.addKeyMap(this.keyMap = buildKeyMap(options, { moveFocus: function(n, avoidWrap) { widget.changeActive(widget.selectedHint + n, avoidWrap); }, @@ -220,7 +226,8 @@ menuSize: function() { return widget.screenAmount(); }, length: completions.length, close: function() { completion.close(); }, - pick: function() { widget.pick(); } + pick: function() { widget.pick(); }, + data: data })); if (options.closeOnUnfocus !== false) { @@ -303,15 +310,16 @@ }; CodeMirror.registerHelper("hint", "auto", function(cm, options) { - var helpers = cm.getHelpers(cm.getCursor(), "hint"); + var helpers = cm.getHelpers(cm.getCursor(), "hint"), words; if (helpers.length) { for (var i = 0; i < helpers.length; i++) { var cur = helpers[i](cm, options); if (cur && cur.list.length) return cur; } - } else { - var words = cm.getHelper(cm.getCursor(), "hintWords"); + } else if (words = cm.getHelper(cm.getCursor(), "hintWords")) { if (words) return CodeMirror.hint.fromList(cm, {words: words}); + } else if (CodeMirror.hint.anyword) { + return CodeMirror.hint.anyword(cm, options); } }); diff --git a/fhem/www/codemirror/xml.js b/fhem/www/codemirror/xml.js index 96b51ff97..920406334 100644 --- a/fhem/www/codemirror/xml.js +++ b/fhem/www/codemirror/xml.js @@ -1,7 +1,8 @@ CodeMirror.defineMode("xml", function(config, parserConfig) { var indentUnit = config.indentUnit; var multilineTagIndentFactor = parserConfig.multilineTagIndentFactor || 1; - var multilineTagIndentPastTag = parserConfig.multilineTagIndentPastTag || true; + var multilineTagIndentPastTag = parserConfig.multilineTagIndentPastTag; + if (multilineTagIndentPastTag == null) multilineTagIndentPastTag = true; var Kludges = parserConfig.htmlMode ? { autoSelfClosers: {'area': true, 'base': true, 'br': true, 'col': true, 'command': true, @@ -33,19 +34,21 @@ CodeMirror.defineMode("xml", function(config, parserConfig) { }, doNotIndent: {"pre": true}, allowUnquoted: true, - allowMissing: true + allowMissing: true, + caseFold: true } : { autoSelfClosers: {}, implicitlyClosed: {}, contextGrabbers: {}, doNotIndent: {}, allowUnquoted: false, - allowMissing: false + allowMissing: false, + caseFold: false }; var alignCDATA = parserConfig.alignCDATA; // Return variables for tokenizers - var tagName, type, setStyle; + var type, setStyle; function inText(stream, state) { function chain(parser) { @@ -72,14 +75,9 @@ CodeMirror.defineMode("xml", function(config, parserConfig) { state.tokenize = inBlock("meta", "?>"); return "meta"; } else { - var isClose = stream.eat("/"); - tagName = ""; - var c; - while ((c = stream.eat(/[^\s\u00a0=<>\"\'\/?]/))) tagName += c; - if (!tagName) return "tag error"; - type = isClose ? "closeTag" : "openTag"; + type = stream.eat("/") ? "closeTag" : "openTag"; state.tokenize = inTag; - return "tag"; + return "tag bracket"; } } else if (ch == "&") { var ok; @@ -104,7 +102,7 @@ CodeMirror.defineMode("xml", function(config, parserConfig) { if (ch == ">" || (ch == "/" && stream.eat(">"))) { state.tokenize = inText; type = ch == ">" ? "endTag" : "selfcloseTag"; - return "tag"; + return "tag bracket"; } else if (ch == "=") { type = "equals"; return null; @@ -119,7 +117,7 @@ CodeMirror.defineMode("xml", function(config, parserConfig) { state.stringStartCol = stream.column(); return state.tokenize(stream, state); } else { - stream.eatWhile(/[^\s\u00a0=<>\"\']/); + stream.match(/^[^\s\u00a0=<>\"\']*[^\s\u00a0=<>\"\'\/]/); return "word"; } } @@ -188,7 +186,7 @@ CodeMirror.defineMode("xml", function(config, parserConfig) { if (!state.context) { return; } - parentTagName = state.context.tagName.toLowerCase(); + parentTagName = state.context.tagName; if (!Kludges.contextGrabbers.hasOwnProperty(parentTagName) || !Kludges.contextGrabbers[parentTagName].hasOwnProperty(nextTagName)) { return; @@ -199,26 +197,42 @@ CodeMirror.defineMode("xml", function(config, parserConfig) { function baseState(type, stream, state) { if (type == "openTag") { - state.tagName = tagName; state.tagStart = stream.column(); - return attrState; + return tagNameState; } else if (type == "closeTag") { - var err = false; - if (state.context) { - if (state.context.tagName != tagName) { - if (Kludges.implicitlyClosed.hasOwnProperty(state.context.tagName.toLowerCase())) - popContext(state); - err = !state.context || state.context.tagName != tagName; - } - } else { - err = true; - } - if (err) setStyle = "error"; - return err ? closeStateErr : closeState; + return closeTagNameState; } else { return baseState; } } + function tagNameState(type, stream, state) { + if (type == "word") { + state.tagName = stream.current(); + setStyle = "tag"; + return attrState; + } else { + setStyle = "error"; + return tagNameState; + } + } + function closeTagNameState(type, stream, state) { + if (type == "word") { + var tagName = stream.current(); + if (state.context && state.context.tagName != tagName && + Kludges.implicitlyClosed.hasOwnProperty(state.context.tagName)) + popContext(state); + if (state.context && state.context.tagName == tagName) { + setStyle = "tag"; + return closeState; + } else { + setStyle = "tag error"; + return closeStateErr; + } + } else { + setStyle = "error"; + return closeStateErr; + } + } function closeState(type, _stream, state) { if (type != "endTag") { setStyle = "error"; @@ -240,10 +254,10 @@ CodeMirror.defineMode("xml", function(config, parserConfig) { var tagName = state.tagName, tagStart = state.tagStart; state.tagName = state.tagStart = null; if (type == "selfcloseTag" || - Kludges.autoSelfClosers.hasOwnProperty(tagName.toLowerCase())) { - maybePopContext(state, tagName.toLowerCase()); + Kludges.autoSelfClosers.hasOwnProperty(tagName)) { + maybePopContext(state, tagName); } else { - maybePopContext(state, tagName.toLowerCase()); + maybePopContext(state, tagName); state.context = new Context(state, tagName, tagStart == state.indented); } return baseState; @@ -281,7 +295,7 @@ CodeMirror.defineMode("xml", function(config, parserConfig) { state.indented = stream.indentation(); if (stream.eatSpace()) return null; - tagName = type = null; + type = null; var style = state.tokenize(stream, state); if ((style || type) && style != "comment") { setStyle = null; @@ -296,7 +310,10 @@ CodeMirror.defineMode("xml", function(config, parserConfig) { var context = state.context; // Indent multi-line strings (e.g. css). if (state.tokenize.isInAttribute) { - return state.stringStartCol + 1; + if (state.tagStart == state.indented) + return state.stringStartCol + 1; + else + return state.indented + indentUnit; } if (context && context.noIndent) return CodeMirror.Pass; if (state.tokenize != inTag && state.tokenize != inText) @@ -309,8 +326,27 @@ CodeMirror.defineMode("xml", function(config, parserConfig) { return state.tagStart + indentUnit * multilineTagIndentFactor; } if (alignCDATA && /