Skip to content

Instantly share code, notes, and snippets.

@virtadpt
Created March 13, 2013 23:34
Show Gist options
  • Save virtadpt/5157510 to your computer and use it in GitHub Desktop.
Save virtadpt/5157510 to your computer and use it in GitHub Desktop.
This is a copy of the CodeMirror Unhosted text editor (https://unhosted.org/adventures/2/An-unhosted-editor.html), which I've set aside for an article about unhosted web applications. I've copied it into a Gist so that people who are curious can poke around in the code. Please note that the code is serialized into a single line (a URL, actually)…
data:text/html;charset=utf-8,<!DOCTYPE html lang%3D"en">%0A<html>%0A <head>%0A <meta charset%3D"utf-8">%0A <title>codemirror<%2Ftitle>%0A %0A %0A %0A <!-- http%3A%2F%2Fcodemirror.net%2Flib%2Fcodemirror.js --><script>%0A%2F%2F CodeMirror version 2.34%0A%0A%2F%2F All functions that need access to the editor's state live inside%0A%2F%2F the CodeMirror function. Below that%2C at the bottom of the file%2C%0A%2F%2F some utilities are defined.%0A%0A%2F%2F CodeMirror is the only global var we claim%0Awindow.CodeMirror %3D (function() {%0A "use strict"%3B%0A %2F%2F This is the function that produces an editor instance. Its%0A %2F%2F closure is used to store the editor state.%0A function CodeMirror(place%2C givenOptions) {%0A %2F%2F Determine effective options based on given values and defaults.%0A var options %3D {}%2C defaults %3D CodeMirror.defaults%3B%0A for (var opt in defaults)%0A if (defaults.hasOwnProperty(opt))%0A options[opt] %3D (givenOptions %26%26 givenOptions.hasOwnProperty(opt) %3F givenOptions %3A defaults)[opt]%3B%0A%0A var input %3D elt("textarea"%2C null%2C null%2C "position%3A absolute%3B padding%3A 0%3B width%3A 1px%3B height%3A 1em")%3B%0A input.setAttribute("wrap"%2C "off")%3B input.setAttribute("autocorrect"%2C "off")%3B input.setAttribute("autocapitalize"%2C "off")%3B%0A %2F%2F Wraps and hides input textarea%0A var inputDiv %3D elt("div"%2C [input]%2C null%2C "overflow%3A hidden%3B position%3A relative%3B width%3A 3px%3B height%3A 0px%3B")%3B%0A %2F%2F The empty scrollbar content%2C used solely for managing the scrollbar thumb.%0A var scrollbarInner %3D elt("div"%2C null%2C "CodeMirror-scrollbar-inner")%3B%0A %2F%2F The vertical scrollbar. Horizontal scrolling is handled by the scroller itself.%0A var scrollbar %3D elt("div"%2C [scrollbarInner]%2C "CodeMirror-scrollbar")%3B%0A %2F%2F DIVs containing the selection and the actual code%0A var lineDiv %3D elt("div")%2C selectionDiv %3D elt("div"%2C null%2C null%2C "position%3A relative%3B z-index%3A -1")%3B%0A %2F%2F Blinky cursor%2C and element used to ensure cursor fits at the end of a line%0A var cursor %3D elt("pre"%2C "\u00a0"%2C "CodeMirror-cursor")%2C widthForcer %3D elt("pre"%2C "\u00a0"%2C "CodeMirror-cursor"%2C "visibility%3A hidden")%3B%0A %2F%2F Used to measure text size%0A var measure %3D elt("div"%2C null%2C null%2C "position%3A absolute%3B width%3A 100%25%3B height%3A 0px%3B overflow%3A hidden%3B visibility%3A hidden%3B")%3B%0A var lineSpace %3D elt("div"%2C [measure%2C cursor%2C widthForcer%2C selectionDiv%2C lineDiv]%2C null%2C "position%3A relative%3B z-index%3A 0")%3B%0A var gutterText %3D elt("div"%2C null%2C "CodeMirror-gutter-text")%2C gutter %3D elt("div"%2C [gutterText]%2C "CodeMirror-gutter")%3B%0A %2F%2F Moved around its parent to cover visible view%0A var mover %3D elt("div"%2C [gutter%2C elt("div"%2C [lineSpace]%2C "CodeMirror-lines")]%2C null%2C "position%3A relative")%3B%0A %2F%2F Set to the height of the text%2C causes scrolling%0A var sizer %3D elt("div"%2C [mover]%2C null%2C "position%3A relative")%3B%0A %2F%2F Provides scrolling%0A var scroller %3D elt("div"%2C [sizer]%2C "CodeMirror-scroll")%3B%0A scroller.setAttribute("tabIndex"%2C "-1")%3B%0A %2F%2F The element in which the editor lives.%0A var wrapper %3D elt("div"%2C [inputDiv%2C scrollbar%2C scroller]%2C "CodeMirror" %2B (options.lineWrapping %3F " CodeMirror-wrap" %3A ""))%3B%0A if (place.appendChild) place.appendChild(wrapper)%3B else place(wrapper)%3B%0A%0A themeChanged()%3B keyMapChanged()%3B%0A %2F%2F Needed to hide big blue blinking cursor on Mobile Safari%0A if (ios) input.style.width %3D "0px"%3B%0A if (!webkit) scroller.draggable %3D true%3B%0A lineSpace.style.outline %3D "none"%3B%0A if (options.tabindex !%3D null) input.tabIndex %3D options.tabindex%3B%0A if (options.autofocus) focusInput()%3B%0A if (!options.gutter %26%26 !options.lineNumbers) gutter.style.display %3D "none"%3B%0A %2F%2F Needed to handle Tab key in KHTML%0A if (khtml) inputDiv.style.height %3D "1px"%2C inputDiv.style.position %3D "absolute"%3B%0A%0A %2F%2F Check for OS X >%3D 10.7. This has transparent scrollbars%2C so the%0A %2F%2F overlaying of one scrollbar with another won't work. This is a%0A %2F%2F temporary hack to simply turn off the overlay scrollbar. See%0A %2F%2F issue %23727.%0A if (mac_geLion) { scrollbar.style.zIndex %3D -2%3B scrollbar.style.visibility %3D "hidden"%3B }%0A %2F%2F Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8).%0A else if (ie_lt8) scrollbar.style.minWidth %3D "18px"%3B%0A%0A %2F%2F Delayed object wrap timeouts%2C making sure only one is active. blinker holds an interval.%0A var poll %3D new Delayed()%2C highlight %3D new Delayed()%2C blinker%3B%0A%0A %2F%2F mode holds a mode API object. doc is the tree of Line objects%2C%0A %2F%2F frontier is the point up to which the content has been parsed%2C%0A %2F%2F and history the undo history (instance of History constructor).%0A var mode%2C doc %3D new BranchChunk([new LeafChunk([new Line("")])])%2C frontier %3D 0%2C focused%3B%0A loadMode()%3B%0A %2F%2F The selection. These are always maintained to point at valid%0A %2F%2F positions. Inverted is used to remember that the user is%0A %2F%2F selecting bottom-to-top.%0A var sel %3D {from%3A {line%3A 0%2C ch%3A 0}%2C to%3A {line%3A 0%2C ch%3A 0}%2C inverted%3A false}%3B%0A %2F%2F Selection-related flags. shiftSelecting obviously tracks%0A %2F%2F whether the user is holding shift.%0A var shiftSelecting%2C lastClick%2C lastDoubleClick%2C lastScrollTop %3D 0%2C draggingText%2C%0A overwrite %3D false%2C suppressEdits %3D false%3B%0A %2F%2F Variables used by startOperation%2FendOperation to track what%0A %2F%2F happened during the operation.%0A var updateInput%2C userSelChange%2C changes%2C textChanged%2C selectionChanged%2C%0A gutterDirty%2C callbacks%3B%0A %2F%2F Current visible range (may be bigger than the view window).%0A var displayOffset %3D 0%2C showingFrom %3D 0%2C showingTo %3D 0%2C lastSizeC %3D 0%3B%0A %2F%2F bracketHighlighted is used to remember that a bracket has been%0A %2F%2F marked.%0A var bracketHighlighted%3B%0A %2F%2F Tracks the maximum line length so that the horizontal scrollbar%0A %2F%2F can be kept static when scrolling.%0A var maxLine %3D getLine(0)%2C updateMaxLine %3D false%2C maxLineChanged %3D true%3B%0A var pollingFast %3D false%3B %2F%2F Ensures slowPoll doesn't cancel fastPoll%0A var goalColumn %3D null%3B%0A%0A %2F%2F Initialize the content.%0A operation(function(){setValue(options.value || "")%3B updateInput %3D false%3B})()%3B%0A var history %3D new History()%3B%0A%0A %2F%2F Register our event handlers.%0A connect(scroller%2C "mousedown"%2C operation(onMouseDown))%3B%0A connect(scroller%2C "dblclick"%2C operation(onDoubleClick))%3B%0A connect(lineSpace%2C "selectstart"%2C e_preventDefault)%3B%0A %2F%2F Gecko browsers fire contextmenu *after* opening the menu%2C at%0A %2F%2F which point we can't mess with it anymore. Context menu is%0A %2F%2F handled in onMouseDown for Gecko.%0A if (!gecko) connect(scroller%2C "contextmenu"%2C onContextMenu)%3B%0A connect(scroller%2C "scroll"%2C onScrollMain)%3B%0A connect(scrollbar%2C "scroll"%2C onScrollBar)%3B%0A connect(scrollbar%2C "mousedown"%2C function() {if (focused) setTimeout(focusInput%2C 0)%3B})%3B%0A var resizeHandler %3D connect(window%2C "resize"%2C function() {%0A if (wrapper.parentNode) updateDisplay(true)%3B%0A else resizeHandler()%3B%0A }%2C true)%3B%0A connect(input%2C "keyup"%2C operation(onKeyUp))%3B%0A connect(input%2C "input"%2C fastPoll)%3B%0A connect(input%2C "keydown"%2C operation(onKeyDown))%3B%0A connect(input%2C "keypress"%2C operation(onKeyPress))%3B%0A connect(input%2C "focus"%2C onFocus)%3B%0A connect(input%2C "blur"%2C onBlur)%3B%0A%0A function drag_(e) {%0A if (options.onDragEvent %26%26 options.onDragEvent(instance%2C addStop(e))) return%3B%0A e_stop(e)%3B%0A }%0A if (options.dragDrop) {%0A connect(scroller%2C "dragstart"%2C onDragStart)%3B%0A connect(scroller%2C "dragenter"%2C drag_)%3B%0A connect(scroller%2C "dragover"%2C drag_)%3B%0A connect(scroller%2C "drop"%2C operation(onDrop))%3B%0A }%0A connect(scroller%2C "paste"%2C function(){focusInput()%3B fastPoll()%3B})%3B%0A connect(input%2C "paste"%2C fastPoll)%3B%0A connect(input%2C "cut"%2C operation(function(){%0A if (!options.readOnly) replaceSelection("")%3B%0A }))%3B%0A%0A %2F%2F Needed to handle Tab key in KHTML%0A if (khtml) connect(sizer%2C "mouseup"%2C function() {%0A if (document.activeElement %3D%3D input) input.blur()%3B%0A focusInput()%3B%0A })%3B%0A%0A %2F%2F IE throws unspecified error in certain cases%2C when%0A %2F%2F trying to access activeElement before onload%0A var hasFocus%3B try { hasFocus %3D (document.activeElement %3D%3D input)%3B } catch(e) { }%0A if (hasFocus || options.autofocus) setTimeout(onFocus%2C 20)%3B%0A else onBlur()%3B%0A%0A function isLine(l) {return l >%3D 0 %26%26 l < doc.size%3B}%0A %2F%2F The instance object that we'll return. Mostly calls out to%0A %2F%2F local functions in the CodeMirror function. Some do some extra%0A %2F%2F range checking and%2For clipping. operation is used to wrap the%0A %2F%2F call so that changes it makes are tracked%2C and the display is%0A %2F%2F updated afterwards.%0A var instance %3D wrapper.CodeMirror %3D {%0A getValue%3A getValue%2C%0A setValue%3A operation(setValue)%2C%0A getSelection%3A getSelection%2C%0A replaceSelection%3A operation(replaceSelection)%2C%0A focus%3A function(){window.focus()%3B focusInput()%3B onFocus()%3B fastPoll()%3B}%2C%0A setOption%3A function(option%2C value) {%0A var oldVal %3D options[option]%3B%0A options[option] %3D value%3B%0A if (option %3D%3D "mode" || option %3D%3D "indentUnit") loadMode()%3B%0A else if (option %3D%3D "readOnly" %26%26 value %3D%3D "nocursor") {onBlur()%3B input.blur()%3B}%0A else if (option %3D%3D "readOnly" %26%26 !value) {resetInput(true)%3B}%0A else if (option %3D%3D "theme") themeChanged()%3B%0A else if (option %3D%3D "lineWrapping" %26%26 oldVal !%3D value) operation(wrappingChanged)()%3B%0A else if (option %3D%3D "tabSize") updateDisplay(true)%3B%0A else if (option %3D%3D "keyMap") keyMapChanged()%3B%0A if (option %3D%3D "lineNumbers" || option %3D%3D "gutter" || option %3D%3D "firstLineNumber" ||%0A option %3D%3D "theme" || option %3D%3D "lineNumberFormatter") {%0A gutterChanged()%3B%0A updateDisplay(true)%3B%0A }%0A }%2C%0A getOption%3A function(option) {return options[option]%3B}%2C%0A getMode%3A function() {return mode%3B}%2C%0A undo%3A operation(undo)%2C%0A redo%3A operation(redo)%2C%0A indentLine%3A operation(function(n%2C dir) {%0A if (typeof dir !%3D "string") {%0A if (dir %3D%3D null) dir %3D options.smartIndent %3F "smart" %3A "prev"%3B%0A else dir %3D dir %3F "add" %3A "subtract"%3B%0A }%0A if (isLine(n)) indentLine(n%2C dir)%3B%0A })%2C%0A indentSelection%3A operation(indentSelected)%2C%0A historySize%3A function() {return {undo%3A history.done.length%2C redo%3A history.undone.length}%3B}%2C%0A clearHistory%3A function() {history %3D new History()%3B}%2C%0A setHistory%3A function(histData) {%0A history %3D new History()%3B%0A history.done %3D histData.done%3B%0A history.undone %3D histData.undone%3B%0A }%2C%0A getHistory%3A function() {%0A function cp(arr) {%0A for (var i %3D 0%2C nw %3D []%2C nwelt%3B i < arr.length%3B %2B%2Bi) {%0A nw.push(nwelt %3D [])%3B%0A for (var j %3D 0%2C elt %3D arr[i]%3B j < elt.length%3B %2B%2Bj) {%0A var old %3D []%2C cur %3D elt[j]%3B%0A nwelt.push({start%3A cur.start%2C added%3A cur.added%2C old%3A old})%3B%0A for (var k %3D 0%3B k < cur.old.length%3B %2B%2Bk) old.push(hlText(cur.old[k]))%3B%0A }%0A }%0A return nw%3B%0A }%0A return {done%3A cp(history.done)%2C undone%3A cp(history.undone)}%3B%0A }%2C%0A matchBrackets%3A operation(function(){matchBrackets(true)%3B})%2C%0A getTokenAt%3A operation(function(pos) {%0A pos %3D clipPos(pos)%3B%0A return getLine(pos.line).getTokenAt(mode%2C getStateBefore(pos.line)%2C options.tabSize%2C pos.ch)%3B%0A })%2C%0A getStateAfter%3A function(line) {%0A line %3D clipLine(line %3D%3D null %3F doc.size - 1%3A line)%3B%0A return getStateBefore(line %2B 1)%3B%0A }%2C%0A cursorCoords%3A function(start%2C mode) {%0A if (start %3D%3D null) start %3D sel.inverted%3B%0A return this.charCoords(start %3F sel.from %3A sel.to%2C mode)%3B%0A }%2C%0A charCoords%3A function(pos%2C mode) {%0A pos %3D clipPos(pos)%3B%0A if (mode %3D%3D "local") return localCoords(pos%2C false)%3B%0A if (mode %3D%3D "div") return localCoords(pos%2C true)%3B%0A return pageCoords(pos)%3B%0A }%2C%0A coordsChar%3A function(coords) {%0A var off %3D eltOffset(lineSpace)%3B%0A return coordsChar(coords.x - off.left%2C coords.y - off.top)%3B%0A }%2C%0A markText%3A operation(markText)%2C%0A setBookmark%3A setBookmark%2C%0A findMarksAt%3A findMarksAt%2C%0A setMarker%3A operation(addGutterMarker)%2C%0A clearMarker%3A operation(removeGutterMarker)%2C%0A setLineClass%3A operation(setLineClass)%2C%0A hideLine%3A operation(function(h) {return setLineHidden(h%2C true)%3B})%2C%0A showLine%3A operation(function(h) {return setLineHidden(h%2C false)%3B})%2C%0A onDeleteLine%3A function(line%2C f) {%0A if (typeof line %3D%3D "number") {%0A if (!isLine(line)) return null%3B%0A line %3D getLine(line)%3B%0A }%0A (line.handlers || (line.handlers %3D [])).push(f)%3B%0A return line%3B%0A }%2C%0A lineInfo%3A lineInfo%2C%0A getViewport%3A function() { return {from%3A showingFrom%2C to%3A showingTo}%3B}%2C%0A addWidget%3A function(pos%2C node%2C scroll%2C vert%2C horiz) {%0A pos %3D localCoords(clipPos(pos))%3B%0A var top %3D pos.yBot%2C left %3D pos.x%3B%0A node.style.position %3D "absolute"%3B%0A sizer.appendChild(node)%3B%0A if (vert %3D%3D "over") top %3D pos.y%3B%0A else if (vert %3D%3D "near") {%0A var vspace %3D Math.max(scroller.offsetHeight%2C doc.height * textHeight())%2C%0A hspace %3D Math.max(sizer.clientWidth%2C lineSpace.clientWidth) - paddingLeft()%3B%0A if (pos.yBot %2B node.offsetHeight > vspace %26%26 pos.y > node.offsetHeight)%0A top %3D pos.y - node.offsetHeight%3B%0A if (left %2B node.offsetWidth > hspace)%0A left %3D hspace - node.offsetWidth%3B%0A }%0A node.style.top %3D (top %2B paddingTop()) %2B "px"%3B%0A node.style.left %3D node.style.right %3D ""%3B%0A if (horiz %3D%3D "right") {%0A left %3D sizer.clientWidth - node.offsetWidth%3B%0A node.style.right %3D "0px"%3B%0A } else {%0A if (horiz %3D%3D "left") left %3D 0%3B%0A else if (horiz %3D%3D "middle") left %3D (sizer.clientWidth - node.offsetWidth) %2F 2%3B%0A node.style.left %3D (left %2B paddingLeft()) %2B "px"%3B%0A }%0A if (scroll)%0A scrollIntoView(left%2C top%2C left %2B node.offsetWidth%2C top %2B node.offsetHeight)%3B%0A }%2C%0A%0A lineCount%3A function() {return doc.size%3B}%2C%0A clipPos%3A clipPos%2C%0A getCursor%3A function(start) {%0A if (start %3D%3D null) start %3D sel.inverted%3B%0A return copyPos(start %3F sel.from %3A sel.to)%3B%0A }%2C%0A somethingSelected%3A function() {return !posEq(sel.from%2C sel.to)%3B}%2C%0A setCursor%3A operation(function(line%2C ch%2C user) {%0A if (ch %3D%3D null %26%26 typeof line.line %3D%3D "number") setCursor(line.line%2C line.ch%2C user)%3B%0A else setCursor(line%2C ch%2C user)%3B%0A })%2C%0A setSelection%3A operation(function(from%2C to%2C user) {%0A (user %3F setSelectionUser %3A setSelection)(clipPos(from)%2C clipPos(to || from))%3B%0A })%2C%0A getLine%3A function(line) {if (isLine(line)) return getLine(line).text%3B}%2C%0A getLineHandle%3A function(line) {if (isLine(line)) return getLine(line)%3B}%2C%0A setLine%3A operation(function(line%2C text) {%0A if (isLine(line)) replaceRange(text%2C {line%3A line%2C ch%3A 0}%2C {line%3A line%2C ch%3A getLine(line).text.length})%3B%0A })%2C%0A removeLine%3A operation(function(line) {%0A if (isLine(line)) replaceRange(""%2C {line%3A line%2C ch%3A 0}%2C clipPos({line%3A line%2B1%2C ch%3A 0}))%3B%0A })%2C%0A replaceRange%3A operation(replaceRange)%2C%0A getRange%3A function(from%2C to%2C lineSep) {return getRange(clipPos(from)%2C clipPos(to)%2C lineSep)%3B}%2C%0A%0A triggerOnKeyDown%3A operation(onKeyDown)%2C%0A execCommand%3A function(cmd) {return commands[cmd](instance)%3B}%2C%0A %2F%2F Stuff used by commands%2C probably not much use to outside code.%0A moveH%3A operation(moveH)%2C%0A deleteH%3A operation(deleteH)%2C%0A moveV%3A operation(moveV)%2C%0A toggleOverwrite%3A function() {%0A if(overwrite){%0A overwrite %3D false%3B%0A cursor.className %3D cursor.className.replace(" CodeMirror-overwrite"%2C "")%3B%0A } else {%0A overwrite %3D true%3B%0A cursor.className %2B%3D " CodeMirror-overwrite"%3B%0A }%0A }%2C%0A%0A posFromIndex%3A function(off) {%0A var lineNo %3D 0%2C ch%3B%0A doc.iter(0%2C doc.size%2C function(line) {%0A var sz %3D line.text.length %2B 1%3B%0A if (sz > off) { ch %3D off%3B return true%3B }%0A off -%3D sz%3B%0A %2B%2BlineNo%3B%0A })%3B%0A return clipPos({line%3A lineNo%2C ch%3A ch})%3B%0A }%2C%0A indexFromPos%3A function (coords) {%0A if (coords.line < 0 || coords.ch < 0) return 0%3B%0A var index %3D coords.ch%3B%0A doc.iter(0%2C coords.line%2C function (line) {%0A index %2B%3D line.text.length %2B 1%3B%0A })%3B%0A return index%3B%0A }%2C%0A scrollTo%3A function(x%2C y) {%0A if (x !%3D null) scroller.scrollLeft %3D x%3B%0A if (y !%3D null) scrollbar.scrollTop %3D scroller.scrollTop %3D y%3B%0A updateDisplay([])%3B%0A }%2C%0A getScrollInfo%3A function() {%0A return {x%3A scroller.scrollLeft%2C y%3A scrollbar.scrollTop%2C%0A height%3A scrollbar.scrollHeight%2C width%3A scroller.scrollWidth}%3B%0A }%2C%0A setSize%3A function(width%2C height) {%0A function interpret(val) {%0A val %3D String(val)%3B%0A return %2F^\d%2B%24%2F.test(val) %3F val %2B "px" %3A val%3B%0A }%0A if (width !%3D null) wrapper.style.width %3D interpret(width)%3B%0A if (height !%3D null) scroller.style.height %3D interpret(height)%3B%0A instance.refresh()%3B%0A }%2C%0A%0A operation%3A function(f){return operation(f)()%3B}%2C%0A compoundChange%3A function(f){return compoundChange(f)%3B}%2C%0A refresh%3A function(){%0A updateDisplay(true%2C null%2C lastScrollTop)%3B%0A if (scrollbar.scrollHeight > lastScrollTop)%0A scrollbar.scrollTop %3D lastScrollTop%3B%0A }%2C%0A getInputField%3A function(){return input%3B}%2C%0A getWrapperElement%3A function(){return wrapper%3B}%2C%0A getScrollerElement%3A function(){return scroller%3B}%2C%0A getGutterElement%3A function(){return gutter%3B}%0A }%3B%0A%0A function getLine(n) { return getLineAt(doc%2C n)%3B }%0A function updateLineHeight(line%2C height) {%0A gutterDirty %3D true%3B%0A var diff %3D height - line.height%3B%0A for (var n %3D line%3B n%3B n %3D n.parent) n.height %2B%3D diff%3B%0A }%0A%0A function lineContent(line%2C wrapAt) {%0A if (!line.styles)%0A line.highlight(mode%2C line.stateAfter %3D getStateBefore(lineNo(line))%2C options.tabSize)%3B%0A return line.getContent(options.tabSize%2C wrapAt%2C options.lineWrapping)%3B%0A }%0A%0A function setValue(code) {%0A var top %3D {line%3A 0%2C ch%3A 0}%3B%0A updateLines(top%2C {line%3A doc.size - 1%2C ch%3A getLine(doc.size-1).text.length}%2C%0A splitLines(code)%2C top%2C top)%3B%0A updateInput %3D true%3B%0A }%0A function getValue(lineSep) {%0A var text %3D []%3B%0A doc.iter(0%2C doc.size%2C function(line) { text.push(line.text)%3B })%3B%0A return text.join(lineSep || "\n")%3B%0A }%0A%0A function onScrollBar(e) {%0A if (scrollbar.scrollTop !%3D lastScrollTop) {%0A lastScrollTop %3D scroller.scrollTop %3D scrollbar.scrollTop%3B%0A updateDisplay([])%3B%0A }%0A }%0A%0A function onScrollMain(e) {%0A if (options.fixedGutter %26%26 gutter.style.left !%3D scroller.scrollLeft %2B "px")%0A gutter.style.left %3D scroller.scrollLeft %2B "px"%3B%0A if (scroller.scrollTop !%3D lastScrollTop) {%0A lastScrollTop %3D scroller.scrollTop%3B%0A if (scrollbar.scrollTop !%3D lastScrollTop)%0A scrollbar.scrollTop %3D lastScrollTop%3B%0A updateDisplay([])%3B%0A }%0A if (options.onScroll) options.onScroll(instance)%3B%0A }%0A%0A function onMouseDown(e) {%0A setShift(e_prop(e%2C "shiftKey"))%3B%0A %2F%2F Check whether this is a click in a widget%0A for (var n %3D e_target(e)%3B n !%3D wrapper%3B n %3D n.parentNode)%0A if (n.parentNode %3D%3D sizer %26%26 n !%3D mover) return%3B%0A%0A %2F%2F See if this is a click in the gutter%0A for (var n %3D e_target(e)%3B n !%3D wrapper%3B n %3D n.parentNode)%0A if (n.parentNode %3D%3D gutterText) {%0A if (options.onGutterClick)%0A options.onGutterClick(instance%2C indexOf(gutterText.childNodes%2C n) %2B showingFrom%2C e)%3B%0A return e_preventDefault(e)%3B%0A }%0A%0A var start %3D posFromMouse(e)%3B%0A%0A switch (e_button(e)) {%0A case 3%3A%0A if (gecko) onContextMenu(e)%3B%0A return%3B%0A case 2%3A%0A if (start) setCursor(start.line%2C start.ch%2C true)%3B%0A setTimeout(focusInput%2C 20)%3B%0A e_preventDefault(e)%3B%0A return%3B%0A }%0A %2F%2F For button 1%2C if it was clicked inside the editor%0A %2F%2F (posFromMouse returning non-null)%2C we have to adjust the%0A %2F%2F selection.%0A if (!start) {if (e_target(e) %3D%3D scroller) e_preventDefault(e)%3B return%3B}%0A%0A if (!focused) onFocus()%3B%0A%0A var now %3D %2Bnew Date%2C type %3D "single"%3B%0A if (lastDoubleClick %26%26 lastDoubleClick.time > now - 400 %26%26 posEq(lastDoubleClick.pos%2C start)) {%0A type %3D "triple"%3B%0A e_preventDefault(e)%3B%0A setTimeout(focusInput%2C 20)%3B%0A selectLine(start.line)%3B%0A } else if (lastClick %26%26 lastClick.time > now - 400 %26%26 posEq(lastClick.pos%2C start)) {%0A type %3D "double"%3B%0A lastDoubleClick %3D {time%3A now%2C pos%3A start}%3B%0A e_preventDefault(e)%3B%0A var word %3D findWordAt(start)%3B%0A setSelectionUser(word.from%2C word.to)%3B%0A } else { lastClick %3D {time%3A now%2C pos%3A start}%3B }%0A%0A function dragEnd(e2) {%0A if (webkit) scroller.draggable %3D false%3B%0A draggingText %3D false%3B%0A up()%3B drop()%3B%0A if (Math.abs(e.clientX - e2.clientX) %2B Math.abs(e.clientY - e2.clientY) < 10) {%0A e_preventDefault(e2)%3B%0A setCursor(start.line%2C start.ch%2C true)%3B%0A focusInput()%3B%0A }%0A }%0A var last %3D start%2C going%3B%0A if (options.dragDrop %26%26 dragAndDrop %26%26 !options.readOnly %26%26 !posEq(sel.from%2C sel.to) %26%26%0A !posLess(start%2C sel.from) %26%26 !posLess(sel.to%2C start) %26%26 type %3D%3D "single") {%0A %2F%2F Let the drag handler handle this.%0A if (webkit) scroller.draggable %3D true%3B%0A var up %3D connect(document%2C "mouseup"%2C operation(dragEnd)%2C true)%3B%0A var drop %3D connect(scroller%2C "drop"%2C operation(dragEnd)%2C true)%3B%0A draggingText %3D true%3B%0A %2F%2F IE's approach to draggable%0A if (scroller.dragDrop) scroller.dragDrop()%3B%0A return%3B%0A }%0A e_preventDefault(e)%3B%0A if (type %3D%3D "single") setCursor(start.line%2C start.ch%2C true)%3B%0A%0A var startstart %3D sel.from%2C startend %3D sel.to%3B%0A%0A function doSelect(cur) {%0A if (type %3D%3D "single") {%0A setSelectionUser(start%2C cur)%3B%0A } else if (type %3D%3D "double") {%0A var word %3D findWordAt(cur)%3B%0A if (posLess(cur%2C startstart)) setSelectionUser(word.from%2C startend)%3B%0A else setSelectionUser(startstart%2C word.to)%3B%0A } else if (type %3D%3D "triple") {%0A if (posLess(cur%2C startstart)) setSelectionUser(startend%2C clipPos({line%3A cur.line%2C ch%3A 0}))%3B%0A else setSelectionUser(startstart%2C clipPos({line%3A cur.line %2B 1%2C ch%3A 0}))%3B%0A }%0A }%0A%0A function extend(e) {%0A var cur %3D posFromMouse(e%2C true)%3B%0A if (cur %26%26 !posEq(cur%2C last)) {%0A if (!focused) onFocus()%3B%0A last %3D cur%3B%0A doSelect(cur)%3B%0A updateInput %3D false%3B%0A var visible %3D visibleLines()%3B%0A if (cur.line >%3D visible.to || cur.line < visible.from)%0A going %3D setTimeout(operation(function(){extend(e)%3B})%2C 150)%3B%0A }%0A }%0A%0A function done(e) {%0A clearTimeout(going)%3B%0A var cur %3D posFromMouse(e)%3B%0A if (cur) doSelect(cur)%3B%0A e_preventDefault(e)%3B%0A focusInput()%3B%0A updateInput %3D true%3B%0A move()%3B up()%3B%0A }%0A var move %3D connect(document%2C "mousemove"%2C operation(function(e) {%0A clearTimeout(going)%3B%0A e_preventDefault(e)%3B%0A if (!ie %26%26 !e_button(e)) done(e)%3B%0A else extend(e)%3B%0A })%2C true)%3B%0A var up %3D connect(document%2C "mouseup"%2C operation(done)%2C true)%3B%0A }%0A function onDoubleClick(e) {%0A for (var n %3D e_target(e)%3B n !%3D wrapper%3B n %3D n.parentNode)%0A if (n.parentNode %3D%3D gutterText) return e_preventDefault(e)%3B%0A e_preventDefault(e)%3B%0A }%0A function onDrop(e) {%0A if (options.onDragEvent %26%26 options.onDragEvent(instance%2C addStop(e))) return%3B%0A e_preventDefault(e)%3B%0A var pos %3D posFromMouse(e%2C true)%2C files %3D e.dataTransfer.files%3B%0A if (!pos || options.readOnly) return%3B%0A if (files %26%26 files.length %26%26 window.FileReader %26%26 window.File) {%0A var n %3D files.length%2C text %3D Array(n)%2C read %3D 0%3B%0A var loadFile %3D function(file%2C i) {%0A var reader %3D new FileReader%3B%0A reader.onload %3D function() {%0A text[i] %3D reader.result%3B%0A if (%2B%2Bread %3D%3D n) {%0A pos %3D clipPos(pos)%3B%0A operation(function() {%0A var end %3D replaceRange(text.join("")%2C pos%2C pos)%3B%0A setSelectionUser(pos%2C end)%3B%0A })()%3B%0A }%0A }%3B%0A reader.readAsText(file)%3B%0A }%3B%0A for (var i %3D 0%3B i < n%3B %2B%2Bi) loadFile(files[i]%2C i)%3B%0A } else {%0A %2F%2F Don't do a replace if the drop happened inside of the selected text.%0A if (draggingText %26%26 !(posLess(pos%2C sel.from) || posLess(sel.to%2C pos))) return%3B%0A try {%0A var text %3D e.dataTransfer.getData("Text")%3B%0A if (text) {%0A compoundChange(function() {%0A var curFrom %3D sel.from%2C curTo %3D sel.to%3B%0A setSelectionUser(pos%2C pos)%3B%0A if (draggingText) replaceRange(""%2C curFrom%2C curTo)%3B%0A replaceSelection(text)%3B%0A focusInput()%3B%0A })%3B%0A }%0A }%0A catch(e){}%0A }%0A }%0A function onDragStart(e) {%0A var txt %3D getSelection()%3B%0A e.dataTransfer.setData("Text"%2C txt)%3B%0A%0A %2F%2F Use dummy image instead of default browsers image.%0A if (e.dataTransfer.setDragImage)%0A e.dataTransfer.setDragImage(elt('img')%2C 0%2C 0)%3B%0A }%0A%0A function doHandleBinding(bound%2C dropShift) {%0A if (typeof bound %3D%3D "string") {%0A bound %3D commands[bound]%3B%0A if (!bound) return false%3B%0A }%0A var prevShift %3D shiftSelecting%3B%0A try {%0A if (options.readOnly) suppressEdits %3D true%3B%0A if (dropShift) shiftSelecting %3D null%3B%0A bound(instance)%3B%0A } catch(e) {%0A if (e !%3D Pass) throw e%3B%0A return false%3B%0A } finally {%0A shiftSelecting %3D prevShift%3B%0A suppressEdits %3D false%3B%0A }%0A return true%3B%0A }%0A var maybeTransition%3B%0A function handleKeyBinding(e) {%0A %2F%2F Handle auto keymap transitions%0A var startMap %3D getKeyMap(options.keyMap)%2C next %3D startMap.auto%3B%0A clearTimeout(maybeTransition)%3B%0A if (next %26%26 !isModifierKey(e)) maybeTransition %3D setTimeout(function() {%0A if (getKeyMap(options.keyMap) %3D%3D startMap) {%0A options.keyMap %3D (next.call %3F next.call(null%2C instance) %3A next)%3B%0A }%0A }%2C 50)%3B%0A%0A var name %3D keyNames[e_prop(e%2C "keyCode")]%2C handled %3D false%3B%0A var flipCtrlCmd %3D opera %26%26 mac%3B%0A if (name %3D%3D null || e.altGraphKey) return false%3B%0A if (e_prop(e%2C "altKey")) name %3D "Alt-" %2B name%3B%0A if (e_prop(e%2C flipCtrlCmd %3F "metaKey" %3A "ctrlKey")) name %3D "Ctrl-" %2B name%3B%0A if (e_prop(e%2C flipCtrlCmd %3F "ctrlKey" %3A "metaKey")) name %3D "Cmd-" %2B name%3B%0A%0A var stopped %3D false%3B%0A function stop() { stopped %3D true%3B }%0A%0A if (e_prop(e%2C "shiftKey")) {%0A handled %3D lookupKey("Shift-" %2B name%2C options.extraKeys%2C options.keyMap%2C%0A function(b) {return doHandleBinding(b%2C true)%3B}%2C stop)%0A || lookupKey(name%2C options.extraKeys%2C options.keyMap%2C function(b) {%0A if (typeof b %3D%3D "string" %26%26 %2F^go[A-Z]%2F.test(b)) return doHandleBinding(b)%3B%0A }%2C stop)%3B%0A } else {%0A handled %3D lookupKey(name%2C options.extraKeys%2C options.keyMap%2C doHandleBinding%2C stop)%3B%0A }%0A if (stopped) handled %3D false%3B%0A if (handled) {%0A e_preventDefault(e)%3B%0A restartBlink()%3B%0A if (ie) { e.oldKeyCode %3D e.keyCode%3B e.keyCode %3D 0%3B }%0A }%0A return handled%3B%0A }%0A function handleCharBinding(e%2C ch) {%0A var handled %3D lookupKey("'" %2B ch %2B "'"%2C options.extraKeys%2C%0A options.keyMap%2C function(b) { return doHandleBinding(b%2C true)%3B })%3B%0A if (handled) {%0A e_preventDefault(e)%3B%0A restartBlink()%3B%0A }%0A return handled%3B%0A }%0A%0A var lastStoppedKey %3D null%3B%0A function onKeyDown(e) {%0A if (!focused) onFocus()%3B%0A if (ie %26%26 e.keyCode %3D%3D 27) { e.returnValue %3D false%3B }%0A if (pollingFast) { if (readInput()) pollingFast %3D false%3B }%0A if (options.onKeyEvent %26%26 options.onKeyEvent(instance%2C addStop(e))) return%3B%0A var code %3D e_prop(e%2C "keyCode")%3B%0A %2F%2F IE does strange things with escape.%0A setShift(code %3D%3D 16 || e_prop(e%2C "shiftKey"))%3B%0A %2F%2F First give onKeyEvent option a chance to handle this.%0A var handled %3D handleKeyBinding(e)%3B%0A if (opera) {%0A lastStoppedKey %3D handled %3F code %3A null%3B%0A %2F%2F Opera has no cut event... we try to at least catch the key combo%0A if (!handled %26%26 code %3D%3D 88 %26%26 e_prop(e%2C mac %3F "metaKey" %3A "ctrlKey"))%0A replaceSelection("")%3B%0A }%0A }%0A function onKeyPress(e) {%0A if (pollingFast) readInput()%3B%0A if (options.onKeyEvent %26%26 options.onKeyEvent(instance%2C addStop(e))) return%3B%0A var keyCode %3D e_prop(e%2C "keyCode")%2C charCode %3D e_prop(e%2C "charCode")%3B%0A if (opera %26%26 keyCode %3D%3D lastStoppedKey) {lastStoppedKey %3D null%3B e_preventDefault(e)%3B return%3B}%0A if (((opera %26%26 (!e.which || e.which < 10)) || khtml) %26%26 handleKeyBinding(e)) return%3B%0A var ch %3D String.fromCharCode(charCode %3D%3D null %3F keyCode %3A charCode)%3B%0A if (options.electricChars %26%26 mode.electricChars %26%26 options.smartIndent %26%26 !options.readOnly) {%0A if (mode.electricChars.indexOf(ch) > -1)%0A setTimeout(operation(function() {indentLine(sel.to.line%2C "smart")%3B})%2C 75)%3B%0A }%0A if (handleCharBinding(e%2C ch)) return%3B%0A fastPoll()%3B%0A }%0A function onKeyUp(e) {%0A if (options.onKeyEvent %26%26 options.onKeyEvent(instance%2C addStop(e))) return%3B%0A if (e_prop(e%2C "keyCode") %3D%3D 16) shiftSelecting %3D null%3B%0A }%0A%0A function onFocus() {%0A if (options.readOnly %3D%3D "nocursor") return%3B%0A if (!focused) {%0A if (options.onFocus) options.onFocus(instance)%3B%0A focused %3D true%3B%0A if (scroller.className.search(%2F\bCodeMirror-focused\b%2F) %3D%3D -1)%0A scroller.className %2B%3D " CodeMirror-focused"%3B%0A }%0A slowPoll()%3B%0A restartBlink()%3B%0A }%0A function onBlur() {%0A if (focused) {%0A if (options.onBlur) options.onBlur(instance)%3B%0A focused %3D false%3B%0A if (bracketHighlighted)%0A operation(function(){%0A if (bracketHighlighted) { bracketHighlighted()%3B bracketHighlighted %3D null%3B }%0A })()%3B%0A scroller.className %3D scroller.className.replace(" CodeMirror-focused"%2C "")%3B%0A }%0A clearInterval(blinker)%3B%0A setTimeout(function() {if (!focused) shiftSelecting %3D null%3B}%2C 150)%3B%0A }%0A%0A %2F%2F Replace the range from from to to by the strings in newText.%0A %2F%2F Afterwards%2C set the selection to selFrom%2C selTo.%0A function updateLines(from%2C to%2C newText%2C selFrom%2C selTo) {%0A if (suppressEdits) return%3B%0A var old %3D []%3B%0A doc.iter(from.line%2C to.line %2B 1%2C function(line) {%0A old.push(newHL(line.text%2C line.markedSpans))%3B%0A })%3B%0A if (history) {%0A history.addChange(from.line%2C newText.length%2C old)%3B%0A while (history.done.length > options.undoDepth) history.done.shift()%3B%0A }%0A var lines %3D updateMarkedSpans(hlSpans(old[0])%2C hlSpans(lst(old))%2C from.ch%2C to.ch%2C newText)%3B%0A updateLinesNoUndo(from%2C to%2C lines%2C selFrom%2C selTo)%3B%0A }%0A function unredoHelper(from%2C to) {%0A if (!from.length) return%3B%0A var set %3D from.pop()%2C out %3D []%3B%0A for (var i %3D set.length - 1%3B i >%3D 0%3B i -%3D 1) {%0A var change %3D set[i]%3B%0A var replaced %3D []%2C end %3D change.start %2B change.added%3B%0A doc.iter(change.start%2C end%2C function(line) { replaced.push(newHL(line.text%2C line.markedSpans))%3B })%3B%0A out.push({start%3A change.start%2C added%3A change.old.length%2C old%3A replaced})%3B%0A var pos %3D {line%3A change.start %2B change.old.length - 1%2C%0A ch%3A editEnd(hlText(lst(replaced))%2C hlText(lst(change.old)))}%3B%0A updateLinesNoUndo({line%3A change.start%2C ch%3A 0}%2C {line%3A end - 1%2C ch%3A getLine(end-1).text.length}%2C%0A change.old%2C pos%2C pos)%3B%0A }%0A updateInput %3D true%3B%0A to.push(out)%3B%0A }%0A function undo() {unredoHelper(history.done%2C history.undone)%3B}%0A function redo() {unredoHelper(history.undone%2C history.done)%3B}%0A%0A function updateLinesNoUndo(from%2C to%2C lines%2C selFrom%2C selTo) {%0A if (suppressEdits) return%3B%0A var recomputeMaxLength %3D false%2C maxLineLength %3D maxLine.text.length%3B%0A if (!options.lineWrapping)%0A doc.iter(from.line%2C to.line %2B 1%2C function(line) {%0A if (!line.hidden %26%26 line.text.length %3D%3D maxLineLength) {recomputeMaxLength %3D true%3B return true%3B}%0A })%3B%0A if (from.line !%3D to.line || lines.length > 1) gutterDirty %3D true%3B%0A%0A var nlines %3D to.line - from.line%2C firstLine %3D getLine(from.line)%2C lastLine %3D getLine(to.line)%3B%0A var lastHL %3D lst(lines)%3B%0A%0A %2F%2F First adjust the line structure%0A if (from.ch %3D%3D 0 %26%26 to.ch %3D%3D 0 %26%26 hlText(lastHL) %3D%3D "") {%0A %2F%2F This is a whole-line replace. Treated specially to make%0A %2F%2F sure line objects move the way they are supposed to.%0A var added %3D []%2C prevLine %3D null%3B%0A for (var i %3D 0%2C e %3D lines.length - 1%3B i < e%3B %2B%2Bi)%0A added.push(new Line(hlText(lines[i])%2C hlSpans(lines[i])))%3B%0A lastLine.update(lastLine.text%2C hlSpans(lastHL))%3B%0A if (nlines) doc.remove(from.line%2C nlines%2C callbacks)%3B%0A if (added.length) doc.insert(from.line%2C added)%3B%0A } else if (firstLine %3D%3D lastLine) {%0A if (lines.length %3D%3D 1) {%0A firstLine.update(firstLine.text.slice(0%2C from.ch) %2B hlText(lines[0]) %2B firstLine.text.slice(to.ch)%2C hlSpans(lines[0]))%3B%0A } else {%0A for (var added %3D []%2C i %3D 1%2C e %3D lines.length - 1%3B i < e%3B %2B%2Bi)%0A added.push(new Line(hlText(lines[i])%2C hlSpans(lines[i])))%3B%0A added.push(new Line(hlText(lastHL) %2B firstLine.text.slice(to.ch)%2C hlSpans(lastHL)))%3B%0A firstLine.update(firstLine.text.slice(0%2C from.ch) %2B hlText(lines[0])%2C hlSpans(lines[0]))%3B%0A doc.insert(from.line %2B 1%2C added)%3B%0A }%0A } else if (lines.length %3D%3D 1) {%0A firstLine.update(firstLine.text.slice(0%2C from.ch) %2B hlText(lines[0]) %2B lastLine.text.slice(to.ch)%2C hlSpans(lines[0]))%3B%0A doc.remove(from.line %2B 1%2C nlines%2C callbacks)%3B%0A } else {%0A var added %3D []%3B%0A firstLine.update(firstLine.text.slice(0%2C from.ch) %2B hlText(lines[0])%2C hlSpans(lines[0]))%3B%0A lastLine.update(hlText(lastHL) %2B lastLine.text.slice(to.ch)%2C hlSpans(lastHL))%3B%0A for (var i %3D 1%2C e %3D lines.length - 1%3B i < e%3B %2B%2Bi)%0A added.push(new Line(hlText(lines[i])%2C hlSpans(lines[i])))%3B%0A if (nlines > 1) doc.remove(from.line %2B 1%2C nlines - 1%2C callbacks)%3B%0A doc.insert(from.line %2B 1%2C added)%3B%0A }%0A if (options.lineWrapping) {%0A var perLine %3D Math.max(5%2C scroller.clientWidth %2F charWidth() - 3)%3B%0A doc.iter(from.line%2C from.line %2B lines.length%2C function(line) {%0A if (line.hidden) return%3B%0A var guess %3D Math.ceil(line.text.length %2F perLine) || 1%3B%0A if (guess !%3D line.height) updateLineHeight(line%2C guess)%3B%0A })%3B%0A } else {%0A doc.iter(from.line%2C from.line %2B lines.length%2C function(line) {%0A var l %3D line.text%3B%0A if (!line.hidden %26%26 l.length > maxLineLength) {%0A maxLine %3D line%3B maxLineLength %3D l.length%3B maxLineChanged %3D true%3B%0A recomputeMaxLength %3D false%3B%0A }%0A })%3B%0A if (recomputeMaxLength) updateMaxLine %3D true%3B%0A }%0A%0A %2F%2F Adjust frontier%2C schedule worker%0A frontier %3D Math.min(frontier%2C from.line)%3B%0A startWorker(400)%3B%0A%0A var lendiff %3D lines.length - nlines - 1%3B%0A %2F%2F Remember that these lines changed%2C for updating the display%0A changes.push({from%3A from.line%2C to%3A to.line %2B 1%2C diff%3A lendiff})%3B%0A if (options.onChange) {%0A %2F%2F Normalize lines to contain only strings%2C since that's what%0A %2F%2F the change event handler expects%0A for (var i %3D 0%3B i < lines.length%3B %2B%2Bi)%0A if (typeof lines[i] !%3D "string") lines[i] %3D lines[i].text%3B%0A var changeObj %3D {from%3A from%2C to%3A to%2C text%3A lines}%3B%0A if (textChanged) {%0A for (var cur %3D textChanged%3B cur.next%3B cur %3D cur.next) {}%0A cur.next %3D changeObj%3B%0A } else textChanged %3D changeObj%3B%0A }%0A%0A %2F%2F Update the selection%0A function updateLine(n) {return n <%3D Math.min(to.line%2C to.line %2B lendiff) %3F n %3A n %2B lendiff%3B}%0A setSelection(clipPos(selFrom)%2C clipPos(selTo)%2C%0A updateLine(sel.from.line)%2C updateLine(sel.to.line))%3B%0A }%0A%0A function needsScrollbar() {%0A var realHeight %3D doc.height * textHeight() %2B 2 * paddingTop()%3B%0A return realHeight * .99 > scroller.offsetHeight %3F realHeight %3A false%3B%0A }%0A%0A function updateVerticalScroll(scrollTop) {%0A var scrollHeight %3D needsScrollbar()%3B%0A scrollbar.style.display %3D scrollHeight %3F "block" %3A "none"%3B%0A if (scrollHeight) {%0A scrollbarInner.style.height %3D sizer.style.minHeight %3D scrollHeight %2B "px"%3B%0A scrollbar.style.height %3D scroller.clientHeight %2B "px"%3B%0A if (scrollTop !%3D null) {%0A scrollbar.scrollTop %3D scroller.scrollTop %3D scrollTop%3B%0A %2F%2F 'Nudge' the scrollbar to work around a Webkit bug where%2C%0A %2F%2F in some situations%2C we'd end up with a scrollbar that%0A %2F%2F reported its scrollTop (and looked) as expected%2C but%0A %2F%2F *behaved* as if it was still in a previous state (i.e.%0A %2F%2F couldn't scroll up%2C even though it appeared to be at the%0A %2F%2F bottom).%0A if (webkit) setTimeout(function() {%0A if (scrollbar.scrollTop !%3D scrollTop) return%3B%0A scrollbar.scrollTop %3D scrollTop %2B (scrollTop %3F -1 %3A 1)%3B%0A scrollbar.scrollTop %3D scrollTop%3B%0A }%2C 0)%3B%0A }%0A } else {%0A sizer.style.minHeight %3D ""%3B%0A }%0A %2F%2F Position the mover div to align with the current virtual scroll position%0A mover.style.top %3D displayOffset * textHeight() %2B "px"%3B%0A }%0A%0A function computeMaxLength() {%0A maxLine %3D getLine(0)%3B maxLineChanged %3D true%3B%0A var maxLineLength %3D maxLine.text.length%3B%0A doc.iter(1%2C doc.size%2C function(line) {%0A var l %3D line.text%3B%0A if (!line.hidden %26%26 l.length > maxLineLength) {%0A maxLineLength %3D l.length%3B maxLine %3D line%3B%0A }%0A })%3B%0A updateMaxLine %3D false%3B%0A }%0A%0A function replaceRange(code%2C from%2C to) {%0A from %3D clipPos(from)%3B%0A if (!to) to %3D from%3B else to %3D clipPos(to)%3B%0A code %3D splitLines(code)%3B%0A function adjustPos(pos) {%0A if (posLess(pos%2C from)) return pos%3B%0A if (!posLess(to%2C pos)) return end%3B%0A var line %3D pos.line %2B code.length - (to.line - from.line) - 1%3B%0A var ch %3D pos.ch%3B%0A if (pos.line %3D%3D to.line)%0A ch %2B%3D lst(code).length - (to.ch - (to.line %3D%3D from.line %3F from.ch %3A 0))%3B%0A return {line%3A line%2C ch%3A ch}%3B%0A }%0A var end%3B%0A replaceRange1(code%2C from%2C to%2C function(end1) {%0A end %3D end1%3B%0A return {from%3A adjustPos(sel.from)%2C to%3A adjustPos(sel.to)}%3B%0A })%3B%0A return end%3B%0A }%0A function replaceSelection(code%2C collapse) {%0A replaceRange1(splitLines(code)%2C sel.from%2C sel.to%2C function(end) {%0A if (collapse %3D%3D "end") return {from%3A end%2C to%3A end}%3B%0A else if (collapse %3D%3D "start") return {from%3A sel.from%2C to%3A sel.from}%3B%0A else return {from%3A sel.from%2C to%3A end}%3B%0A })%3B%0A }%0A function replaceRange1(code%2C from%2C to%2C computeSel) {%0A var endch %3D code.length %3D%3D 1 %3F code[0].length %2B from.ch %3A lst(code).length%3B%0A var newSel %3D computeSel({line%3A from.line %2B code.length - 1%2C ch%3A endch})%3B%0A updateLines(from%2C to%2C code%2C newSel.from%2C newSel.to)%3B%0A }%0A%0A function getRange(from%2C to%2C lineSep) {%0A var l1 %3D from.line%2C l2 %3D to.line%3B%0A if (l1 %3D%3D l2) return getLine(l1).text.slice(from.ch%2C to.ch)%3B%0A var code %3D [getLine(l1).text.slice(from.ch)]%3B%0A doc.iter(l1 %2B 1%2C l2%2C function(line) { code.push(line.text)%3B })%3B%0A code.push(getLine(l2).text.slice(0%2C to.ch))%3B%0A return code.join(lineSep || "\n")%3B%0A }%0A function getSelection(lineSep) {%0A return getRange(sel.from%2C sel.to%2C lineSep)%3B%0A }%0A%0A function slowPoll() {%0A if (pollingFast) return%3B%0A poll.set(options.pollInterval%2C function() {%0A readInput()%3B%0A if (focused) slowPoll()%3B%0A })%3B%0A }%0A function fastPoll() {%0A var missed %3D false%3B%0A pollingFast %3D true%3B%0A function p() {%0A var changed %3D readInput()%3B%0A if (!changed %26%26 !missed) {missed %3D true%3B poll.set(60%2C p)%3B}%0A else {pollingFast %3D false%3B slowPoll()%3B}%0A }%0A poll.set(20%2C p)%3B%0A }%0A%0A %2F%2F Previnput is a hack to work with IME. If we reset the textarea%0A %2F%2F on every change%2C that breaks IME. So we look for changes%0A %2F%2F compared to the previous content instead. (Modern browsers have%0A %2F%2F events that indicate IME taking place%2C but these are not widely%0A %2F%2F supported or compatible enough yet to rely on.)%0A var prevInput %3D ""%3B%0A function readInput() {%0A if (!focused || hasSelection(input) || options.readOnly) return false%3B%0A var text %3D input.value%3B%0A if (text %3D%3D prevInput) return false%3B%0A if (!nestedOperation) startOperation()%3B%0A shiftSelecting %3D null%3B%0A var same %3D 0%2C l %3D Math.min(prevInput.length%2C text.length)%3B%0A while (same < l %26%26 prevInput[same] %3D%3D text[same]) %2B%2Bsame%3B%0A if (same < prevInput.length)%0A sel.from %3D {line%3A sel.from.line%2C ch%3A sel.from.ch - (prevInput.length - same)}%3B%0A else if (overwrite %26%26 posEq(sel.from%2C sel.to))%0A sel.to %3D {line%3A sel.to.line%2C ch%3A Math.min(getLine(sel.to.line).text.length%2C sel.to.ch %2B (text.length - same))}%3B%0A replaceSelection(text.slice(same)%2C "end")%3B%0A if (text.length > 1000) { input.value %3D prevInput %3D ""%3B }%0A else prevInput %3D text%3B%0A if (!nestedOperation) endOperation()%3B%0A return true%3B%0A }%0A function resetInput(user) {%0A if (!posEq(sel.from%2C sel.to)) {%0A prevInput %3D ""%3B%0A input.value %3D getSelection()%3B%0A if (focused) selectInput(input)%3B%0A } else if (user) prevInput %3D input.value %3D ""%3B%0A }%0A%0A function focusInput() {%0A if (options.readOnly !%3D "nocursor") input.focus()%3B%0A }%0A%0A function scrollCursorIntoView() {%0A var coords %3D calculateCursorCoords()%3B%0A scrollIntoView(coords.x%2C coords.y%2C coords.x%2C coords.yBot)%3B%0A if (!focused) return%3B%0A var box %3D sizer.getBoundingClientRect()%2C doScroll %3D null%3B%0A if (coords.y %2B box.top < 0) doScroll %3D true%3B%0A else if (coords.y %2B box.top %2B textHeight() > (window.innerHeight || document.documentElement.clientHeight)) doScroll %3D false%3B%0A if (doScroll !%3D null) {%0A var hidden %3D cursor.style.display %3D%3D "none"%3B%0A if (hidden) {%0A cursor.style.display %3D ""%3B%0A cursor.style.left %3D coords.x %2B "px"%3B%0A cursor.style.top %3D (coords.y - displayOffset) %2B "px"%3B%0A }%0A cursor.scrollIntoView(doScroll)%3B%0A if (hidden) cursor.style.display %3D "none"%3B%0A }%0A }%0A function calculateCursorCoords() {%0A var cursor %3D localCoords(sel.inverted %3F sel.from %3A sel.to)%3B%0A var x %3D options.lineWrapping %3F Math.min(cursor.x%2C lineSpace.offsetWidth) %3A cursor.x%3B%0A return {x%3A x%2C y%3A cursor.y%2C yBot%3A cursor.yBot}%3B%0A }%0A function scrollIntoView(x1%2C y1%2C x2%2C y2) {%0A var scrollPos %3D calculateScrollPos(x1%2C y1%2C x2%2C y2)%3B%0A if (scrollPos.scrollLeft !%3D null) {scroller.scrollLeft %3D scrollPos.scrollLeft%3B}%0A if (scrollPos.scrollTop !%3D null) {scrollbar.scrollTop %3D scroller.scrollTop %3D scrollPos.scrollTop%3B}%0A }%0A function calculateScrollPos(x1%2C y1%2C x2%2C y2) {%0A var pl %3D paddingLeft()%2C pt %3D paddingTop()%3B%0A y1 %2B%3D pt%3B y2 %2B%3D pt%3B x1 %2B%3D pl%3B x2 %2B%3D pl%3B%0A var screen %3D scroller.clientHeight%2C screentop %3D scrollbar.scrollTop%2C result %3D {}%3B%0A var docBottom %3D needsScrollbar() || Infinity%3B%0A var atTop %3D y1 < pt %2B 10%2C atBottom %3D y2 %2B pt > docBottom - 10%3B%0A if (y1 < screentop) result.scrollTop %3D atTop %3F 0 %3A Math.max(0%2C y1)%3B%0A else if (y2 > screentop %2B screen) result.scrollTop %3D (atBottom %3F docBottom %3A y2) - screen%3B%0A%0A var screenw %3D scroller.clientWidth%2C screenleft %3D scroller.scrollLeft%3B%0A var gutterw %3D options.fixedGutter %3F gutter.clientWidth %3A 0%3B%0A var atLeft %3D x1 < gutterw %2B pl %2B 10%3B%0A if (x1 < screenleft %2B gutterw || atLeft) {%0A if (atLeft) x1 %3D 0%3B%0A result.scrollLeft %3D Math.max(0%2C x1 - 10 - gutterw)%3B%0A } else if (x2 > screenw %2B screenleft - 3) {%0A result.scrollLeft %3D x2 %2B 10 - screenw%3B%0A }%0A return result%3B%0A }%0A%0A function visibleLines(scrollTop) {%0A var lh %3D textHeight()%2C top %3D (scrollTop !%3D null %3F scrollTop %3A scrollbar.scrollTop) - paddingTop()%3B%0A var fromHeight %3D Math.max(0%2C Math.floor(top %2F lh))%3B%0A var toHeight %3D Math.ceil((top %2B scroller.clientHeight) %2F lh)%3B%0A return {from%3A lineAtHeight(doc%2C fromHeight)%2C%0A to%3A lineAtHeight(doc%2C toHeight)}%3B%0A }%0A %2F%2F Uses a set of changes plus the current scroll position to%0A %2F%2F determine which DOM updates have to be made%2C and makes the%0A %2F%2F updates.%0A function updateDisplay(changes%2C suppressCallback%2C scrollTop) {%0A if (!scroller.clientWidth) {%0A showingFrom %3D showingTo %3D displayOffset %3D 0%3B%0A return%3B%0A }%0A %2F%2F Compute the new visible window%0A %2F%2F If scrollTop is specified%2C use that to determine which lines%0A %2F%2F to render instead of the current scrollbar position.%0A var visible %3D visibleLines(scrollTop)%3B%0A %2F%2F Bail out if the visible area is already rendered and nothing changed.%0A if (changes !%3D%3D true %26%26 changes.length %3D%3D 0 %26%26 visible.from > showingFrom %26%26 visible.to < showingTo) {%0A updateVerticalScroll(scrollTop)%3B%0A return%3B%0A }%0A var from %3D Math.max(visible.from - 100%2C 0)%2C to %3D Math.min(doc.size%2C visible.to %2B 100)%3B%0A if (showingFrom < from %26%26 from - showingFrom < 20) from %3D showingFrom%3B%0A if (showingTo > to %26%26 showingTo - to < 20) to %3D Math.min(doc.size%2C showingTo)%3B%0A%0A %2F%2F Create a range of theoretically intact lines%2C and punch holes%0A %2F%2F in that using the change info.%0A var intact %3D changes %3D%3D%3D true %3F [] %3A%0A computeIntact([{from%3A showingFrom%2C to%3A showingTo%2C domStart%3A 0}]%2C changes)%3B%0A %2F%2F Clip off the parts that won't be visible%0A var intactLines %3D 0%3B%0A for (var i %3D 0%3B i < intact.length%3B %2B%2Bi) {%0A var range %3D intact[i]%3B%0A if (range.from < from) {range.domStart %2B%3D (from - range.from)%3B range.from %3D from%3B}%0A if (range.to > to) range.to %3D to%3B%0A if (range.from >%3D range.to) intact.splice(i--%2C 1)%3B%0A else intactLines %2B%3D range.to - range.from%3B%0A }%0A if (intactLines %3D%3D to - from %26%26 from %3D%3D showingFrom %26%26 to %3D%3D showingTo) {%0A updateVerticalScroll(scrollTop)%3B%0A return%3B%0A }%0A intact.sort(function(a%2C b) {return a.domStart - b.domStart%3B})%3B%0A%0A var th %3D textHeight()%2C gutterDisplay %3D gutter.style.display%3B%0A lineDiv.style.display %3D "none"%3B%0A patchDisplay(from%2C to%2C intact)%3B%0A lineDiv.style.display %3D gutter.style.display %3D ""%3B%0A%0A var different %3D from !%3D showingFrom || to !%3D showingTo || lastSizeC !%3D scroller.clientHeight %2B th%3B%0A %2F%2F This is just a bogus formula that detects when the editor is%0A %2F%2F resized or the font size changes.%0A if (different) lastSizeC %3D scroller.clientHeight %2B th%3B%0A if (from !%3D showingFrom || to !%3D showingTo %26%26 options.onViewportChange)%0A setTimeout(function(){%0A if (options.onViewportChange) options.onViewportChange(instance%2C from%2C to)%3B%0A })%3B%0A showingFrom %3D from%3B showingTo %3D to%3B%0A displayOffset %3D heightAtLine(doc%2C from)%3B%0A startWorker(100)%3B%0A%0A %2F%2F Since this is all rather error prone%2C it is honoured with the%0A %2F%2F only assertion in the whole file.%0A if (lineDiv.childNodes.length !%3D showingTo - showingFrom)%0A throw new Error("BAD PATCH! " %2B JSON.stringify(intact) %2B " size%3D" %2B (showingTo - showingFrom) %2B%0A " nodes%3D" %2B lineDiv.childNodes.length)%3B%0A%0A function checkHeights() {%0A var curNode %3D lineDiv.firstChild%2C heightChanged %3D false%3B%0A doc.iter(showingFrom%2C showingTo%2C function(line) {%0A %2F%2F Work around bizarro IE7 bug where%2C sometimes%2C our curNode%0A %2F%2F is magically replaced with a new node in the DOM%2C leaving%0A %2F%2F us with a reference to an orphan (nextSibling-less) node.%0A if (!curNode) return%3B%0A if (!line.hidden) {%0A var height %3D Math.round(curNode.offsetHeight %2F th) || 1%3B%0A if (line.height !%3D height) {%0A updateLineHeight(line%2C height)%3B%0A gutterDirty %3D heightChanged %3D true%3B%0A }%0A }%0A curNode %3D curNode.nextSibling%3B%0A })%3B%0A return heightChanged%3B%0A }%0A%0A if (options.lineWrapping) checkHeights()%3B%0A%0A gutter.style.display %3D gutterDisplay%3B%0A if (different || gutterDirty) {%0A %2F%2F If the gutter grew in size%2C re-check heights. If those changed%2C re-draw gutter.%0A updateGutter() %26%26 options.lineWrapping %26%26 checkHeights() %26%26 updateGutter()%3B%0A }%0A updateVerticalScroll(scrollTop)%3B%0A updateSelection()%3B%0A if (!suppressCallback %26%26 options.onUpdate) options.onUpdate(instance)%3B%0A return true%3B%0A }%0A%0A function computeIntact(intact%2C changes) {%0A for (var i %3D 0%2C l %3D changes.length || 0%3B i < l%3B %2B%2Bi) {%0A var change %3D changes[i]%2C intact2 %3D []%2C diff %3D change.diff || 0%3B%0A for (var j %3D 0%2C l2 %3D intact.length%3B j < l2%3B %2B%2Bj) {%0A var range %3D intact[j]%3B%0A if (change.to <%3D range.from %26%26 change.diff)%0A intact2.push({from%3A range.from %2B diff%2C to%3A range.to %2B diff%2C%0A domStart%3A range.domStart})%3B%0A else if (change.to <%3D range.from || change.from >%3D range.to)%0A intact2.push(range)%3B%0A else {%0A if (change.from > range.from)%0A intact2.push({from%3A range.from%2C to%3A change.from%2C domStart%3A range.domStart})%3B%0A if (change.to < range.to)%0A intact2.push({from%3A change.to %2B diff%2C to%3A range.to %2B diff%2C%0A domStart%3A range.domStart %2B (change.to - range.from)})%3B%0A }%0A }%0A intact %3D intact2%3B%0A }%0A return intact%3B%0A }%0A%0A function patchDisplay(from%2C to%2C intact) {%0A function killNode(node) {%0A var tmp %3D node.nextSibling%3B%0A node.parentNode.removeChild(node)%3B%0A return tmp%3B%0A }%0A %2F%2F The first pass removes the DOM nodes that aren't intact.%0A if (!intact.length) removeChildren(lineDiv)%3B%0A else {%0A var domPos %3D 0%2C curNode %3D lineDiv.firstChild%2C n%3B%0A for (var i %3D 0%3B i < intact.length%3B %2B%2Bi) {%0A var cur %3D intact[i]%3B%0A while (cur.domStart > domPos) {curNode %3D killNode(curNode)%3B domPos%2B%2B%3B}%0A for (var j %3D 0%2C e %3D cur.to - cur.from%3B j < e%3B %2B%2Bj) {curNode %3D curNode.nextSibling%3B domPos%2B%2B%3B}%0A }%0A while (curNode) curNode %3D killNode(curNode)%3B%0A }%0A %2F%2F This pass fills in the lines that actually changed.%0A var nextIntact %3D intact.shift()%2C curNode %3D lineDiv.firstChild%2C j %3D from%3B%0A doc.iter(from%2C to%2C function(line) {%0A if (nextIntact %26%26 nextIntact.to %3D%3D j) nextIntact %3D intact.shift()%3B%0A if (!nextIntact || nextIntact.from > j) {%0A if (line.hidden) var lineElement %3D elt("pre")%3B%0A else {%0A var lineElement %3D lineContent(line)%3B%0A if (line.className) lineElement.className %3D line.className%3B%0A %2F%2F Kludge to make sure the styled element lies behind the selection (by z-index)%0A if (line.bgClassName) {%0A var pre %3D elt("pre"%2C "\u00a0"%2C line.bgClassName%2C "position%3A absolute%3B left%3A 0%3B right%3A 0%3B top%3A 0%3B bottom%3A 0%3B z-index%3A -2")%3B%0A lineElement %3D elt("div"%2C [pre%2C lineElement]%2C null%2C "position%3A relative")%3B%0A }%0A }%0A lineDiv.insertBefore(lineElement%2C curNode)%3B%0A } else {%0A curNode %3D curNode.nextSibling%3B%0A }%0A %2B%2Bj%3B%0A })%3B%0A }%0A%0A function updateGutter() {%0A if (!options.gutter %26%26 !options.lineNumbers) return%3B%0A var hText %3D mover.offsetHeight%2C hEditor %3D scroller.clientHeight%3B%0A gutter.style.height %3D (hText - hEditor < 2 %3F hEditor %3A hText) %2B "px"%3B%0A var fragment %3D document.createDocumentFragment()%2C i %3D showingFrom%2C normalNode%3B%0A doc.iter(showingFrom%2C Math.max(showingTo%2C showingFrom %2B 1)%2C function(line) {%0A if (line.hidden) {%0A fragment.appendChild(elt("pre"))%3B%0A } else {%0A var marker %3D line.gutterMarker%3B%0A var text %3D options.lineNumbers %3F options.lineNumberFormatter(i %2B options.firstLineNumber) %3A null%3B%0A if (marker %26%26 marker.text)%0A text %3D marker.text.replace("%25N%25"%2C text !%3D null %3F text %3A "")%3B%0A else if (text %3D%3D null)%0A text %3D "\u00a0"%3B%0A var markerElement %3D fragment.appendChild(elt("pre"%2C null%2C marker %26%26 marker.style))%3B%0A markerElement.innerHTML %3D text%3B%0A for (var j %3D 1%3B j < line.height%3B %2B%2Bj) {%0A markerElement.appendChild(elt("br"))%3B%0A markerElement.appendChild(document.createTextNode("\u00a0"))%3B%0A }%0A if (!marker) normalNode %3D i%3B%0A }%0A %2B%2Bi%3B%0A })%3B%0A gutter.style.display %3D "none"%3B%0A removeChildrenAndAdd(gutterText%2C fragment)%3B%0A %2F%2F Make sure scrolling doesn't cause number gutter size to pop%0A if (normalNode !%3D null %26%26 options.lineNumbers) {%0A var node %3D gutterText.childNodes[normalNode - showingFrom]%3B%0A var minwidth %3D String(doc.size).length%2C val %3D eltText(node.firstChild)%2C pad %3D ""%3B%0A while (val.length %2B pad.length < minwidth) pad %2B%3D "\u00a0"%3B%0A if (pad) node.insertBefore(document.createTextNode(pad)%2C node.firstChild)%3B%0A }%0A gutter.style.display %3D ""%3B%0A var resized %3D Math.abs((parseInt(lineSpace.style.marginLeft) || 0) - gutter.offsetWidth) > 2%3B%0A lineSpace.style.marginLeft %3D gutter.offsetWidth %2B "px"%3B%0A gutterDirty %3D false%3B%0A return resized%3B%0A }%0A function updateSelection() {%0A var collapsed %3D posEq(sel.from%2C sel.to)%3B%0A var fromPos %3D localCoords(sel.from%2C true)%3B%0A var toPos %3D collapsed %3F fromPos %3A localCoords(sel.to%2C true)%3B%0A var headPos %3D sel.inverted %3F fromPos %3A toPos%2C th %3D textHeight()%3B%0A var wrapOff %3D eltOffset(wrapper)%2C lineOff %3D eltOffset(lineDiv)%3B%0A inputDiv.style.top %3D Math.max(0%2C Math.min(scroller.offsetHeight%2C headPos.y %2B lineOff.top - wrapOff.top)) %2B "px"%3B%0A inputDiv.style.left %3D Math.max(0%2C Math.min(scroller.offsetWidth%2C headPos.x %2B lineOff.left - wrapOff.left)) %2B "px"%3B%0A if (collapsed) {%0A cursor.style.top %3D headPos.y %2B "px"%3B%0A cursor.style.left %3D (options.lineWrapping %3F Math.min(headPos.x%2C lineSpace.offsetWidth) %3A headPos.x) %2B "px"%3B%0A cursor.style.display %3D ""%3B%0A selectionDiv.style.display %3D "none"%3B%0A } else {%0A var sameLine %3D fromPos.y %3D%3D toPos.y%2C fragment %3D document.createDocumentFragment()%3B%0A var clientWidth %3D lineSpace.clientWidth || lineSpace.offsetWidth%3B%0A var clientHeight %3D lineSpace.clientHeight || lineSpace.offsetHeight%3B%0A var add %3D function(left%2C top%2C right%2C height) {%0A var rstyle %3D quirksMode %3F "width%3A " %2B (!right %3F clientWidth %3A clientWidth - right - left) %2B "px"%0A %3A "right%3A " %2B right %2B "px"%3B%0A fragment.appendChild(elt("div"%2C null%2C "CodeMirror-selected"%2C "position%3A absolute%3B left%3A " %2B left %2B%0A "px%3B top%3A " %2B top %2B "px%3B " %2B rstyle %2B "%3B height%3A " %2B height %2B "px"))%3B%0A }%3B%0A if (sel.from.ch %26%26 fromPos.y >%3D 0) {%0A var right %3D sameLine %3F clientWidth - toPos.x %3A 0%3B%0A add(fromPos.x%2C fromPos.y%2C right%2C th)%3B%0A }%0A var middleStart %3D Math.max(0%2C fromPos.y %2B (sel.from.ch %3F th %3A 0))%3B%0A var middleHeight %3D Math.min(toPos.y%2C clientHeight) - middleStart%3B%0A if (middleHeight > 0.2 * th)%0A add(0%2C middleStart%2C 0%2C middleHeight)%3B%0A if ((!sameLine || !sel.from.ch) %26%26 toPos.y < clientHeight - .5 * th)%0A add(0%2C toPos.y%2C clientWidth - toPos.x%2C th)%3B%0A removeChildrenAndAdd(selectionDiv%2C fragment)%3B%0A cursor.style.display %3D "none"%3B%0A selectionDiv.style.display %3D ""%3B%0A }%0A }%0A%0A function setShift(val) {%0A if (val) shiftSelecting %3D shiftSelecting || (sel.inverted %3F sel.to %3A sel.from)%3B%0A else shiftSelecting %3D null%3B%0A }%0A function setSelectionUser(from%2C to) {%0A var sh %3D shiftSelecting %26%26 clipPos(shiftSelecting)%3B%0A if (sh) {%0A if (posLess(sh%2C from)) from %3D sh%3B%0A else if (posLess(to%2C sh)) to %3D sh%3B%0A }%0A setSelection(from%2C to)%3B%0A userSelChange %3D true%3B%0A }%0A %2F%2F Update the selection. Last two args are only used by%0A %2F%2F updateLines%2C since they have to be expressed in the line%0A %2F%2F numbers before the update.%0A function setSelection(from%2C to%2C oldFrom%2C oldTo) {%0A goalColumn %3D null%3B%0A if (oldFrom %3D%3D null) {oldFrom %3D sel.from.line%3B oldTo %3D sel.to.line%3B}%0A if (posEq(sel.from%2C from) %26%26 posEq(sel.to%2C to)) return%3B%0A if (posLess(to%2C from)) {var tmp %3D to%3B to %3D from%3B from %3D tmp%3B}%0A%0A %2F%2F Skip over hidden lines.%0A if (from.line !%3D oldFrom) {%0A var from1 %3D skipHidden(from%2C oldFrom%2C sel.from.ch)%3B%0A %2F%2F If there is no non-hidden line left%2C force visibility on current line%0A if (!from1) setLineHidden(from.line%2C false)%3B%0A else from %3D from1%3B%0A }%0A if (to.line !%3D oldTo) to %3D skipHidden(to%2C oldTo%2C sel.to.ch)%3B%0A%0A if (posEq(from%2C to)) sel.inverted %3D false%3B%0A else if (posEq(from%2C sel.to)) sel.inverted %3D false%3B%0A else if (posEq(to%2C sel.from)) sel.inverted %3D true%3B%0A%0A if (options.autoClearEmptyLines %26%26 posEq(sel.from%2C sel.to)) {%0A var head %3D sel.inverted %3F from %3A to%3B%0A if (head.line !%3D sel.from.line %26%26 sel.from.line < doc.size) {%0A var oldLine %3D getLine(sel.from.line)%3B%0A if (%2F^\s%2B%24%2F.test(oldLine.text))%0A setTimeout(operation(function() {%0A if (oldLine.parent %26%26 %2F^\s%2B%24%2F.test(oldLine.text)) {%0A var no %3D lineNo(oldLine)%3B%0A replaceRange(""%2C {line%3A no%2C ch%3A 0}%2C {line%3A no%2C ch%3A oldLine.text.length})%3B%0A }%0A }%2C 10))%3B%0A }%0A }%0A%0A sel.from %3D from%3B sel.to %3D to%3B%0A selectionChanged %3D true%3B%0A }%0A function skipHidden(pos%2C oldLine%2C oldCh) {%0A function getNonHidden(dir) {%0A var lNo %3D pos.line %2B dir%2C end %3D dir %3D%3D 1 %3F doc.size %3A -1%3B%0A while (lNo !%3D end) {%0A var line %3D getLine(lNo)%3B%0A if (!line.hidden) {%0A var ch %3D pos.ch%3B%0A if (toEnd || ch > oldCh || ch > line.text.length) ch %3D line.text.length%3B%0A return {line%3A lNo%2C ch%3A ch}%3B%0A }%0A lNo %2B%3D dir%3B%0A }%0A }%0A var line %3D getLine(pos.line)%3B%0A var toEnd %3D pos.ch %3D%3D line.text.length %26%26 pos.ch !%3D oldCh%3B%0A if (!line.hidden) return pos%3B%0A if (pos.line >%3D oldLine) return getNonHidden(1) || getNonHidden(-1)%3B%0A else return getNonHidden(-1) || getNonHidden(1)%3B%0A }%0A function setCursor(line%2C ch%2C user) {%0A var pos %3D clipPos({line%3A line%2C ch%3A ch || 0})%3B%0A (user %3F setSelectionUser %3A setSelection)(pos%2C pos)%3B%0A }%0A%0A function clipLine(n) {return Math.max(0%2C Math.min(n%2C doc.size-1))%3B}%0A function clipPos(pos) {%0A if (pos.line < 0) return {line%3A 0%2C ch%3A 0}%3B%0A if (pos.line >%3D doc.size) return {line%3A doc.size-1%2C ch%3A getLine(doc.size-1).text.length}%3B%0A var ch %3D pos.ch%2C linelen %3D getLine(pos.line).text.length%3B%0A if (ch %3D%3D null || ch > linelen) return {line%3A pos.line%2C ch%3A linelen}%3B%0A else if (ch < 0) return {line%3A pos.line%2C ch%3A 0}%3B%0A else return pos%3B%0A }%0A%0A function findPosH(dir%2C unit) {%0A var end %3D sel.inverted %3F sel.from %3A sel.to%2C line %3D end.line%2C ch %3D end.ch%3B%0A var lineObj %3D getLine(line)%3B%0A function findNextLine() {%0A for (var l %3D line %2B dir%2C e %3D dir < 0 %3F -1 %3A doc.size%3B l !%3D e%3B l %2B%3D dir) {%0A var lo %3D getLine(l)%3B%0A if (!lo.hidden) { line %3D l%3B lineObj %3D lo%3B return true%3B }%0A }%0A }%0A function moveOnce(boundToLine) {%0A if (ch %3D%3D (dir < 0 %3F 0 %3A lineObj.text.length)) {%0A if (!boundToLine %26%26 findNextLine()) ch %3D dir < 0 %3F lineObj.text.length %3A 0%3B%0A else return false%3B%0A } else ch %2B%3D dir%3B%0A return true%3B%0A }%0A if (unit %3D%3D "char") moveOnce()%3B%0A else if (unit %3D%3D "column") moveOnce(true)%3B%0A else if (unit %3D%3D "word") {%0A var sawWord %3D false%3B%0A for (%3B%3B) {%0A if (dir < 0) if (!moveOnce()) break%3B%0A if (isWordChar(lineObj.text.charAt(ch))) sawWord %3D true%3B%0A else if (sawWord) {if (dir < 0) {dir %3D 1%3B moveOnce()%3B} break%3B}%0A if (dir > 0) if (!moveOnce()) break%3B%0A }%0A }%0A return {line%3A line%2C ch%3A ch}%3B%0A }%0A function moveH(dir%2C unit) {%0A var pos %3D dir < 0 %3F sel.from %3A sel.to%3B%0A if (shiftSelecting || posEq(sel.from%2C sel.to)) pos %3D findPosH(dir%2C unit)%3B%0A setCursor(pos.line%2C pos.ch%2C true)%3B%0A }%0A function deleteH(dir%2C unit) {%0A if (!posEq(sel.from%2C sel.to)) replaceRange(""%2C sel.from%2C sel.to)%3B%0A else if (dir < 0) replaceRange(""%2C findPosH(dir%2C unit)%2C sel.to)%3B%0A else replaceRange(""%2C sel.from%2C findPosH(dir%2C unit))%3B%0A userSelChange %3D true%3B%0A }%0A function moveV(dir%2C unit) {%0A var dist %3D 0%2C pos %3D localCoords(sel.inverted %3F sel.from %3A sel.to%2C true)%3B%0A if (goalColumn !%3D null) pos.x %3D goalColumn%3B%0A if (unit %3D%3D "page") {%0A var screen %3D Math.min(scroller.clientHeight%2C window.innerHeight || document.documentElement.clientHeight)%3B%0A var target %3D coordsChar(pos.x%2C pos.y %2B screen * dir)%3B%0A } else if (unit %3D%3D "line") {%0A var th %3D textHeight()%3B%0A var target %3D coordsChar(pos.x%2C pos.y %2B .5 * th %2B dir * th)%3B%0A }%0A if (unit %3D%3D "page") scrollbar.scrollTop %2B%3D localCoords(target%2C true).y - pos.y%3B%0A setCursor(target.line%2C target.ch%2C true)%3B%0A goalColumn %3D pos.x%3B%0A }%0A%0A function findWordAt(pos) {%0A var line %3D getLine(pos.line).text%3B%0A var start %3D pos.ch%2C end %3D pos.ch%3B%0A if (line) {%0A if (pos.after %3D%3D%3D false || end %3D%3D line.length) --start%3B else %2B%2Bend%3B%0A var startChar %3D line.charAt(start)%3B%0A var check %3D isWordChar(startChar) %3F isWordChar %3A%0A %2F\s%2F.test(startChar) %3F function(ch) {return %2F\s%2F.test(ch)%3B} %3A%0A function(ch) {return !%2F\s%2F.test(ch) %26%26 !isWordChar(ch)%3B}%3B%0A while (start > 0 %26%26 check(line.charAt(start - 1))) --start%3B%0A while (end < line.length %26%26 check(line.charAt(end))) %2B%2Bend%3B%0A }%0A return {from%3A {line%3A pos.line%2C ch%3A start}%2C to%3A {line%3A pos.line%2C ch%3A end}}%3B%0A }%0A function selectLine(line) {%0A setSelectionUser({line%3A line%2C ch%3A 0}%2C clipPos({line%3A line %2B 1%2C ch%3A 0}))%3B%0A }%0A function indentSelected(mode) {%0A if (posEq(sel.from%2C sel.to)) return indentLine(sel.from.line%2C mode)%3B%0A var e %3D sel.to.line - (sel.to.ch %3F 0 %3A 1)%3B%0A for (var i %3D sel.from.line%3B i <%3D e%3B %2B%2Bi) indentLine(i%2C mode)%3B%0A }%0A%0A function indentLine(n%2C how) {%0A if (!how) how %3D "add"%3B%0A if (how %3D%3D "smart") {%0A if (!mode.indent) how %3D "prev"%3B%0A else var state %3D getStateBefore(n)%3B%0A }%0A%0A var line %3D getLine(n)%2C curSpace %3D line.indentation(options.tabSize)%2C%0A curSpaceString %3D line.text.match(%2F^\s*%2F)[0]%2C indentation%3B%0A if (how %3D%3D "smart") {%0A indentation %3D mode.indent(state%2C line.text.slice(curSpaceString.length)%2C line.text)%3B%0A if (indentation %3D%3D Pass) how %3D "prev"%3B%0A }%0A if (how %3D%3D "prev") {%0A if (n) indentation %3D getLine(n-1).indentation(options.tabSize)%3B%0A else indentation %3D 0%3B%0A }%0A else if (how %3D%3D "add") indentation %3D curSpace %2B options.indentUnit%3B%0A else if (how %3D%3D "subtract") indentation %3D curSpace - options.indentUnit%3B%0A indentation %3D Math.max(0%2C indentation)%3B%0A var diff %3D indentation - curSpace%3B%0A%0A var indentString %3D ""%2C pos %3D 0%3B%0A if (options.indentWithTabs)%0A for (var i %3D Math.floor(indentation %2F options.tabSize)%3B i%3B --i) {pos %2B%3D options.tabSize%3B indentString %2B%3D "\t"%3B}%0A if (pos < indentation) indentString %2B%3D spaceStr(indentation - pos)%3B%0A%0A if (indentString !%3D curSpaceString)%0A replaceRange(indentString%2C {line%3A n%2C ch%3A 0}%2C {line%3A n%2C ch%3A curSpaceString.length})%3B%0A }%0A%0A function loadMode() {%0A mode %3D CodeMirror.getMode(options%2C options.mode)%3B%0A doc.iter(0%2C doc.size%2C function(line) { line.stateAfter %3D null%3B })%3B%0A frontier %3D 0%3B%0A startWorker(100)%3B%0A }%0A function gutterChanged() {%0A var visible %3D options.gutter || options.lineNumbers%3B%0A gutter.style.display %3D visible %3F "" %3A "none"%3B%0A if (visible) gutterDirty %3D true%3B%0A else lineDiv.parentNode.style.marginLeft %3D 0%3B%0A }%0A function wrappingChanged(from%2C to) {%0A if (options.lineWrapping) {%0A wrapper.className %2B%3D " CodeMirror-wrap"%3B%0A var perLine %3D scroller.clientWidth %2F charWidth() - 3%3B%0A doc.iter(0%2C doc.size%2C function(line) {%0A if (line.hidden) return%3B%0A var guess %3D Math.ceil(line.text.length %2F perLine) || 1%3B%0A if (guess !%3D 1) updateLineHeight(line%2C guess)%3B%0A })%3B%0A lineSpace.style.minWidth %3D widthForcer.style.left %3D ""%3B%0A } else {%0A wrapper.className %3D wrapper.className.replace(" CodeMirror-wrap"%2C "")%3B%0A computeMaxLength()%3B%0A doc.iter(0%2C doc.size%2C function(line) {%0A if (line.height !%3D 1 %26%26 !line.hidden) updateLineHeight(line%2C 1)%3B%0A })%3B%0A }%0A changes.push({from%3A 0%2C to%3A doc.size})%3B%0A }%0A function themeChanged() {%0A scroller.className %3D scroller.className.replace(%2F\s*cm-s-\S%2B%2Fg%2C "") %2B%0A options.theme.replace(%2F(^|\s)\s*%2Fg%2C " cm-s-")%3B%0A }%0A function keyMapChanged() {%0A var style %3D keyMap[options.keyMap].style%3B%0A wrapper.className %3D wrapper.className.replace(%2F\s*cm-keymap-\S%2B%2Fg%2C "") %2B%0A (style %3F " cm-keymap-" %2B style %3A "")%3B%0A }%0A%0A function TextMarker(type%2C style) { this.lines %3D []%3B this.type %3D type%3B if (style) this.style %3D style%3B }%0A TextMarker.prototype.clear %3D operation(function() {%0A var min %3D Infinity%2C max %3D -Infinity%3B%0A for (var i %3D 0%3B i < this.lines.length%3B %2B%2Bi) {%0A var line %3D this.lines[i]%3B%0A var span %3D getMarkedSpanFor(line.markedSpans%2C this%2C true)%3B%0A if (span.from !%3D null || span.to !%3D null) {%0A var lineN %3D lineNo(line)%3B%0A min %3D Math.min(min%2C lineN)%3B max %3D Math.max(max%2C lineN)%3B%0A }%0A }%0A if (min !%3D Infinity)%0A changes.push({from%3A min%2C to%3A max %2B 1})%3B%0A this.lines.length %3D 0%3B%0A })%3B%0A TextMarker.prototype.find %3D function() {%0A var from%2C to%3B%0A for (var i %3D 0%3B i < this.lines.length%3B %2B%2Bi) {%0A var line %3D this.lines[i]%3B%0A var span %3D getMarkedSpanFor(line.markedSpans%2C this)%3B%0A if (span.from !%3D null || span.to !%3D null) {%0A var found %3D lineNo(line)%3B%0A if (span.from !%3D null) from %3D {line%3A found%2C ch%3A span.from}%3B%0A if (span.to !%3D null) to %3D {line%3A found%2C ch%3A span.to}%3B%0A }%0A }%0A if (this.type %3D%3D "bookmark") return from%3B%0A return from %26%26 {from%3A from%2C to%3A to}%3B%0A }%3B%0A%0A function markText(from%2C to%2C className%2C options) {%0A from %3D clipPos(from)%3B to %3D clipPos(to)%3B%0A var marker %3D new TextMarker("range"%2C className)%3B%0A if (options) for (var opt in options) if (options.hasOwnProperty(opt))%0A marker[opt] %3D options[opt]%3B%0A var curLine %3D from.line%3B%0A doc.iter(curLine%2C to.line %2B 1%2C function(line) {%0A var span %3D {from%3A curLine %3D%3D from.line %3F from.ch %3A null%2C%0A to%3A curLine %3D%3D to.line %3F to.ch %3A null%2C%0A marker%3A marker}%3B%0A (line.markedSpans || (line.markedSpans %3D [])).push(span)%3B%0A marker.lines.push(line)%3B%0A %2B%2BcurLine%3B%0A })%3B%0A changes.push({from%3A from.line%2C to%3A to.line %2B 1})%3B%0A return marker%3B%0A }%0A%0A function setBookmark(pos) {%0A pos %3D clipPos(pos)%3B%0A var marker %3D new TextMarker("bookmark")%2C line %3D getLine(pos.line)%3B%0A var span %3D {from%3A pos.ch%2C to%3A pos.ch%2C marker%3A marker}%3B%0A (line.markedSpans || (line.markedSpans %3D [])).push(span)%3B%0A marker.lines.push(line)%3B%0A return marker%3B%0A }%0A%0A function findMarksAt(pos) {%0A pos %3D clipPos(pos)%3B%0A var markers %3D []%2C spans %3D getLine(pos.line).markedSpans%3B%0A if (spans) for (var i %3D 0%3B i < spans.length%3B %2B%2Bi) {%0A var span %3D spans[i]%3B%0A if ((span.from %3D%3D null || span.from <%3D pos.ch) %26%26%0A (span.to %3D%3D null || span.to >%3D pos.ch))%0A markers.push(span.marker)%3B%0A }%0A return markers%3B%0A }%0A%0A function addGutterMarker(line%2C text%2C className) {%0A if (typeof line %3D%3D "number") line %3D getLine(clipLine(line))%3B%0A line.gutterMarker %3D {text%3A text%2C style%3A className}%3B%0A gutterDirty %3D true%3B%0A return line%3B%0A }%0A function removeGutterMarker(line) {%0A if (typeof line %3D%3D "number") line %3D getLine(clipLine(line))%3B%0A line.gutterMarker %3D null%3B%0A gutterDirty %3D true%3B%0A }%0A%0A function changeLine(handle%2C op) {%0A var no %3D handle%2C line %3D handle%3B%0A if (typeof handle %3D%3D "number") line %3D getLine(clipLine(handle))%3B%0A else no %3D lineNo(handle)%3B%0A if (no %3D%3D null) return null%3B%0A if (op(line%2C no)) changes.push({from%3A no%2C to%3A no %2B 1})%3B%0A else return null%3B%0A return line%3B%0A }%0A function setLineClass(handle%2C className%2C bgClassName) {%0A return changeLine(handle%2C function(line) {%0A if (line.className !%3D className || line.bgClassName !%3D bgClassName) {%0A line.className %3D className%3B%0A line.bgClassName %3D bgClassName%3B%0A return true%3B%0A }%0A })%3B%0A }%0A function setLineHidden(handle%2C hidden) {%0A return changeLine(handle%2C function(line%2C no) {%0A if (line.hidden !%3D hidden) {%0A line.hidden %3D hidden%3B%0A if (!options.lineWrapping) {%0A if (hidden %26%26 line.text.length %3D%3D maxLine.text.length) {%0A updateMaxLine %3D true%3B%0A } else if (!hidden %26%26 line.text.length > maxLine.text.length) {%0A maxLine %3D line%3B updateMaxLine %3D false%3B%0A }%0A }%0A updateLineHeight(line%2C hidden %3F 0 %3A 1)%3B%0A var fline %3D sel.from.line%2C tline %3D sel.to.line%3B%0A if (hidden %26%26 (fline %3D%3D no || tline %3D%3D no)) {%0A var from %3D fline %3D%3D no %3F skipHidden({line%3A fline%2C ch%3A 0}%2C fline%2C 0) %3A sel.from%3B%0A var to %3D tline %3D%3D no %3F skipHidden({line%3A tline%2C ch%3A 0}%2C tline%2C 0) %3A sel.to%3B%0A %2F%2F Can't hide the last visible line%2C we'd have no place to put the cursor%0A if (!to) return%3B%0A setSelection(from%2C to)%3B%0A }%0A return (gutterDirty %3D true)%3B%0A }%0A })%3B%0A }%0A%0A function lineInfo(line) {%0A if (typeof line %3D%3D "number") {%0A if (!isLine(line)) return null%3B%0A var n %3D line%3B%0A line %3D getLine(line)%3B%0A if (!line) return null%3B%0A } else {%0A var n %3D lineNo(line)%3B%0A if (n %3D%3D null) return null%3B%0A }%0A var marker %3D line.gutterMarker%3B%0A return {line%3A n%2C handle%3A line%2C text%3A line.text%2C markerText%3A marker %26%26 marker.text%2C%0A markerClass%3A marker %26%26 marker.style%2C lineClass%3A line.className%2C bgClass%3A line.bgClassName}%3B%0A }%0A%0A function measureLine(line%2C ch) {%0A if (ch %3D%3D 0) return {top%3A 0%2C left%3A 0}%3B%0A var wbr %3D options.lineWrapping %26%26 ch < line.text.length %26%26%0A spanAffectsWrapping.test(line.text.slice(ch - 1%2C ch %2B 1))%3B%0A var pre %3D lineContent(line%2C ch)%3B%0A removeChildrenAndAdd(measure%2C pre)%3B%0A var anchor %3D pre.anchor%3B%0A var top %3D anchor.offsetTop%2C left %3D anchor.offsetLeft%3B%0A %2F%2F Older IEs report zero offsets for spans directly after a wrap%0A if (ie %26%26 top %3D%3D 0 %26%26 left %3D%3D 0) {%0A var backup %3D elt("span"%2C "x")%3B%0A anchor.parentNode.insertBefore(backup%2C anchor.nextSibling)%3B%0A top %3D backup.offsetTop%3B%0A }%0A return {top%3A top%2C left%3A left}%3B%0A }%0A function localCoords(pos%2C inLineWrap) {%0A var x%2C lh %3D textHeight()%2C y %3D lh * (heightAtLine(doc%2C pos.line) - (inLineWrap %3F displayOffset %3A 0))%3B%0A if (pos.ch %3D%3D 0) x %3D 0%3B%0A else {%0A var sp %3D measureLine(getLine(pos.line)%2C pos.ch)%3B%0A x %3D sp.left%3B%0A if (options.lineWrapping) y %2B%3D Math.max(0%2C sp.top)%3B%0A }%0A return {x%3A x%2C y%3A y%2C yBot%3A y %2B lh}%3B%0A }%0A %2F%2F Coords must be lineSpace-local%0A function coordsChar(x%2C y) {%0A var th %3D textHeight()%2C cw %3D charWidth()%2C heightPos %3D displayOffset %2B Math.floor(y %2F th)%3B%0A if (heightPos < 0) return {line%3A 0%2C ch%3A 0}%3B%0A var lineNo %3D lineAtHeight(doc%2C heightPos)%3B%0A if (lineNo >%3D doc.size) return {line%3A doc.size - 1%2C ch%3A getLine(doc.size - 1).text.length}%3B%0A var lineObj %3D getLine(lineNo)%2C text %3D lineObj.text%3B%0A var tw %3D options.lineWrapping%2C innerOff %3D tw %3F heightPos - heightAtLine(doc%2C lineNo) %3A 0%3B%0A if (x <%3D 0 %26%26 innerOff %3D%3D 0) return {line%3A lineNo%2C ch%3A 0}%3B%0A var wrongLine %3D false%3B%0A function getX(len) {%0A var sp %3D measureLine(lineObj%2C len)%3B%0A if (tw) {%0A var off %3D Math.round(sp.top %2F th)%3B%0A wrongLine %3D off !%3D innerOff%3B%0A return Math.max(0%2C sp.left %2B (off - innerOff) * scroller.clientWidth)%3B%0A }%0A return sp.left%3B%0A }%0A var from %3D 0%2C fromX %3D 0%2C to %3D text.length%2C toX%3B%0A %2F%2F Guess a suitable upper bound for our search.%0A var estimated %3D Math.min(to%2C Math.ceil((x %2B innerOff * scroller.clientWidth * .9) %2F cw))%3B%0A for (%3B%3B) {%0A var estX %3D getX(estimated)%3B%0A if (estX <%3D x %26%26 estimated < to) estimated %3D Math.min(to%2C Math.ceil(estimated * 1.2))%3B%0A else {toX %3D estX%3B to %3D estimated%3B break%3B}%0A }%0A if (x > toX) return {line%3A lineNo%2C ch%3A to}%3B%0A %2F%2F Try to guess a suitable lower bound as well.%0A estimated %3D Math.floor(to * 0.8)%3B estX %3D getX(estimated)%3B%0A if (estX < x) {from %3D estimated%3B fromX %3D estX%3B}%0A %2F%2F Do a binary search between these bounds.%0A for (%3B%3B) {%0A if (to - from <%3D 1) {%0A var after %3D x - fromX < toX - x%3B%0A return {line%3A lineNo%2C ch%3A after %3F from %3A to%2C after%3A after}%3B%0A }%0A var middle %3D Math.ceil((from %2B to) %2F 2)%2C middleX %3D getX(middle)%3B%0A if (middleX > x) {to %3D middle%3B toX %3D middleX%3B if (wrongLine) toX %2B%3D 1000%3B }%0A else {from %3D middle%3B fromX %3D middleX%3B}%0A }%0A }%0A function pageCoords(pos) {%0A var local %3D localCoords(pos%2C true)%2C off %3D eltOffset(lineSpace)%3B%0A return {x%3A off.left %2B local.x%2C y%3A off.top %2B local.y%2C yBot%3A off.top %2B local.yBot}%3B%0A }%0A%0A var cachedHeight%2C cachedHeightFor%2C measurePre%3B%0A function textHeight() {%0A if (measurePre %3D%3D null) {%0A measurePre %3D elt("pre")%3B%0A for (var i %3D 0%3B i < 49%3B %2B%2Bi) {%0A measurePre.appendChild(document.createTextNode("x"))%3B%0A measurePre.appendChild(elt("br"))%3B%0A }%0A measurePre.appendChild(document.createTextNode("x"))%3B%0A }%0A var offsetHeight %3D lineDiv.clientHeight%3B%0A if (offsetHeight %3D%3D cachedHeightFor) return cachedHeight%3B%0A cachedHeightFor %3D offsetHeight%3B%0A removeChildrenAndAdd(measure%2C measurePre.cloneNode(true))%3B%0A cachedHeight %3D measure.firstChild.offsetHeight %2F 50 || 1%3B%0A removeChildren(measure)%3B%0A return cachedHeight%3B%0A }%0A var cachedWidth%2C cachedWidthFor %3D 0%3B%0A function charWidth() {%0A if (scroller.clientWidth %3D%3D cachedWidthFor) return cachedWidth%3B%0A cachedWidthFor %3D scroller.clientWidth%3B%0A var anchor %3D elt("span"%2C "x")%3B%0A var pre %3D elt("pre"%2C [anchor])%3B%0A removeChildrenAndAdd(measure%2C pre)%3B%0A return (cachedWidth %3D anchor.offsetWidth || 10)%3B%0A }%0A function paddingTop() {return lineSpace.offsetTop%3B}%0A function paddingLeft() {return lineSpace.offsetLeft%3B}%0A%0A function posFromMouse(e%2C liberal) {%0A var offW %3D eltOffset(scroller%2C true)%2C x%2C y%3B%0A %2F%2F Fails unpredictably on IE[67] when mouse is dragged around quickly.%0A try { x %3D e.clientX%3B y %3D e.clientY%3B } catch (e) { return null%3B }%0A %2F%2F This is a mess of a heuristic to try and determine whether a%0A %2F%2F scroll-bar was clicked or not%2C and to return null if one was%0A %2F%2F (and !liberal).%0A if (!liberal %26%26 (x - offW.left > scroller.clientWidth || y - offW.top > scroller.clientHeight))%0A return null%3B%0A var offL %3D eltOffset(lineSpace%2C true)%3B%0A return coordsChar(x - offL.left%2C y - offL.top)%3B%0A }%0A var detectingSelectAll%3B%0A function onContextMenu(e) {%0A var pos %3D posFromMouse(e)%2C scrollPos %3D scrollbar.scrollTop%3B%0A if (!pos || opera) return%3B %2F%2F Opera is difficult.%0A if (posEq(sel.from%2C sel.to) || posLess(pos%2C sel.from) || !posLess(pos%2C sel.to))%0A operation(setCursor)(pos.line%2C pos.ch)%3B%0A%0A var oldCSS %3D input.style.cssText%3B%0A inputDiv.style.position %3D "absolute"%3B%0A input.style.cssText %3D "position%3A fixed%3B width%3A 30px%3B height%3A 30px%3B top%3A " %2B (e.clientY - 5) %2B%0A "px%3B left%3A " %2B (e.clientX - 5) %2B "px%3B z-index%3A 1000%3B background%3A white%3B " %2B%0A "border-width%3A 0%3B outline%3A none%3B overflow%3A hidden%3B opacity%3A .05%3B filter%3A alpha(opacity%3D5)%3B"%3B%0A focusInput()%3B%0A resetInput(true)%3B%0A %2F%2F Adds "Select all" to context menu in FF%0A if (posEq(sel.from%2C sel.to)) input.value %3D prevInput %3D " "%3B%0A%0A function rehide() {%0A inputDiv.style.position %3D "relative"%3B%0A input.style.cssText %3D oldCSS%3B%0A if (ie_lt9) scrollbar.scrollTop %3D scrollPos%3B%0A slowPoll()%3B%0A%0A %2F%2F Try to detect the user choosing select-all %0A if (input.selectionStart !%3D null) {%0A clearTimeout(detectingSelectAll)%3B%0A var extval %3D input.value %3D " " %2B (posEq(sel.from%2C sel.to) %3F "" %3A input.value)%2C i %3D 0%3B%0A prevInput %3D " "%3B%0A input.selectionStart %3D 1%3B input.selectionEnd %3D extval.length%3B%0A detectingSelectAll %3D setTimeout(function poll(){%0A if (prevInput %3D%3D " " %26%26 input.selectionStart %3D%3D 0)%0A operation(commands.selectAll)(instance)%3B%0A else if (i%2B%2B < 10) detectingSelectAll %3D setTimeout(poll%2C 500)%3B%0A else resetInput()%3B%0A }%2C 200)%3B%0A }%0A }%0A%0A if (gecko) {%0A e_stop(e)%3B%0A var mouseup %3D connect(window%2C "mouseup"%2C function() {%0A mouseup()%3B%0A setTimeout(rehide%2C 20)%3B%0A }%2C true)%3B%0A } else {%0A setTimeout(rehide%2C 50)%3B%0A }%0A }%0A%0A %2F%2F Cursor-blinking%0A function restartBlink() {%0A clearInterval(blinker)%3B%0A var on %3D true%3B%0A cursor.style.visibility %3D ""%3B%0A blinker %3D setInterval(function() {%0A cursor.style.visibility %3D (on %3D !on) %3F "" %3A "hidden"%3B%0A }%2C options.cursorBlinkRate)%3B%0A }%0A%0A var matching %3D {"("%3A ")>"%2C ")"%3A "(<"%2C "["%3A "]>"%2C "]"%3A "[<"%2C "{"%3A "}>"%2C "}"%3A "{<"}%3B%0A function matchBrackets(autoclear) {%0A var head %3D sel.inverted %3F sel.from %3A sel.to%2C line %3D getLine(head.line)%2C pos %3D head.ch - 1%3B%0A var match %3D (pos >%3D 0 %26%26 matching[line.text.charAt(pos)]) || matching[line.text.charAt(%2B%2Bpos)]%3B%0A if (!match) return%3B%0A var ch %3D match.charAt(0)%2C forward %3D match.charAt(1) %3D%3D ">"%2C d %3D forward %3F 1 %3A -1%2C st %3D line.styles%3B%0A for (var off %3D pos %2B 1%2C i %3D 0%2C e %3D st.length%3B i < e%3B i%2B%3D2)%0A if ((off -%3D st[i].length) <%3D 0) {var style %3D st[i%2B1]%3B break%3B}%0A%0A var stack %3D [line.text.charAt(pos)]%2C re %3D %2F[(){}[\]]%2F%3B%0A function scan(line%2C from%2C to) {%0A if (!line.text) return%3B%0A var st %3D line.styles%2C pos %3D forward %3F 0 %3A line.text.length - 1%2C cur%3B%0A for (var i %3D forward %3F 0 %3A st.length - 2%2C e %3D forward %3F st.length %3A -2%3B i !%3D e%3B i %2B%3D 2*d) {%0A var text %3D st[i]%3B%0A if (st[i%2B1] !%3D style) {pos %2B%3D d * text.length%3B continue%3B}%0A for (var j %3D forward %3F 0 %3A text.length - 1%2C te %3D forward %3F text.length %3A -1%3B j !%3D te%3B j %2B%3D d%2C pos%2B%3Dd) {%0A if (pos >%3D from %26%26 pos < to %26%26 re.test(cur %3D text.charAt(j))) {%0A var match %3D matching[cur]%3B%0A if (match.charAt(1) %3D%3D ">" %3D%3D forward) stack.push(cur)%3B%0A else if (stack.pop() !%3D match.charAt(0)) return {pos%3A pos%2C match%3A false}%3B%0A else if (!stack.length) return {pos%3A pos%2C match%3A true}%3B%0A }%0A }%0A }%0A }%0A for (var i %3D head.line%2C e %3D forward %3F Math.min(i %2B 100%2C doc.size) %3A Math.max(-1%2C i - 100)%3B i !%3D e%3B i%2B%3Dd) {%0A var line %3D getLine(i)%2C first %3D i %3D%3D head.line%3B%0A var found %3D scan(line%2C first %26%26 forward %3F pos %2B 1 %3A 0%2C first %26%26 !forward %3F pos %3A line.text.length)%3B%0A if (found) break%3B%0A }%0A if (!found) found %3D {pos%3A null%2C match%3A false}%3B%0A var style %3D found.match %3F "CodeMirror-matchingbracket" %3A "CodeMirror-nonmatchingbracket"%3B%0A var one %3D markText({line%3A head.line%2C ch%3A pos}%2C {line%3A head.line%2C ch%3A pos%2B1}%2C style)%2C%0A two %3D found.pos !%3D null %26%26 markText({line%3A i%2C ch%3A found.pos}%2C {line%3A i%2C ch%3A found.pos %2B 1}%2C style)%3B%0A var clear %3D operation(function(){one.clear()%3B two %26%26 two.clear()%3B})%3B%0A if (autoclear) setTimeout(clear%2C 800)%3B%0A else bracketHighlighted %3D clear%3B%0A }%0A%0A %2F%2F Finds the line to start with when starting a parse. Tries to%0A %2F%2F find a line with a stateAfter%2C so that it can start with a%0A %2F%2F valid state. If that fails%2C it returns the line with the%0A %2F%2F smallest indentation%2C which tends to need the least context to%0A %2F%2F parse correctly.%0A function findStartLine(n) {%0A var minindent%2C minline%3B%0A for (var search %3D n%2C lim %3D n - 40%3B search > lim%3B --search) {%0A if (search %3D%3D 0) return 0%3B%0A var line %3D getLine(search-1)%3B%0A if (line.stateAfter) return search%3B%0A var indented %3D line.indentation(options.tabSize)%3B%0A if (minline %3D%3D null || minindent > indented) {%0A minline %3D search - 1%3B%0A minindent %3D indented%3B%0A }%0A }%0A return minline%3B%0A }%0A function getStateBefore(n) {%0A var pos %3D findStartLine(n)%2C state %3D pos %26%26 getLine(pos-1).stateAfter%3B%0A if (!state) state %3D startState(mode)%3B%0A else state %3D copyState(mode%2C state)%3B%0A doc.iter(pos%2C n%2C function(line) {%0A line.process(mode%2C state%2C options.tabSize)%3B%0A line.stateAfter %3D (pos %3D%3D n - 1 || pos %25 5 %3D%3D 0) %3F copyState(mode%2C state) %3A null%3B%0A })%3B%0A return state%3B%0A }%0A function highlightWorker() {%0A if (frontier >%3D showingTo) return%3B%0A var end %3D %2Bnew Date %2B options.workTime%2C state %3D copyState(mode%2C getStateBefore(frontier))%3B%0A var startFrontier %3D frontier%3B%0A doc.iter(frontier%2C showingTo%2C function(line) {%0A if (frontier >%3D showingFrom) { %2F%2F Visible%0A line.highlight(mode%2C state%2C options.tabSize)%3B%0A line.stateAfter %3D copyState(mode%2C state)%3B%0A } else {%0A line.process(mode%2C state%2C options.tabSize)%3B%0A line.stateAfter %3D frontier %25 5 %3D%3D 0 %3F copyState(mode%2C state) %3A null%3B%0A }%0A %2B%2Bfrontier%3B%0A if (%2Bnew Date > end) {%0A startWorker(options.workDelay)%3B%0A return true%3B%0A }%0A })%3B%0A if (showingTo > startFrontier %26%26 frontier >%3D showingFrom)%0A operation(function() {changes.push({from%3A startFrontier%2C to%3A frontier})%3B})()%3B%0A }%0A function startWorker(time) {%0A if (frontier < showingTo)%0A highlight.set(time%2C highlightWorker)%3B%0A }%0A%0A %2F%2F Operations are used to wrap changes in such a way that each%0A %2F%2F change won't have to update the cursor and display (which would%0A %2F%2F be awkward%2C slow%2C and error-prone)%2C but instead updates are%0A %2F%2F batched and then all combined and executed at once.%0A function startOperation() {%0A updateInput %3D userSelChange %3D textChanged %3D null%3B%0A changes %3D []%3B selectionChanged %3D false%3B callbacks %3D []%3B%0A }%0A function endOperation() {%0A if (updateMaxLine) computeMaxLength()%3B%0A if (maxLineChanged %26%26 !options.lineWrapping) {%0A var cursorWidth %3D widthForcer.offsetWidth%2C left %3D measureLine(maxLine%2C maxLine.text.length).left%3B%0A if (!ie_lt8) {%0A widthForcer.style.left %3D left %2B "px"%3B%0A lineSpace.style.minWidth %3D (left %2B cursorWidth) %2B "px"%3B%0A }%0A maxLineChanged %3D false%3B%0A }%0A var newScrollPos%2C updated%3B%0A if (selectionChanged) {%0A var coords %3D calculateCursorCoords()%3B%0A newScrollPos %3D calculateScrollPos(coords.x%2C coords.y%2C coords.x%2C coords.yBot)%3B%0A }%0A if (changes.length || newScrollPos %26%26 newScrollPos.scrollTop !%3D null)%0A updated %3D updateDisplay(changes%2C true%2C newScrollPos %26%26 newScrollPos.scrollTop)%3B%0A if (!updated) {%0A if (selectionChanged) updateSelection()%3B%0A if (gutterDirty) updateGutter()%3B%0A }%0A if (newScrollPos) scrollCursorIntoView()%3B%0A if (selectionChanged) restartBlink()%3B%0A%0A if (focused %26%26 (updateInput %3D%3D%3D true || (updateInput !%3D%3D false %26%26 selectionChanged)))%0A resetInput(userSelChange)%3B%0A%0A if (selectionChanged %26%26 options.matchBrackets)%0A setTimeout(operation(function() {%0A if (bracketHighlighted) {bracketHighlighted()%3B bracketHighlighted %3D null%3B}%0A if (posEq(sel.from%2C sel.to)) matchBrackets(false)%3B%0A })%2C 20)%3B%0A var sc %3D selectionChanged%2C cbs %3D callbacks%3B %2F%2F these can be reset by callbacks%0A if (textChanged %26%26 options.onChange %26%26 instance)%0A options.onChange(instance%2C textChanged)%3B%0A if (sc %26%26 options.onCursorActivity)%0A options.onCursorActivity(instance)%3B%0A for (var i %3D 0%3B i < cbs.length%3B %2B%2Bi) cbs[i](instance)%3B%0A if (updated %26%26 options.onUpdate) options.onUpdate(instance)%3B%0A }%0A var nestedOperation %3D 0%3B%0A function operation(f) {%0A return function() {%0A if (!nestedOperation%2B%2B) startOperation()%3B%0A try {var result %3D f.apply(this%2C arguments)%3B}%0A finally {if (!--nestedOperation) endOperation()%3B}%0A return result%3B%0A }%3B%0A }%0A%0A function compoundChange(f) {%0A history.startCompound()%3B%0A try { return f()%3B } finally { history.endCompound()%3B }%0A }%0A%0A for (var ext in extensions)%0A if (extensions.propertyIsEnumerable(ext) %26%26%0A !instance.propertyIsEnumerable(ext))%0A instance[ext] %3D extensions[ext]%3B%0A return instance%3B%0A } %2F%2F (end of function CodeMirror)%0A%0A %2F%2F The default configuration options.%0A CodeMirror.defaults %3D {%0A value%3A ""%2C%0A mode%3A null%2C%0A theme%3A "default"%2C%0A indentUnit%3A 2%2C%0A indentWithTabs%3A false%2C%0A smartIndent%3A true%2C%0A tabSize%3A 4%2C%0A keyMap%3A "default"%2C%0A extraKeys%3A null%2C%0A electricChars%3A true%2C%0A autoClearEmptyLines%3A false%2C%0A onKeyEvent%3A null%2C%0A onDragEvent%3A null%2C%0A lineWrapping%3A false%2C%0A lineNumbers%3A false%2C%0A gutter%3A false%2C%0A fixedGutter%3A false%2C%0A firstLineNumber%3A 1%2C%0A readOnly%3A false%2C%0A dragDrop%3A true%2C%0A onChange%3A null%2C%0A onCursorActivity%3A null%2C%0A onViewportChange%3A null%2C%0A onGutterClick%3A null%2C%0A onUpdate%3A null%2C%0A onFocus%3A null%2C onBlur%3A null%2C onScroll%3A null%2C%0A matchBrackets%3A false%2C%0A cursorBlinkRate%3A 530%2C%0A workTime%3A 100%2C%0A workDelay%3A 200%2C%0A pollInterval%3A 100%2C%0A undoDepth%3A 40%2C%0A tabindex%3A null%2C%0A autofocus%3A null%2C%0A lineNumberFormatter%3A function(integer) { return integer%3B }%0A }%3B%0A%0A var ios %3D %2FAppleWebKit%2F.test(navigator.userAgent) %26%26 %2FMobile\%2F\w%2B%2F.test(navigator.userAgent)%3B%0A var mac %3D ios || %2FMac%2F.test(navigator.platform)%3B%0A var win %3D %2FWin%2F.test(navigator.platform)%3B%0A%0A %2F%2F Known modes%2C by name and by MIME%0A var modes %3D CodeMirror.modes %3D {}%2C mimeModes %3D CodeMirror.mimeModes %3D {}%3B%0A CodeMirror.defineMode %3D function(name%2C mode) {%0A if (!CodeMirror.defaults.mode %26%26 name !%3D "null") CodeMirror.defaults.mode %3D name%3B%0A if (arguments.length > 2) {%0A mode.dependencies %3D []%3B%0A for (var i %3D 2%3B i < arguments.length%3B %2B%2Bi) mode.dependencies.push(arguments[i])%3B%0A }%0A modes[name] %3D mode%3B%0A }%3B%0A CodeMirror.defineMIME %3D function(mime%2C spec) {%0A mimeModes[mime] %3D spec%3B%0A }%3B%0A CodeMirror.resolveMode %3D function(spec) {%0A if (typeof spec %3D%3D "string" %26%26 mimeModes.hasOwnProperty(spec))%0A spec %3D mimeModes[spec]%3B%0A else if (typeof spec %3D%3D "string" %26%26 %2F^[\w\-]%2B\%2F[\w\-]%2B\%2Bxml%24%2F.test(spec))%0A return CodeMirror.resolveMode("application%2Fxml")%3B%0A if (typeof spec %3D%3D "string") return {name%3A spec}%3B%0A else return spec || {name%3A "null"}%3B%0A }%3B%0A CodeMirror.getMode %3D function(options%2C spec) {%0A var spec %3D CodeMirror.resolveMode(spec)%3B%0A var mfactory %3D modes[spec.name]%3B%0A if (!mfactory) return CodeMirror.getMode(options%2C "text%2Fplain")%3B%0A var modeObj %3D mfactory(options%2C spec)%3B%0A if (modeExtensions.hasOwnProperty(spec.name)) {%0A var exts %3D modeExtensions[spec.name]%3B%0A for (var prop in exts) if (exts.hasOwnProperty(prop)) modeObj[prop] %3D exts[prop]%3B%0A }%0A modeObj.name %3D spec.name%3B%0A return modeObj%3B%0A }%3B%0A CodeMirror.listModes %3D function() {%0A var list %3D []%3B%0A for (var m in modes)%0A if (modes.propertyIsEnumerable(m)) list.push(m)%3B%0A return list%3B%0A }%3B%0A CodeMirror.listMIMEs %3D function() {%0A var list %3D []%3B%0A for (var m in mimeModes)%0A if (mimeModes.propertyIsEnumerable(m)) list.push({mime%3A m%2C mode%3A mimeModes[m]})%3B%0A return list%3B%0A }%3B%0A%0A var extensions %3D CodeMirror.extensions %3D {}%3B%0A CodeMirror.defineExtension %3D function(name%2C func) {%0A extensions[name] %3D func%3B%0A }%3B%0A%0A var modeExtensions %3D CodeMirror.modeExtensions %3D {}%3B%0A CodeMirror.extendMode %3D function(mode%2C properties) {%0A var exts %3D modeExtensions.hasOwnProperty(mode) %3F modeExtensions[mode] %3A (modeExtensions[mode] %3D {})%3B%0A for (var prop in properties) if (properties.hasOwnProperty(prop))%0A exts[prop] %3D properties[prop]%3B%0A }%3B%0A%0A var commands %3D CodeMirror.commands %3D {%0A selectAll%3A function(cm) {cm.setSelection({line%3A 0%2C ch%3A 0}%2C {line%3A cm.lineCount() - 1})%3B}%2C%0A killLine%3A function(cm) {%0A var from %3D cm.getCursor(true)%2C to %3D cm.getCursor(false)%2C sel %3D !posEq(from%2C to)%3B%0A if (!sel %26%26 cm.getLine(from.line).length %3D%3D from.ch) cm.replaceRange(""%2C from%2C {line%3A from.line %2B 1%2C ch%3A 0})%3B%0A else cm.replaceRange(""%2C from%2C sel %3F to %3A {line%3A from.line})%3B%0A }%2C%0A deleteLine%3A function(cm) {var l %3D cm.getCursor().line%3B cm.replaceRange(""%2C {line%3A l%2C ch%3A 0}%2C {line%3A l})%3B}%2C%0A undo%3A function(cm) {cm.undo()%3B}%2C%0A redo%3A function(cm) {cm.redo()%3B}%2C%0A goDocStart%3A function(cm) {cm.setCursor(0%2C 0%2C true)%3B}%2C%0A goDocEnd%3A function(cm) {cm.setSelection({line%3A cm.lineCount() - 1}%2C null%2C true)%3B}%2C%0A goLineStart%3A function(cm) {cm.setCursor(cm.getCursor().line%2C 0%2C true)%3B}%2C%0A goLineStartSmart%3A function(cm) {%0A var cur %3D cm.getCursor()%3B%0A var text %3D cm.getLine(cur.line)%2C firstNonWS %3D Math.max(0%2C text.search(%2F\S%2F))%3B%0A cm.setCursor(cur.line%2C cur.ch <%3D firstNonWS %26%26 cur.ch %3F 0 %3A firstNonWS%2C true)%3B%0A }%2C%0A goLineEnd%3A function(cm) {cm.setSelection({line%3A cm.getCursor().line}%2C null%2C true)%3B}%2C%0A goLineUp%3A function(cm) {cm.moveV(-1%2C "line")%3B}%2C%0A goLineDown%3A function(cm) {cm.moveV(1%2C "line")%3B}%2C%0A goPageUp%3A function(cm) {cm.moveV(-1%2C "page")%3B}%2C%0A goPageDown%3A function(cm) {cm.moveV(1%2C "page")%3B}%2C%0A goCharLeft%3A function(cm) {cm.moveH(-1%2C "char")%3B}%2C%0A goCharRight%3A function(cm) {cm.moveH(1%2C "char")%3B}%2C%0A goColumnLeft%3A function(cm) {cm.moveH(-1%2C "column")%3B}%2C%0A goColumnRight%3A function(cm) {cm.moveH(1%2C "column")%3B}%2C%0A goWordLeft%3A function(cm) {cm.moveH(-1%2C "word")%3B}%2C%0A goWordRight%3A function(cm) {cm.moveH(1%2C "word")%3B}%2C%0A delCharLeft%3A function(cm) {cm.deleteH(-1%2C "char")%3B}%2C%0A delCharRight%3A function(cm) {cm.deleteH(1%2C "char")%3B}%2C%0A delWordLeft%3A function(cm) {cm.deleteH(-1%2C "word")%3B}%2C%0A delWordRight%3A function(cm) {cm.deleteH(1%2C "word")%3B}%2C%0A indentAuto%3A function(cm) {cm.indentSelection("smart")%3B}%2C%0A indentMore%3A function(cm) {cm.indentSelection("add")%3B}%2C%0A indentLess%3A function(cm) {cm.indentSelection("subtract")%3B}%2C%0A insertTab%3A function(cm) {cm.replaceSelection("\t"%2C "end")%3B}%2C%0A defaultTab%3A function(cm) {%0A if (cm.somethingSelected()) cm.indentSelection("add")%3B%0A else cm.replaceSelection("\t"%2C "end")%3B%0A }%2C%0A transposeChars%3A function(cm) {%0A var cur %3D cm.getCursor()%2C line %3D cm.getLine(cur.line)%3B%0A if (cur.ch > 0 %26%26 cur.ch < line.length - 1)%0A cm.replaceRange(line.charAt(cur.ch) %2B line.charAt(cur.ch - 1)%2C%0A {line%3A cur.line%2C ch%3A cur.ch - 1}%2C {line%3A cur.line%2C ch%3A cur.ch %2B 1})%3B%0A }%2C%0A newlineAndIndent%3A function(cm) {%0A cm.replaceSelection("\n"%2C "end")%3B%0A cm.indentLine(cm.getCursor().line)%3B%0A }%2C%0A toggleOverwrite%3A function(cm) {cm.toggleOverwrite()%3B}%0A }%3B%0A%0A var keyMap %3D CodeMirror.keyMap %3D {}%3B%0A keyMap.basic %3D {%0A "Left"%3A "goCharLeft"%2C "Right"%3A "goCharRight"%2C "Up"%3A "goLineUp"%2C "Down"%3A "goLineDown"%2C%0A "End"%3A "goLineEnd"%2C "Home"%3A "goLineStartSmart"%2C "PageUp"%3A "goPageUp"%2C "PageDown"%3A "goPageDown"%2C%0A "Delete"%3A "delCharRight"%2C "Backspace"%3A "delCharLeft"%2C "Tab"%3A "defaultTab"%2C "Shift-Tab"%3A "indentAuto"%2C%0A "Enter"%3A "newlineAndIndent"%2C "Insert"%3A "toggleOverwrite"%0A }%3B%0A %2F%2F Note that the save and find-related commands aren't defined by%0A %2F%2F default. Unknown commands are simply ignored.%0A keyMap.pcDefault %3D {%0A "Ctrl-A"%3A "selectAll"%2C "Ctrl-D"%3A "deleteLine"%2C "Ctrl-Z"%3A "undo"%2C "Shift-Ctrl-Z"%3A "redo"%2C "Ctrl-Y"%3A "redo"%2C%0A "Ctrl-Home"%3A "goDocStart"%2C "Alt-Up"%3A "goDocStart"%2C "Ctrl-End"%3A "goDocEnd"%2C "Ctrl-Down"%3A "goDocEnd"%2C%0A "Ctrl-Left"%3A "goWordLeft"%2C "Ctrl-Right"%3A "goWordRight"%2C "Alt-Left"%3A "goLineStart"%2C "Alt-Right"%3A "goLineEnd"%2C%0A "Ctrl-Backspace"%3A "delWordLeft"%2C "Ctrl-Delete"%3A "delWordRight"%2C "Ctrl-S"%3A "save"%2C "Ctrl-F"%3A "find"%2C%0A "Ctrl-G"%3A "findNext"%2C "Shift-Ctrl-G"%3A "findPrev"%2C "Shift-Ctrl-F"%3A "replace"%2C "Shift-Ctrl-R"%3A "replaceAll"%2C%0A "Ctrl-["%3A "indentLess"%2C "Ctrl-]"%3A "indentMore"%2C%0A fallthrough%3A "basic"%0A }%3B%0A keyMap.macDefault %3D {%0A "Cmd-A"%3A "selectAll"%2C "Cmd-D"%3A "deleteLine"%2C "Cmd-Z"%3A "undo"%2C "Shift-Cmd-Z"%3A "redo"%2C "Cmd-Y"%3A "redo"%2C%0A "Cmd-Up"%3A "goDocStart"%2C "Cmd-End"%3A "goDocEnd"%2C "Cmd-Down"%3A "goDocEnd"%2C "Alt-Left"%3A "goWordLeft"%2C%0A "Alt-Right"%3A "goWordRight"%2C "Cmd-Left"%3A "goLineStart"%2C "Cmd-Right"%3A "goLineEnd"%2C "Alt-Backspace"%3A "delWordLeft"%2C%0A "Ctrl-Alt-Backspace"%3A "delWordRight"%2C "Alt-Delete"%3A "delWordRight"%2C "Cmd-S"%3A "save"%2C "Cmd-F"%3A "find"%2C%0A "Cmd-G"%3A "findNext"%2C "Shift-Cmd-G"%3A "findPrev"%2C "F"%3A "replace"%2C "Shift-Cmd-Alt-F"%3A "replaceAll"%2C%0A "Cmd-["%3A "indentLess"%2C "Cmd-]"%3A "indentMore"%2C%0A fallthrough%3A ["basic"%2C "emacsy"]%0A }%3B%0A keyMap["default"] %3D mac %3F keyMap.macDefault %3A keyMap.pcDefault%3B%0A keyMap.emacsy %3D {%0A "Ctrl-F"%3A "goCharRight"%2C "Ctrl-B"%3A "goCharLeft"%2C "Ctrl-P"%3A "goLineUp"%2C "Ctrl-N"%3A "goLineDown"%2C%0A "Alt-F"%3A "goWordRight"%2C "Alt-B"%3A "goWordLeft"%2C "Ctrl-A"%3A "goLineStart"%2C "Ctrl-E"%3A "goLineEnd"%2C%0A "Ctrl-V"%3A "goPageUp"%2C "Shift-Ctrl-V"%3A "goPageDown"%2C "Ctrl-D"%3A "delCharRight"%2C "Ctrl-H"%3A "delCharLeft"%2C%0A "Alt-D"%3A "delWordRight"%2C "Alt-Backspace"%3A "delWordLeft"%2C "Ctrl-K"%3A "killLine"%2C "Ctrl-T"%3A "transposeChars"%0A }%3B%0A%0A function getKeyMap(val) {%0A if (typeof val %3D%3D "string") return keyMap[val]%3B%0A else return val%3B%0A }%0A function lookupKey(name%2C extraMap%2C map%2C handle%2C stop) {%0A function lookup(map) {%0A map %3D getKeyMap(map)%3B%0A var found %3D map[name]%3B%0A if (found %3D%3D%3D false) {%0A if (stop) stop()%3B%0A return true%3B%0A }%0A if (found !%3D null %26%26 handle(found)) return true%3B%0A if (map.nofallthrough) {%0A if (stop) stop()%3B%0A return true%3B%0A }%0A var fallthrough %3D map.fallthrough%3B%0A if (fallthrough %3D%3D null) return false%3B%0A if (Object.prototype.toString.call(fallthrough) !%3D "[object Array]")%0A return lookup(fallthrough)%3B%0A for (var i %3D 0%2C e %3D fallthrough.length%3B i < e%3B %2B%2Bi) {%0A if (lookup(fallthrough[i])) return true%3B%0A }%0A return false%3B%0A }%0A if (extraMap %26%26 lookup(extraMap)) return true%3B%0A return lookup(map)%3B%0A }%0A function isModifierKey(event) {%0A var name %3D keyNames[e_prop(event%2C "keyCode")]%3B%0A return name %3D%3D "Ctrl" || name %3D%3D "Alt" || name %3D%3D "Shift" || name %3D%3D "Mod"%3B%0A }%0A%0A CodeMirror.fromTextArea %3D function(textarea%2C options) {%0A if (!options) options %3D {}%3B%0A options.value %3D textarea.value%3B%0A if (!options.tabindex %26%26 textarea.tabindex)%0A options.tabindex %3D textarea.tabindex%3B%0A %2F%2F Set autofocus to true if this textarea is focused%2C or if it has%0A %2F%2F autofocus and no other element is focused.%0A if (options.autofocus %3D%3D null) {%0A var hasFocus %3D document.body%3B%0A %2F%2F doc.activeElement occasionally throws on IE%0A try { hasFocus %3D document.activeElement%3B } catch(e) {}%0A options.autofocus %3D hasFocus %3D%3D textarea ||%0A textarea.getAttribute("autofocus") !%3D null %26%26 hasFocus %3D%3D document.body%3B%0A }%0A%0A function save() {textarea.value %3D instance.getValue()%3B}%0A if (textarea.form) {%0A %2F%2F Deplorable hack to make the submit method do the right thing.%0A var rmSubmit %3D connect(textarea.form%2C "submit"%2C save%2C true)%3B%0A if (typeof textarea.form.submit %3D%3D "function") {%0A var realSubmit %3D textarea.form.submit%3B%0A textarea.form.submit %3D function wrappedSubmit() {%0A save()%3B%0A textarea.form.submit %3D realSubmit%3B%0A textarea.form.submit()%3B%0A textarea.form.submit %3D wrappedSubmit%3B%0A }%3B%0A }%0A }%0A%0A textarea.style.display %3D "none"%3B%0A var instance %3D CodeMirror(function(node) {%0A textarea.parentNode.insertBefore(node%2C textarea.nextSibling)%3B%0A }%2C options)%3B%0A instance.save %3D save%3B%0A instance.getTextArea %3D function() { return textarea%3B }%3B%0A instance.toTextArea %3D function() {%0A save()%3B%0A textarea.parentNode.removeChild(instance.getWrapperElement())%3B%0A textarea.style.display %3D ""%3B%0A if (textarea.form) {%0A rmSubmit()%3B%0A if (typeof textarea.form.submit %3D%3D "function")%0A textarea.form.submit %3D realSubmit%3B%0A }%0A }%3B%0A return instance%3B%0A }%3B%0A%0A var gecko %3D %2Fgecko\%2F\d{7}%2Fi.test(navigator.userAgent)%3B%0A var ie %3D %2FMSIE \d%2F.test(navigator.userAgent)%3B%0A var ie_lt8 %3D %2FMSIE [1-7]\b%2F.test(navigator.userAgent)%3B%0A var ie_lt9 %3D %2FMSIE [1-8]\b%2F.test(navigator.userAgent)%3B%0A var quirksMode %3D ie %26%26 document.documentMode %3D%3D 5%3B%0A var webkit %3D %2FWebKit\%2F%2F.test(navigator.userAgent)%3B%0A var chrome %3D %2FChrome\%2F%2F.test(navigator.userAgent)%3B%0A var opera %3D %2FOpera\%2F%2F.test(navigator.userAgent)%3B%0A var safari %3D %2FApple Computer%2F.test(navigator.vendor)%3B%0A var khtml %3D %2FKHTML\%2F%2F.test(navigator.userAgent)%3B%0A var mac_geLion %3D %2FMac OS X 10\D([7-9]|\d\d)\D%2F.test(navigator.userAgent)%3B%0A%0A %2F%2F Utility functions for working with state. Exported because modes%0A %2F%2F sometimes need to do this.%0A function copyState(mode%2C state) {%0A if (state %3D%3D%3D true) return state%3B%0A if (mode.copyState) return mode.copyState(state)%3B%0A var nstate %3D {}%3B%0A for (var n in state) {%0A var val %3D state[n]%3B%0A if (val instanceof Array) val %3D val.concat([])%3B%0A nstate[n] %3D val%3B%0A }%0A return nstate%3B%0A }%0A CodeMirror.copyState %3D copyState%3B%0A function startState(mode%2C a1%2C a2) {%0A return mode.startState %3F mode.startState(a1%2C a2) %3A true%3B%0A }%0A CodeMirror.startState %3D startState%3B%0A CodeMirror.innerMode %3D function(mode%2C state) {%0A while (mode.innerMode) {%0A var info %3D mode.innerMode(state)%3B%0A state %3D info.state%3B%0A mode %3D info.mode%3B%0A }%0A return info || {mode%3A mode%2C state%3A state}%3B%0A }%3B%0A%0A %2F%2F The character stream used by a mode's parser.%0A function StringStream(string%2C tabSize) {%0A this.pos %3D this.start %3D 0%3B%0A this.string %3D string%3B%0A this.tabSize %3D tabSize || 8%3B%0A }%0A StringStream.prototype %3D {%0A eol%3A function() {return this.pos >%3D this.string.length%3B}%2C%0A sol%3A function() {return this.pos %3D%3D 0%3B}%2C%0A peek%3A function() {return this.string.charAt(this.pos) || undefined%3B}%2C%0A next%3A function() {%0A if (this.pos < this.string.length)%0A return this.string.charAt(this.pos%2B%2B)%3B%0A }%2C%0A eat%3A function(match) {%0A var ch %3D this.string.charAt(this.pos)%3B%0A if (typeof match %3D%3D "string") var ok %3D ch %3D%3D match%3B%0A else var ok %3D ch %26%26 (match.test %3F match.test(ch) %3A match(ch))%3B%0A if (ok) {%2B%2Bthis.pos%3B return ch%3B}%0A }%2C%0A eatWhile%3A function(match) {%0A var start %3D this.pos%3B%0A while (this.eat(match)){}%0A return this.pos > start%3B%0A }%2C%0A eatSpace%3A function() {%0A var start %3D this.pos%3B%0A while (%2F[\s\u00a0]%2F.test(this.string.charAt(this.pos))) %2B%2Bthis.pos%3B%0A return this.pos > start%3B%0A }%2C%0A skipToEnd%3A function() {this.pos %3D this.string.length%3B}%2C%0A skipTo%3A function(ch) {%0A var found %3D this.string.indexOf(ch%2C this.pos)%3B%0A if (found > -1) {this.pos %3D found%3B return true%3B}%0A }%2C%0A backUp%3A function(n) {this.pos -%3D n%3B}%2C%0A column%3A function() {return countColumn(this.string%2C this.start%2C this.tabSize)%3B}%2C%0A indentation%3A function() {return countColumn(this.string%2C null%2C this.tabSize)%3B}%2C%0A match%3A function(pattern%2C consume%2C caseInsensitive) {%0A if (typeof pattern %3D%3D "string") {%0A var cased %3D function(str) {return caseInsensitive %3F str.toLowerCase() %3A str%3B}%3B%0A if (cased(this.string).indexOf(cased(pattern)%2C this.pos) %3D%3D this.pos) {%0A if (consume !%3D%3D false) this.pos %2B%3D pattern.length%3B%0A return true%3B%0A }%0A } else {%0A var match %3D this.string.slice(this.pos).match(pattern)%3B%0A if (match %26%26 match.index > 0) return null%3B%0A if (match %26%26 consume !%3D%3D false) this.pos %2B%3D match[0].length%3B%0A return match%3B%0A }%0A }%2C%0A current%3A function(){return this.string.slice(this.start%2C this.pos)%3B}%0A }%3B%0A CodeMirror.StringStream %3D StringStream%3B%0A%0A function MarkedSpan(from%2C to%2C marker) {%0A this.from %3D from%3B this.to %3D to%3B this.marker %3D marker%3B%0A }%0A%0A function getMarkedSpanFor(spans%2C marker%2C del) {%0A if (spans) for (var i %3D 0%3B i < spans.length%3B %2B%2Bi) {%0A var span %3D spans[i]%3B%0A if (span.marker %3D%3D marker) {%0A if (del) spans.splice(i%2C 1)%3B%0A return span%3B%0A }%0A }%0A }%0A%0A function markedSpansBefore(old%2C startCh%2C endCh) {%0A if (old) for (var i %3D 0%2C nw%3B i < old.length%3B %2B%2Bi) {%0A var span %3D old[i]%2C marker %3D span.marker%3B%0A var startsBefore %3D span.from %3D%3D null || (marker.inclusiveLeft %3F span.from <%3D startCh %3A span.from < startCh)%3B%0A if (startsBefore || marker.type %3D%3D "bookmark" %26%26 span.from %3D%3D startCh %26%26 span.from !%3D endCh) {%0A var endsAfter %3D span.to %3D%3D null || (marker.inclusiveRight %3F span.to >%3D startCh %3A span.to > startCh)%3B%0A (nw || (nw %3D [])).push({from%3A span.from%2C%0A to%3A endsAfter %3F null %3A span.to%2C%0A marker%3A marker})%3B%0A }%0A }%0A return nw%3B%0A }%0A%0A function markedSpansAfter(old%2C endCh) {%0A if (old) for (var i %3D 0%2C nw%3B i < old.length%3B %2B%2Bi) {%0A var span %3D old[i]%2C marker %3D span.marker%3B%0A var endsAfter %3D span.to %3D%3D null || (marker.inclusiveRight %3F span.to >%3D endCh %3A span.to > endCh)%3B%0A if (endsAfter || marker.type %3D%3D "bookmark" %26%26 span.from %3D%3D endCh) {%0A var startsBefore %3D span.from %3D%3D null || (marker.inclusiveLeft %3F span.from <%3D endCh %3A span.from < endCh)%3B%0A (nw || (nw %3D [])).push({from%3A startsBefore %3F null %3A span.from - endCh%2C%0A to%3A span.to %3D%3D null %3F null %3A span.to - endCh%2C%0A marker%3A marker})%3B%0A }%0A }%0A return nw%3B%0A }%0A%0A function updateMarkedSpans(oldFirst%2C oldLast%2C startCh%2C endCh%2C newText) {%0A if (!oldFirst %26%26 !oldLast) return newText%3B%0A %2F%2F Get the spans that 'stick out' on both sides%0A var first %3D markedSpansBefore(oldFirst%2C startCh)%3B%0A var last %3D markedSpansAfter(oldLast%2C endCh)%3B%0A%0A %2F%2F Next%2C merge those two ends%0A var sameLine %3D newText.length %3D%3D 1%2C offset %3D lst(newText).length %2B (sameLine %3F startCh %3A 0)%3B%0A if (first) {%0A %2F%2F Fix up .to properties of first%0A for (var i %3D 0%3B i < first.length%3B %2B%2Bi) {%0A var span %3D first[i]%3B%0A if (span.to %3D%3D null) {%0A var found %3D getMarkedSpanFor(last%2C span.marker)%3B%0A if (!found) span.to %3D startCh%3B%0A else if (sameLine) span.to %3D found.to %3D%3D null %3F null %3A found.to %2B offset%3B%0A }%0A }%0A }%0A if (last) {%0A %2F%2F Fix up .from in last (or move them into first in case of sameLine)%0A for (var i %3D 0%3B i < last.length%3B %2B%2Bi) {%0A var span %3D last[i]%3B%0A if (span.to !%3D null) span.to %2B%3D offset%3B%0A if (span.from %3D%3D null) {%0A var found %3D getMarkedSpanFor(first%2C span.marker)%3B%0A if (!found) {%0A span.from %3D offset%3B%0A if (sameLine) (first || (first %3D [])).push(span)%3B%0A }%0A } else {%0A span.from %2B%3D offset%3B%0A if (sameLine) (first || (first %3D [])).push(span)%3B%0A }%0A }%0A }%0A%0A var newMarkers %3D [newHL(newText[0]%2C first)]%3B%0A if (!sameLine) {%0A %2F%2F Fill gap with whole-line-spans%0A var gap %3D newText.length - 2%2C gapMarkers%3B%0A if (gap > 0 %26%26 first)%0A for (var i %3D 0%3B i < first.length%3B %2B%2Bi)%0A if (first[i].to %3D%3D null)%0A (gapMarkers || (gapMarkers %3D [])).push({from%3A null%2C to%3A null%2C marker%3A first[i].marker})%3B%0A for (var i %3D 0%3B i < gap%3B %2B%2Bi)%0A newMarkers.push(newHL(newText[i%2B1]%2C gapMarkers))%3B%0A newMarkers.push(newHL(lst(newText)%2C last))%3B%0A }%0A return newMarkers%3B%0A }%0A%0A %2F%2F hl stands for history-line%2C a data structure that can be either a%0A %2F%2F string (line without markers) or a {text%2C markedSpans} object.%0A function hlText(val) { return typeof val %3D%3D "string" %3F val %3A val.text%3B }%0A function hlSpans(val) { return typeof val %3D%3D "string" %3F null %3A val.markedSpans%3B }%0A function newHL(text%2C spans) { return spans %3F {text%3A text%2C markedSpans%3A spans} %3A text%3B }%0A%0A function detachMarkedSpans(line) {%0A var spans %3D line.markedSpans%3B%0A if (!spans) return%3B%0A for (var i %3D 0%3B i < spans.length%3B %2B%2Bi) {%0A var lines %3D spans[i].marker.lines%3B%0A var ix %3D indexOf(lines%2C line)%3B%0A lines.splice(ix%2C 1)%3B%0A }%0A line.markedSpans %3D null%3B%0A }%0A%0A function attachMarkedSpans(line%2C spans) {%0A if (!spans) return%3B%0A for (var i %3D 0%3B i < spans.length%3B %2B%2Bi)%0A var marker %3D spans[i].marker.lines.push(line)%3B%0A line.markedSpans %3D spans%3B%0A }%0A%0A %2F%2F When measuring the position of the end of a line%2C different%0A %2F%2F browsers require different approaches. If an empty span is added%2C%0A %2F%2F many browsers report bogus offsets. Of those%2C some (Webkit%2C%0A %2F%2F recent IE) will accept a space without moving the whole span to%0A %2F%2F the next line when wrapping it%2C others work with a zero-width%0A %2F%2F space.%0A var eolSpanContent %3D " "%3B%0A if (gecko || (ie %26%26 !ie_lt8)) eolSpanContent %3D "\u200b"%3B%0A else if (opera) eolSpanContent %3D ""%3B%0A%0A %2F%2F Line objects. These hold state related to a line%2C including%0A %2F%2F highlighting info (the styles array).%0A function Line(text%2C markedSpans) {%0A this.text %3D text%3B%0A this.height %3D 1%3B%0A attachMarkedSpans(this%2C markedSpans)%3B%0A }%0A Line.prototype %3D {%0A update%3A function(text%2C markedSpans) {%0A this.text %3D text%3B%0A this.stateAfter %3D this.styles %3D null%3B%0A detachMarkedSpans(this)%3B%0A attachMarkedSpans(this%2C markedSpans)%3B%0A }%2C%0A %2F%2F Run the given mode's parser over a line%2C update the styles%0A %2F%2F array%2C which contains alternating fragments of text and CSS%0A %2F%2F classes.%0A highlight%3A function(mode%2C state%2C tabSize) {%0A var stream %3D new StringStream(this.text%2C tabSize)%2C st %3D this.styles || (this.styles %3D [])%3B%0A var pos %3D st.length %3D 0%3B%0A if (this.text %3D%3D "" %26%26 mode.blankLine) mode.blankLine(state)%3B%0A while (!stream.eol()) {%0A var style %3D mode.token(stream%2C state)%2C substr %3D stream.current()%3B%0A stream.start %3D stream.pos%3B%0A if (pos %26%26 st[pos-1] %3D%3D style) {%0A st[pos-2] %2B%3D substr%3B%0A } else if (substr) {%0A st[pos%2B%2B] %3D substr%3B st[pos%2B%2B] %3D style%3B%0A }%0A %2F%2F Give up when line is ridiculously long%0A if (stream.pos > 5000) {%0A st[pos%2B%2B] %3D this.text.slice(stream.pos)%3B st[pos%2B%2B] %3D null%3B%0A break%3B%0A }%0A }%0A }%2C%0A process%3A function(mode%2C state%2C tabSize) {%0A var stream %3D new StringStream(this.text%2C tabSize)%3B%0A if (this.text %3D%3D "" %26%26 mode.blankLine) mode.blankLine(state)%3B%0A while (!stream.eol() %26%26 stream.pos <%3D 5000) {%0A mode.token(stream%2C state)%3B%0A stream.start %3D stream.pos%3B%0A }%0A }%2C%0A %2F%2F Fetch the parser token for a given character. Useful for hacks%0A %2F%2F that want to inspect the mode state (say%2C for completion).%0A getTokenAt%3A function(mode%2C state%2C tabSize%2C ch) {%0A var txt %3D this.text%2C stream %3D new StringStream(txt%2C tabSize)%3B%0A while (stream.pos < ch %26%26 !stream.eol()) {%0A stream.start %3D stream.pos%3B%0A var style %3D mode.token(stream%2C state)%3B%0A }%0A return {start%3A stream.start%2C%0A end%3A stream.pos%2C%0A string%3A stream.current()%2C%0A className%3A style || null%2C%0A state%3A state}%3B%0A }%2C%0A indentation%3A function(tabSize) {return countColumn(this.text%2C null%2C tabSize)%3B}%2C%0A %2F%2F Produces an HTML fragment for the line%2C taking selection%2C%0A %2F%2F marking%2C and highlighting into account.%0A getContent%3A function(tabSize%2C wrapAt%2C compensateForWrapping) {%0A var first %3D true%2C col %3D 0%2C specials %3D %2F[\t\u0000-\u0019\u200b\u2028\u2029\uFEFF]%2Fg%3B%0A var pre %3D elt("pre")%3B%0A function span_(html%2C text%2C style) {%0A if (!text) return%3B%0A %2F%2F Work around a bug where%2C in some compat modes%2C IE ignores leading spaces%0A if (first %26%26 ie %26%26 text.charAt(0) %3D%3D " ") text %3D "\u00a0" %2B text.slice(1)%3B%0A first %3D false%3B%0A if (!specials.test(text)) {%0A col %2B%3D text.length%3B%0A var content %3D document.createTextNode(text)%3B%0A } else {%0A var content %3D document.createDocumentFragment()%2C pos %3D 0%3B%0A while (true) {%0A specials.lastIndex %3D pos%3B%0A var m %3D specials.exec(text)%3B%0A var skipped %3D m %3F m.index - pos %3A text.length - pos%3B%0A if (skipped) {%0A content.appendChild(document.createTextNode(text.slice(pos%2C pos %2B skipped)))%3B%0A col %2B%3D skipped%3B%0A }%0A if (!m) break%3B%0A pos %2B%3D skipped %2B 1%3B%0A if (m[0] %3D%3D "\t") {%0A var tabWidth %3D tabSize - col %25 tabSize%3B%0A content.appendChild(elt("span"%2C spaceStr(tabWidth)%2C "cm-tab"))%3B%0A col %2B%3D tabWidth%3B%0A } else {%0A var token %3D elt("span"%2C "\u2022"%2C "cm-invalidchar")%3B%0A token.title %3D "\\u" %2B m[0].charCodeAt(0).toString(16)%3B%0A content.appendChild(token)%3B%0A col %2B%3D 1%3B%0A }%0A }%0A }%0A if (style) html.appendChild(elt("span"%2C [content]%2C style))%3B%0A else html.appendChild(content)%3B%0A }%0A var span %3D span_%3B%0A if (wrapAt !%3D null) {%0A var outPos %3D 0%2C anchor %3D pre.anchor %3D elt("span")%3B%0A span %3D function(html%2C text%2C style) {%0A var l %3D text.length%3B%0A if (wrapAt >%3D outPos %26%26 wrapAt < outPos %2B l) {%0A if (wrapAt > outPos) {%0A span_(html%2C text.slice(0%2C wrapAt - outPos)%2C style)%3B%0A %2F%2F See comment at the definition of spanAffectsWrapping%0A if (compensateForWrapping) html.appendChild(elt("wbr"))%3B%0A }%0A html.appendChild(anchor)%3B%0A var cut %3D wrapAt - outPos%3B%0A span_(anchor%2C opera %3F text.slice(cut%2C cut %2B 1) %3A text.slice(cut)%2C style)%3B%0A if (opera) span_(html%2C text.slice(cut %2B 1)%2C style)%3B%0A wrapAt--%3B%0A outPos %2B%3D l%3B%0A } else {%0A outPos %2B%3D l%3B%0A span_(html%2C text%2C style)%3B%0A if (outPos %3D%3D wrapAt %26%26 outPos %3D%3D len) {%0A setTextContent(anchor%2C eolSpanContent)%3B%0A html.appendChild(anchor)%3B%0A }%0A %2F%2F Stop outputting HTML when gone sufficiently far beyond measure%0A else if (outPos > wrapAt %2B 10 %26%26 %2F\s%2F.test(text)) span %3D function(){}%3B%0A }%0A }%3B%0A }%0A%0A var st %3D this.styles%2C allText %3D this.text%2C marked %3D this.markedSpans%3B%0A var len %3D allText.length%3B%0A function styleToClass(style) {%0A if (!style) return null%3B%0A return "cm-" %2B style.replace(%2F %2B%2Fg%2C " cm-")%3B%0A }%0A if (!allText %26%26 wrapAt %3D%3D null) {%0A span(pre%2C " ")%3B%0A } else if (!marked || !marked.length) {%0A for (var i %3D 0%2C ch %3D 0%3B ch < len%3B i%2B%3D2) {%0A var str %3D st[i]%2C style %3D st[i%2B1]%2C l %3D str.length%3B%0A if (ch %2B l > len) str %3D str.slice(0%2C len - ch)%3B%0A ch %2B%3D l%3B%0A span(pre%2C str%2C styleToClass(style))%3B%0A }%0A } else {%0A marked.sort(function(a%2C b) { return a.from - b.from%3B })%3B%0A var pos %3D 0%2C i %3D 0%2C text %3D ""%2C style%2C sg %3D 0%3B%0A var nextChange %3D marked[0].from || 0%2C marks %3D []%2C markpos %3D 0%3B%0A var advanceMarks %3D function() {%0A var m%3B%0A while (markpos < marked.length %26%26%0A ((m %3D marked[markpos]).from %3D%3D pos || m.from %3D%3D null)) {%0A if (m.marker.type %3D%3D "range") marks.push(m)%3B%0A %2B%2Bmarkpos%3B%0A }%0A nextChange %3D markpos < marked.length %3F marked[markpos].from %3A Infinity%3B%0A for (var i %3D 0%3B i < marks.length%3B %2B%2Bi) {%0A var to %3D marks[i].to%3B%0A if (to %3D%3D null) to %3D Infinity%3B%0A if (to %3D%3D pos) marks.splice(i--%2C 1)%3B%0A else nextChange %3D Math.min(to%2C nextChange)%3B%0A }%0A }%3B%0A var m %3D 0%3B%0A while (pos < len) {%0A if (nextChange %3D%3D pos) advanceMarks()%3B%0A var upto %3D Math.min(len%2C nextChange)%3B%0A while (true) {%0A if (text) {%0A var end %3D pos %2B text.length%3B%0A var appliedStyle %3D style%3B%0A for (var j %3D 0%3B j < marks.length%3B %2B%2Bj) {%0A var mark %3D marks[j]%3B%0A appliedStyle %3D (appliedStyle %3F appliedStyle %2B " " %3A "") %2B mark.marker.style%3B%0A if (mark.marker.endStyle %26%26 mark.to %3D%3D%3D Math.min(end%2C upto)) appliedStyle %2B%3D " " %2B mark.marker.endStyle%3B%0A if (mark.marker.startStyle %26%26 mark.from %3D%3D%3D pos) appliedStyle %2B%3D " " %2B mark.marker.startStyle%3B%0A }%0A span(pre%2C end > upto %3F text.slice(0%2C upto - pos) %3A text%2C appliedStyle)%3B%0A if (end >%3D upto) {text %3D text.slice(upto - pos)%3B pos %3D upto%3B break%3B}%0A pos %3D end%3B%0A }%0A text %3D st[i%2B%2B]%3B style %3D styleToClass(st[i%2B%2B])%3B%0A }%0A }%0A }%0A return pre%3B%0A }%2C%0A cleanUp%3A function() {%0A this.parent %3D null%3B%0A detachMarkedSpans(this)%3B%0A }%0A }%3B%0A%0A %2F%2F Data structure that holds the sequence of lines.%0A function LeafChunk(lines) {%0A this.lines %3D lines%3B%0A this.parent %3D null%3B%0A for (var i %3D 0%2C e %3D lines.length%2C height %3D 0%3B i < e%3B %2B%2Bi) {%0A lines[i].parent %3D this%3B%0A height %2B%3D lines[i].height%3B%0A }%0A this.height %3D height%3B%0A }%0A LeafChunk.prototype %3D {%0A chunkSize%3A function() { return this.lines.length%3B }%2C%0A remove%3A function(at%2C n%2C callbacks) {%0A for (var i %3D at%2C e %3D at %2B n%3B i < e%3B %2B%2Bi) {%0A var line %3D this.lines[i]%3B%0A this.height -%3D line.height%3B%0A line.cleanUp()%3B%0A if (line.handlers)%0A for (var j %3D 0%3B j < line.handlers.length%3B %2B%2Bj) callbacks.push(line.handlers[j])%3B%0A }%0A this.lines.splice(at%2C n)%3B%0A }%2C%0A collapse%3A function(lines) {%0A lines.splice.apply(lines%2C [lines.length%2C 0].concat(this.lines))%3B%0A }%2C%0A insertHeight%3A function(at%2C lines%2C height) {%0A this.height %2B%3D height%3B%0A this.lines %3D this.lines.slice(0%2C at).concat(lines).concat(this.lines.slice(at))%3B%0A for (var i %3D 0%2C e %3D lines.length%3B i < e%3B %2B%2Bi) lines[i].parent %3D this%3B%0A }%2C%0A iterN%3A function(at%2C n%2C op) {%0A for (var e %3D at %2B n%3B at < e%3B %2B%2Bat)%0A if (op(this.lines[at])) return true%3B%0A }%0A }%3B%0A function BranchChunk(children) {%0A this.children %3D children%3B%0A var size %3D 0%2C height %3D 0%3B%0A for (var i %3D 0%2C e %3D children.length%3B i < e%3B %2B%2Bi) {%0A var ch %3D children[i]%3B%0A size %2B%3D ch.chunkSize()%3B height %2B%3D ch.height%3B%0A ch.parent %3D this%3B%0A }%0A this.size %3D size%3B%0A this.height %3D height%3B%0A this.parent %3D null%3B%0A }%0A BranchChunk.prototype %3D {%0A chunkSize%3A function() { return this.size%3B }%2C%0A remove%3A function(at%2C n%2C callbacks) {%0A this.size -%3D n%3B%0A for (var i %3D 0%3B i < this.children.length%3B %2B%2Bi) {%0A var child %3D this.children[i]%2C sz %3D child.chunkSize()%3B%0A if (at < sz) {%0A var rm %3D Math.min(n%2C sz - at)%2C oldHeight %3D child.height%3B%0A child.remove(at%2C rm%2C callbacks)%3B%0A this.height -%3D oldHeight - child.height%3B%0A if (sz %3D%3D rm) { this.children.splice(i--%2C 1)%3B child.parent %3D null%3B }%0A if ((n -%3D rm) %3D%3D 0) break%3B%0A at %3D 0%3B%0A } else at -%3D sz%3B%0A }%0A if (this.size - n < 25) {%0A var lines %3D []%3B%0A this.collapse(lines)%3B%0A this.children %3D [new LeafChunk(lines)]%3B%0A this.children[0].parent %3D this%3B%0A }%0A }%2C%0A collapse%3A function(lines) {%0A for (var i %3D 0%2C e %3D this.children.length%3B i < e%3B %2B%2Bi) this.children[i].collapse(lines)%3B%0A }%2C%0A insert%3A function(at%2C lines) {%0A var height %3D 0%3B%0A for (var i %3D 0%2C e %3D lines.length%3B i < e%3B %2B%2Bi) height %2B%3D lines[i].height%3B%0A this.insertHeight(at%2C lines%2C height)%3B%0A }%2C%0A insertHeight%3A function(at%2C lines%2C height) {%0A this.size %2B%3D lines.length%3B%0A this.height %2B%3D height%3B%0A for (var i %3D 0%2C e %3D this.children.length%3B i < e%3B %2B%2Bi) {%0A var child %3D this.children[i]%2C sz %3D child.chunkSize()%3B%0A if (at <%3D sz) {%0A child.insertHeight(at%2C lines%2C height)%3B%0A if (child.lines %26%26 child.lines.length > 50) {%0A while (child.lines.length > 50) {%0A var spilled %3D child.lines.splice(child.lines.length - 25%2C 25)%3B%0A var newleaf %3D new LeafChunk(spilled)%3B%0A child.height -%3D newleaf.height%3B%0A this.children.splice(i %2B 1%2C 0%2C newleaf)%3B%0A newleaf.parent %3D this%3B%0A }%0A this.maybeSpill()%3B%0A }%0A break%3B%0A }%0A at -%3D sz%3B%0A }%0A }%2C%0A maybeSpill%3A function() {%0A if (this.children.length <%3D 10) return%3B%0A var me %3D this%3B%0A do {%0A var spilled %3D me.children.splice(me.children.length - 5%2C 5)%3B%0A var sibling %3D new BranchChunk(spilled)%3B%0A if (!me.parent) { %2F%2F Become the parent node%0A var copy %3D new BranchChunk(me.children)%3B%0A copy.parent %3D me%3B%0A me.children %3D [copy%2C sibling]%3B%0A me %3D copy%3B%0A } else {%0A me.size -%3D sibling.size%3B%0A me.height -%3D sibling.height%3B%0A var myIndex %3D indexOf(me.parent.children%2C me)%3B%0A me.parent.children.splice(myIndex %2B 1%2C 0%2C sibling)%3B%0A }%0A sibling.parent %3D me.parent%3B%0A } while (me.children.length > 10)%3B%0A me.parent.maybeSpill()%3B%0A }%2C%0A iter%3A function(from%2C to%2C op) { this.iterN(from%2C to - from%2C op)%3B }%2C%0A iterN%3A function(at%2C n%2C op) {%0A for (var i %3D 0%2C e %3D this.children.length%3B i < e%3B %2B%2Bi) {%0A var child %3D this.children[i]%2C sz %3D child.chunkSize()%3B%0A if (at < sz) {%0A var used %3D Math.min(n%2C sz - at)%3B%0A if (child.iterN(at%2C used%2C op)) return true%3B%0A if ((n -%3D used) %3D%3D 0) break%3B%0A at %3D 0%3B%0A } else at -%3D sz%3B%0A }%0A }%0A }%3B%0A%0A function getLineAt(chunk%2C n) {%0A while (!chunk.lines) {%0A for (var i %3D 0%3B%3B %2B%2Bi) {%0A var child %3D chunk.children[i]%2C sz %3D child.chunkSize()%3B%0A if (n < sz) { chunk %3D child%3B break%3B }%0A n -%3D sz%3B%0A }%0A }%0A return chunk.lines[n]%3B%0A }%0A function lineNo(line) {%0A if (line.parent %3D%3D null) return null%3B%0A var cur %3D line.parent%2C no %3D indexOf(cur.lines%2C line)%3B%0A for (var chunk %3D cur.parent%3B chunk%3B cur %3D chunk%2C chunk %3D chunk.parent) {%0A for (var i %3D 0%2C e %3D chunk.children.length%3B %3B %2B%2Bi) {%0A if (chunk.children[i] %3D%3D cur) break%3B%0A no %2B%3D chunk.children[i].chunkSize()%3B%0A }%0A }%0A return no%3B%0A }%0A function lineAtHeight(chunk%2C h) {%0A var n %3D 0%3B%0A outer%3A do {%0A for (var i %3D 0%2C e %3D chunk.children.length%3B i < e%3B %2B%2Bi) {%0A var child %3D chunk.children[i]%2C ch %3D child.height%3B%0A if (h < ch) { chunk %3D child%3B continue outer%3B }%0A h -%3D ch%3B%0A n %2B%3D child.chunkSize()%3B%0A }%0A return n%3B%0A } while (!chunk.lines)%3B%0A for (var i %3D 0%2C e %3D chunk.lines.length%3B i < e%3B %2B%2Bi) {%0A var line %3D chunk.lines[i]%2C lh %3D line.height%3B%0A if (h < lh) break%3B%0A h -%3D lh%3B%0A }%0A return n %2B i%3B%0A }%0A function heightAtLine(chunk%2C n) {%0A var h %3D 0%3B%0A outer%3A do {%0A for (var i %3D 0%2C e %3D chunk.children.length%3B i < e%3B %2B%2Bi) {%0A var child %3D chunk.children[i]%2C sz %3D child.chunkSize()%3B%0A if (n < sz) { chunk %3D child%3B continue outer%3B }%0A n -%3D sz%3B%0A h %2B%3D child.height%3B%0A }%0A return h%3B%0A } while (!chunk.lines)%3B%0A for (var i %3D 0%3B i < n%3B %2B%2Bi) h %2B%3D chunk.lines[i].height%3B%0A return h%3B%0A }%0A%0A %2F%2F The history object 'chunks' changes that are made close together%0A %2F%2F and at almost the same time into bigger undoable units.%0A function History() {%0A this.time %3D 0%3B%0A this.done %3D []%3B this.undone %3D []%3B%0A this.compound %3D 0%3B%0A this.closed %3D false%3B%0A }%0A History.prototype %3D {%0A addChange%3A function(start%2C added%2C old) {%0A this.undone.length %3D 0%3B%0A var time %3D %2Bnew Date%2C cur %3D lst(this.done)%2C last %3D cur %26%26 lst(cur)%3B%0A var dtime %3D time - this.time%3B%0A%0A if (this.compound %26%26 cur %26%26 !this.closed) {%0A cur.push({start%3A start%2C added%3A added%2C old%3A old})%3B%0A } else if (dtime > 400 || !last || this.closed ||%0A last.start > start %2B old.length || last.start %2B last.added < start) {%0A this.done.push([{start%3A start%2C added%3A added%2C old%3A old}])%3B%0A this.closed %3D false%3B%0A } else {%0A var startBefore %3D Math.max(0%2C last.start - start)%2C%0A endAfter %3D Math.max(0%2C (start %2B old.length) - (last.start %2B last.added))%3B%0A for (var i %3D startBefore%3B i > 0%3B --i) last.old.unshift(old[i - 1])%3B%0A for (var i %3D endAfter%3B i > 0%3B --i) last.old.push(old[old.length - i])%3B%0A if (startBefore) last.start %3D start%3B%0A last.added %2B%3D added - (old.length - startBefore - endAfter)%3B%0A }%0A this.time %3D time%3B%0A }%2C%0A startCompound%3A function() {%0A if (!this.compound%2B%2B) this.closed %3D true%3B%0A }%2C%0A endCompound%3A function() {%0A if (!--this.compound) this.closed %3D true%3B%0A }%0A }%3B%0A%0A function stopMethod() {e_stop(this)%3B}%0A %2F%2F Ensure an event has a stop method.%0A function addStop(event) {%0A if (!event.stop) event.stop %3D stopMethod%3B%0A return event%3B%0A }%0A%0A function e_preventDefault(e) {%0A if (e.preventDefault) e.preventDefault()%3B%0A else e.returnValue %3D false%3B%0A }%0A function e_stopPropagation(e) {%0A if (e.stopPropagation) e.stopPropagation()%3B%0A else e.cancelBubble %3D true%3B%0A }%0A function e_stop(e) {e_preventDefault(e)%3B e_stopPropagation(e)%3B}%0A CodeMirror.e_stop %3D e_stop%3B%0A CodeMirror.e_preventDefault %3D e_preventDefault%3B%0A CodeMirror.e_stopPropagation %3D e_stopPropagation%3B%0A%0A function e_target(e) {return e.target || e.srcElement%3B}%0A function e_button(e) {%0A var b %3D e.which%3B%0A if (b %3D%3D null) {%0A if (e.button %26 1) b %3D 1%3B%0A else if (e.button %26 2) b %3D 3%3B%0A else if (e.button %26 4) b %3D 2%3B%0A }%0A if (mac %26%26 e.ctrlKey %26%26 b %3D%3D 1) b %3D 3%3B%0A return b%3B%0A }%0A%0A %2F%2F Allow 3rd-party code to override event properties by adding an override%0A %2F%2F object to an event object.%0A function e_prop(e%2C prop) {%0A var overridden %3D e.override %26%26 e.override.hasOwnProperty(prop)%3B%0A return overridden %3F e.override[prop] %3A e[prop]%3B%0A }%0A%0A %2F%2F Event handler registration. If disconnect is true%2C it'll return a%0A %2F%2F function that unregisters the handler.%0A function connect(node%2C type%2C handler%2C disconnect) {%0A if (typeof node.addEventListener %3D%3D "function") {%0A node.addEventListener(type%2C handler%2C false)%3B%0A if (disconnect) return function() {node.removeEventListener(type%2C handler%2C false)%3B}%3B%0A } else {%0A var wrapHandler %3D function(event) {handler(event || window.event)%3B}%3B%0A node.attachEvent("on" %2B type%2C wrapHandler)%3B%0A if (disconnect) return function() {node.detachEvent("on" %2B type%2C wrapHandler)%3B}%3B%0A }%0A }%0A CodeMirror.connect %3D connect%3B%0A%0A function Delayed() {this.id %3D null%3B}%0A Delayed.prototype %3D {set%3A function(ms%2C f) {clearTimeout(this.id)%3B this.id %3D setTimeout(f%2C ms)%3B}}%3B%0A%0A var Pass %3D CodeMirror.Pass %3D {toString%3A function(){return "CodeMirror.Pass"%3B}}%3B%0A%0A %2F%2F Detect drag-and-drop%0A var dragAndDrop %3D function() {%0A %2F%2F There is *some* kind of drag-and-drop support in IE6-8%2C but I%0A %2F%2F couldn't get it to work yet.%0A if (ie_lt9) return false%3B%0A var div %3D elt('div')%3B%0A return "draggable" in div || "dragDrop" in div%3B%0A }()%3B%0A%0A %2F%2F Feature-detect whether newlines in textareas are converted to \r\n%0A var lineSep %3D function () {%0A var te %3D elt("textarea")%3B%0A te.value %3D "foo\nbar"%3B%0A if (te.value.indexOf("\r") > -1) return "\r\n"%3B%0A return "\n"%3B%0A }()%3B%0A%0A %2F%2F For a reason I have yet to figure out%2C some browsers disallow%0A %2F%2F word wrapping between certain characters *only* if a new inline%0A %2F%2F element is started between them. This makes it hard to reliably%0A %2F%2F measure the position of things%2C since that requires inserting an%0A %2F%2F extra span. This terribly fragile set of regexps matches the%0A %2F%2F character combinations that suffer from this phenomenon on the%0A %2F%2F various browsers.%0A var spanAffectsWrapping %3D %2F^%24%2F%3B %2F%2F Won't match any two-character string%0A if (gecko) spanAffectsWrapping %3D %2F%24'%2F%3B%0A else if (safari) spanAffectsWrapping %3D %2F\-[^ \-%3F]|\%3F[^ !'\"\)%2C.\-\%2F%3A%3B\%3F\]\}]%2F%3B%0A else if (chrome) spanAffectsWrapping %3D %2F\-[^ \-\.%3F]|\%3F[^ \-\.%3F\]\}%3A%3B!'\"\)%2C\%2F]|[\.!\"%23%26%25\)*%2B%2C%3A%3B%3D>\]|\}~][\(\{\[<]|\%24'%2F%3B%0A%0A %2F%2F Counts the column offset in a string%2C taking tabs into account.%0A %2F%2F Used mostly to find indentation.%0A function countColumn(string%2C end%2C tabSize) {%0A if (end %3D%3D null) {%0A end %3D string.search(%2F[^\s\u00a0]%2F)%3B%0A if (end %3D%3D -1) end %3D string.length%3B%0A }%0A for (var i %3D 0%2C n %3D 0%3B i < end%3B %2B%2Bi) {%0A if (string.charAt(i) %3D%3D "\t") n %2B%3D tabSize - (n %25 tabSize)%3B%0A else %2B%2Bn%3B%0A }%0A return n%3B%0A }%0A%0A function eltOffset(node%2C screen) {%0A %2F%2F Take the parts of bounding client rect that we are interested in so we are able to edit if need be%2C%0A %2F%2F since the returned value cannot be changed externally (they are kept in sync as the element moves within the page)%0A try { var box %3D node.getBoundingClientRect()%3B box %3D { top%3A box.top%2C left%3A box.left }%3B }%0A catch(e) { box %3D {top%3A 0%2C left%3A 0}%3B }%0A if (!screen) {%0A %2F%2F Get the toplevel scroll%2C working around browser differences.%0A if (window.pageYOffset %3D%3D null) {%0A var t %3D document.documentElement || document.body.parentNode%3B%0A if (t.scrollTop %3D%3D null) t %3D document.body%3B%0A box.top %2B%3D t.scrollTop%3B box.left %2B%3D t.scrollLeft%3B%0A } else {%0A box.top %2B%3D window.pageYOffset%3B box.left %2B%3D window.pageXOffset%3B%0A }%0A }%0A return box%3B%0A }%0A%0A function eltText(node) {%0A return node.textContent || node.innerText || node.nodeValue || ""%3B%0A }%0A%0A var spaceStrs %3D [""]%3B%0A function spaceStr(n) {%0A while (spaceStrs.length <%3D n)%0A spaceStrs.push(lst(spaceStrs) %2B " ")%3B%0A return spaceStrs[n]%3B%0A }%0A%0A function lst(arr) { return arr[arr.length-1]%3B }%0A%0A function selectInput(node) {%0A if (ios) { %2F%2F Mobile Safari apparently has a bug where select() is broken.%0A node.selectionStart %3D 0%3B%0A node.selectionEnd %3D node.value.length%3B%0A } else node.select()%3B%0A }%0A%0A %2F%2F Operations on {line%2C ch} objects.%0A function posEq(a%2C b) {return a.line %3D%3D b.line %26%26 a.ch %3D%3D b.ch%3B}%0A function posLess(a%2C b) {return a.line < b.line || (a.line %3D%3D b.line %26%26 a.ch < b.ch)%3B}%0A function copyPos(x) {return {line%3A x.line%2C ch%3A x.ch}%3B}%0A%0A function elt(tag%2C content%2C className%2C style) {%0A var e %3D document.createElement(tag)%3B%0A if (className) e.className %3D className%3B%0A if (style) e.style.cssText %3D style%3B%0A if (typeof content %3D%3D "string") setTextContent(e%2C content)%3B%0A else if (content) for (var i %3D 0%3B i < content.length%3B %2B%2Bi) e.appendChild(content[i])%3B%0A return e%3B%0A }%0A function removeChildren(e) {%0A e.innerHTML %3D ""%3B%0A return e%3B%0A }%0A function removeChildrenAndAdd(parent%2C e) {%0A removeChildren(parent).appendChild(e)%3B%0A }%0A function setTextContent(e%2C str) {%0A if (ie_lt9) {%0A e.innerHTML %3D ""%3B%0A e.appendChild(document.createTextNode(str))%3B%0A } else e.textContent %3D str%3B%0A }%0A%0A %2F%2F Used to position the cursor after an undo%2Fredo by finding the%0A %2F%2F last edited character.%0A function editEnd(from%2C to) {%0A if (!to) return 0%3B%0A if (!from) return to.length%3B%0A for (var i %3D from.length%2C j %3D to.length%3B i >%3D 0 %26%26 j >%3D 0%3B --i%2C --j)%0A if (from.charAt(i) !%3D to.charAt(j)) break%3B%0A return j %2B 1%3B%0A }%0A%0A function indexOf(collection%2C elt) {%0A if (collection.indexOf) return collection.indexOf(elt)%3B%0A for (var i %3D 0%2C e %3D collection.length%3B i < e%3B %2B%2Bi)%0A if (collection[i] %3D%3D elt) return i%3B%0A return -1%3B%0A }%0A function isWordChar(ch) {%0A return %2F\w%2F.test(ch) || ch.toUpperCase() !%3D ch.toLowerCase()%3B%0A }%0A%0A %2F%2F See if "".split is the broken IE version%2C if so%2C provide an%0A %2F%2F alternative way to split lines.%0A var splitLines %3D "\n\nb".split(%2F\n%2F).length !%3D 3 %3F function(string) {%0A var pos %3D 0%2C result %3D []%2C l %3D string.length%3B%0A while (pos <%3D l) {%0A var nl %3D string.indexOf("\n"%2C pos)%3B%0A if (nl %3D%3D -1) nl %3D string.length%3B%0A var line %3D string.slice(pos%2C string.charAt(nl - 1) %3D%3D "\r" %3F nl - 1 %3A nl)%3B%0A var rt %3D line.indexOf("\r")%3B%0A if (rt !%3D -1) {%0A result.push(line.slice(0%2C rt))%3B%0A pos %2B%3D rt %2B 1%3B%0A } else {%0A result.push(line)%3B%0A pos %3D nl %2B 1%3B%0A }%0A }%0A return result%3B%0A } %3A function(string){return string.split(%2F\r\n%3F|\n%2F)%3B}%3B%0A CodeMirror.splitLines %3D splitLines%3B%0A%0A var hasSelection %3D window.getSelection %3F function(te) {%0A try { return te.selectionStart !%3D te.selectionEnd%3B }%0A catch(e) { return false%3B }%0A } %3A function(te) {%0A try {var range %3D te.ownerDocument.selection.createRange()%3B}%0A catch(e) {}%0A if (!range || range.parentElement() !%3D te) return false%3B%0A return range.compareEndPoints("StartToEnd"%2C range) !%3D 0%3B%0A }%3B%0A%0A CodeMirror.defineMode("null"%2C function() {%0A return {token%3A function(stream) {stream.skipToEnd()%3B}}%3B%0A })%3B%0A CodeMirror.defineMIME("text%2Fplain"%2C "null")%3B%0A%0A var keyNames %3D {3%3A "Enter"%2C 8%3A "Backspace"%2C 9%3A "Tab"%2C 13%3A "Enter"%2C 16%3A "Shift"%2C 17%3A "Ctrl"%2C 18%3A "Alt"%2C%0A 19%3A "Pause"%2C 20%3A "CapsLock"%2C 27%3A "Esc"%2C 32%3A "Space"%2C 33%3A "PageUp"%2C 34%3A "PageDown"%2C 35%3A "End"%2C%0A 36%3A "Home"%2C 37%3A "Left"%2C 38%3A "Up"%2C 39%3A "Right"%2C 40%3A "Down"%2C 44%3A "PrintScrn"%2C 45%3A "Insert"%2C%0A 46%3A "Delete"%2C 59%3A "%3B"%2C 91%3A "Mod"%2C 92%3A "Mod"%2C 93%3A "Mod"%2C 109%3A "-"%2C 107%3A "%3D"%2C 127%3A "Delete"%2C%0A 186%3A "%3B"%2C 187%3A "%3D"%2C 188%3A "%2C"%2C 189%3A "-"%2C 190%3A "."%2C 191%3A "%2F"%2C 192%3A "`"%2C 219%3A "["%2C 220%3A "\\"%2C%0A 221%3A "]"%2C 222%3A "'"%2C 63276%3A "PageUp"%2C 63277%3A "PageDown"%2C 63275%3A "End"%2C 63273%3A "Home"%2C%0A 63234%3A "Left"%2C 63232%3A "Up"%2C 63235%3A "Right"%2C 63233%3A "Down"%2C 63302%3A "Insert"%2C 63272%3A "Delete"}%3B%0A CodeMirror.keyNames %3D keyNames%3B%0A (function() {%0A %2F%2F Number keys%0A for (var i %3D 0%3B i < 10%3B i%2B%2B) keyNames[i %2B 48] %3D String(i)%3B%0A %2F%2F Alphabetic keys%0A for (var i %3D 65%3B i <%3D 90%3B i%2B%2B) keyNames[i] %3D String.fromCharCode(i)%3B%0A %2F%2F Function keys%0A for (var i %3D 1%3B i <%3D 12%3B i%2B%2B) keyNames[i %2B 111] %3D keyNames[i %2B 63235] %3D "F" %2B i%3B%0A })()%3B%0A%0A CodeMirror.version %3D "2.34"%3B%0A%0A return CodeMirror%3B%0A})()%3B%0A%0A <%2Fscript>%0A %0A %0A %0A <!-- http%3A%2F%2Fcodemirror.net%2Flib%2Fcodemirror.css --><style>%0A.CodeMirror {%0A line-height%3A 1em%3B%0A font-family%3A monospace%3B%0A%0A %2F* Necessary so the scrollbar can be absolutely positioned within the wrapper on Lion. *%2F%0A position%3A relative%3B%0A %2F* This prevents unwanted scrollbars from showing up on the body and wrapper in IE. *%2F%0A overflow%3A hidden%3B%0A}%0A%0A.CodeMirror-scroll {%0A overflow%3A auto%3B%0A height%3A 300px%3B%0A %2F* This is needed to prevent an IE[67] bug where the scrolled content%0A is visible outside of the scrolling box. *%2F%0A position%3A relative%3B%0A outline%3A none%3B%0A}%0A%0A%2F* Vertical scrollbar *%2F%0A.CodeMirror-scrollbar {%0A position%3A absolute%3B%0A right%3A 0%3B top%3A 0%3B%0A overflow-x%3A hidden%3B%0A overflow-y%3A scroll%3B%0A z-index%3A 5%3B%0A}%0A.CodeMirror-scrollbar-inner {%0A %2F* This needs to have a nonzero width in order for the scrollbar to appear%0A in Firefox and IE9. *%2F%0A width%3A 1px%3B%0A}%0A.CodeMirror-scrollbar.cm-sb-overlap {%0A %2F* Ensure that the scrollbar appears in Lion%2C and that it overlaps the content%0A rather than sitting to the right of it. *%2F%0A position%3A absolute%3B%0A z-index%3A 1%3B%0A float%3A none%3B%0A right%3A 0%3B%0A min-width%3A 12px%3B%0A}%0A.CodeMirror-scrollbar.cm-sb-nonoverlap {%0A min-width%3A 12px%3B%0A}%0A.CodeMirror-scrollbar.cm-sb-ie7 {%0A min-width%3A 18px%3B%0A}%0A%0A.CodeMirror-gutter {%0A position%3A absolute%3B left%3A 0%3B top%3A 0%3B%0A z-index%3A 10%3B%0A background-color%3A %23f7f7f7%3B%0A border-right%3A 1px solid %23eee%3B%0A min-width%3A 2em%3B%0A height%3A 100%25%3B%0A}%0A.CodeMirror-gutter-text {%0A color%3A %23aaa%3B%0A text-align%3A right%3B%0A padding%3A .4em .2em .4em .4em%3B%0A white-space%3A pre !important%3B%0A cursor%3A default%3B%0A}%0A.CodeMirror-lines {%0A padding%3A .4em%3B%0A white-space%3A pre%3B%0A cursor%3A text%3B%0A}%0A%0A.CodeMirror pre {%0A -moz-border-radius%3A 0%3B%0A -webkit-border-radius%3A 0%3B%0A -o-border-radius%3A 0%3B%0A border-radius%3A 0%3B%0A border-width%3A 0%3B margin%3A 0%3B padding%3A 0%3B background%3A transparent%3B%0A font-family%3A inherit%3B%0A font-size%3A inherit%3B%0A padding%3A 0%3B margin%3A 0%3B%0A white-space%3A pre%3B%0A word-wrap%3A normal%3B%0A line-height%3A inherit%3B%0A color%3A inherit%3B%0A}%0A%0A.CodeMirror-wrap pre {%0A word-wrap%3A break-word%3B%0A white-space%3A pre-wrap%3B%0A word-break%3A normal%3B%0A}%0A.CodeMirror-wrap .CodeMirror-scroll {%0A overflow-x%3A hidden%3B%0A}%0A%0A.CodeMirror textarea {%0A outline%3A none !important%3B%0A}%0A%0A.CodeMirror pre.CodeMirror-cursor {%0A z-index%3A 10%3B%0A position%3A absolute%3B%0A visibility%3A hidden%3B%0A border-left%3A 1px solid black%3B%0A border-right%3A none%3B%0A width%3A 0%3B%0A}%0A.cm-keymap-fat-cursor pre.CodeMirror-cursor {%0A width%3A auto%3B%0A border%3A 0%3B%0A background%3A transparent%3B%0A background%3A rgba(0%2C 200%2C 0%2C .4)%3B%0A filter%3A progid%3ADXImageTransform.Microsoft.gradient(startColorstr%3D%236600c800%2C endColorstr%3D%234c00c800)%3B%0A}%0A%2F* Kludge to turn off filter in ie9%2B%2C which also accepts rgba *%2F%0A.cm-keymap-fat-cursor pre.CodeMirror-cursor%3Anot(%23nonsense_id) {%0A filter%3A progid%3ADXImageTransform.Microsoft.gradient(enabled%3Dfalse)%3B%0A}%0A.CodeMirror pre.CodeMirror-cursor.CodeMirror-overwrite {}%0A.CodeMirror-focused pre.CodeMirror-cursor {%0A visibility%3A visible%3B%0A}%0A%0Adiv.CodeMirror-selected { background%3A %23d9d9d9%3B }%0A.CodeMirror-focused div.CodeMirror-selected { background%3A %23d7d4f0%3B }%0A%0A.CodeMirror-searching {%0A background%3A %23ffa%3B%0A background%3A rgba(255%2C 255%2C 0%2C .4)%3B%0A}%0A%0A%2F* Default theme *%2F%0A%0A.cm-s-default span.cm-keyword {color%3A %23708%3B}%0A.cm-s-default span.cm-atom {color%3A %23219%3B}%0A.cm-s-default span.cm-number {color%3A %23164%3B}%0A.cm-s-default span.cm-def {color%3A %2300f%3B}%0A.cm-s-default span.cm-variable {color%3A black%3B}%0A.cm-s-default span.cm-variable-2 {color%3A %2305a%3B}%0A.cm-s-default span.cm-variable-3 {color%3A %23085%3B}%0A.cm-s-default span.cm-property {color%3A black%3B}%0A.cm-s-default span.cm-operator {color%3A black%3B}%0A.cm-s-default span.cm-comment {color%3A %23a50%3B}%0A.cm-s-default span.cm-string {color%3A %23a11%3B}%0A.cm-s-default span.cm-string-2 {color%3A %23f50%3B}%0A.cm-s-default span.cm-meta {color%3A %23555%3B}%0A.cm-s-default span.cm-error {color%3A %23f00%3B}%0A.cm-s-default span.cm-qualifier {color%3A %23555%3B}%0A.cm-s-default span.cm-builtin {color%3A %2330a%3B}%0A.cm-s-default span.cm-bracket {color%3A %23997%3B}%0A.cm-s-default span.cm-tag {color%3A %23170%3B}%0A.cm-s-default span.cm-attribute {color%3A %2300c%3B}%0A.cm-s-default span.cm-header {color%3A blue%3B}%0A.cm-s-default span.cm-quote {color%3A %23090%3B}%0A.cm-s-default span.cm-hr {color%3A %23999%3B}%0A.cm-s-default span.cm-link {color%3A %2300c%3B}%0A%0Aspan.cm-header%2C span.cm-strong {font-weight%3A bold%3B}%0Aspan.cm-em {font-style%3A italic%3B}%0Aspan.cm-emstrong {font-style%3A italic%3B font-weight%3A bold%3B}%0Aspan.cm-link {text-decoration%3A underline%3B}%0A%0Aspan.cm-invalidchar {color%3A %23f00%3B}%0A%0Adiv.CodeMirror span.CodeMirror-matchingbracket {color%3A %230f0%3B}%0Adiv.CodeMirror span.CodeMirror-nonmatchingbracket {color%3A %23f22%3B}%0A%0A%40media print {%0A%0A %2F* Hide the cursor when printing *%2F%0A .CodeMirror pre.CodeMirror-cursor {%0A visibility%3A hidden%3B%0A }%0A%0A}%0A <%2Fstyle> %0A %0A %0A %0A <!-- http%3A%2F%2Fcodemirror.net%2Fmode%2Fxml%2Fxml.js --><script>%0ACodeMirror.defineMode("xml"%2C function(config%2C parserConfig) {%0A var indentUnit %3D config.indentUnit%3B%0A var Kludges %3D parserConfig.htmlMode %3F {%0A autoSelfClosers%3A {'area'%3A true%2C 'base'%3A true%2C 'br'%3A true%2C 'col'%3A true%2C 'command'%3A true%2C%0A 'embed'%3A true%2C 'frame'%3A true%2C 'hr'%3A true%2C 'img'%3A true%2C 'input'%3A true%2C%0A 'keygen'%3A true%2C 'link'%3A true%2C 'meta'%3A true%2C 'param'%3A true%2C 'source'%3A true%2C%0A 'track'%3A true%2C 'wbr'%3A true}%2C%0A implicitlyClosed%3A {'dd'%3A true%2C 'li'%3A true%2C 'optgroup'%3A true%2C 'option'%3A true%2C 'p'%3A true%2C%0A 'rp'%3A true%2C 'rt'%3A true%2C 'tbody'%3A true%2C 'td'%3A true%2C 'tfoot'%3A true%2C%0A 'th'%3A true%2C 'tr'%3A true}%2C%0A contextGrabbers%3A {%0A 'dd'%3A {'dd'%3A true%2C 'dt'%3A true}%2C%0A 'dt'%3A {'dd'%3A true%2C 'dt'%3A true}%2C%0A 'li'%3A {'li'%3A true}%2C%0A 'option'%3A {'option'%3A true%2C 'optgroup'%3A true}%2C%0A 'optgroup'%3A {'optgroup'%3A true}%2C%0A 'p'%3A {'address'%3A true%2C 'article'%3A true%2C 'aside'%3A true%2C 'blockquote'%3A true%2C 'dir'%3A true%2C%0A 'div'%3A true%2C 'dl'%3A true%2C 'fieldset'%3A true%2C 'footer'%3A true%2C 'form'%3A true%2C%0A 'h1'%3A true%2C 'h2'%3A true%2C 'h3'%3A true%2C 'h4'%3A true%2C 'h5'%3A true%2C 'h6'%3A true%2C%0A 'header'%3A true%2C 'hgroup'%3A true%2C 'hr'%3A true%2C 'menu'%3A true%2C 'nav'%3A true%2C 'ol'%3A true%2C%0A 'p'%3A true%2C 'pre'%3A true%2C 'section'%3A true%2C 'table'%3A true%2C 'ul'%3A true}%2C%0A 'rp'%3A {'rp'%3A true%2C 'rt'%3A true}%2C%0A 'rt'%3A {'rp'%3A true%2C 'rt'%3A true}%2C%0A 'tbody'%3A {'tbody'%3A true%2C 'tfoot'%3A true}%2C%0A 'td'%3A {'td'%3A true%2C 'th'%3A true}%2C%0A 'tfoot'%3A {'tbody'%3A true}%2C%0A 'th'%3A {'td'%3A true%2C 'th'%3A true}%2C%0A 'thead'%3A {'tbody'%3A true%2C 'tfoot'%3A true}%2C%0A 'tr'%3A {'tr'%3A true}%0A }%2C%0A doNotIndent%3A {"pre"%3A true}%2C%0A allowUnquoted%3A true%2C%0A allowMissing%3A true%0A } %3A {%0A autoSelfClosers%3A {}%2C%0A implicitlyClosed%3A {}%2C%0A contextGrabbers%3A {}%2C%0A doNotIndent%3A {}%2C%0A allowUnquoted%3A false%2C%0A allowMissing%3A false%0A }%3B%0A var alignCDATA %3D parserConfig.alignCDATA%3B%0A%0A %2F%2F Return variables for tokenizers%0A var tagName%2C type%3B%0A%0A function inText(stream%2C state) {%0A function chain(parser) {%0A state.tokenize %3D parser%3B%0A return parser(stream%2C state)%3B%0A }%0A%0A var ch %3D stream.next()%3B%0A if (ch %3D%3D "<") {%0A if (stream.eat("!")) {%0A if (stream.eat("[")) {%0A if (stream.match("CDATA[")) return chain(inBlock("atom"%2C "]]>"))%3B%0A else return null%3B%0A }%0A else if (stream.match("--")) return chain(inBlock("comment"%2C "-->"))%3B%0A else if (stream.match("DOCTYPE"%2C true%2C true)) {%0A stream.eatWhile(%2F[\w\._\-]%2F)%3B%0A return chain(doctype(1))%3B%0A }%0A else return null%3B%0A }%0A else if (stream.eat("%3F")) {%0A stream.eatWhile(%2F[\w\._\-]%2F)%3B%0A state.tokenize %3D inBlock("meta"%2C "%3F>")%3B%0A return "meta"%3B%0A }%0A else {%0A type %3D stream.eat("%2F") %3F "closeTag" %3A "openTag"%3B%0A stream.eatSpace()%3B%0A tagName %3D ""%3B%0A var c%3B%0A while ((c %3D stream.eat(%2F[^\s\u00a0%3D<>\"\'\%2F%3F]%2F))) tagName %2B%3D c%3B%0A state.tokenize %3D inTag%3B%0A return "tag"%3B%0A }%0A }%0A else if (ch %3D%3D "%26") {%0A var ok%3B%0A if (stream.eat("%23")) {%0A if (stream.eat("x")) {%0A ok %3D stream.eatWhile(%2F[a-fA-F\d]%2F) %26%26 stream.eat("%3B")%3B %0A } else {%0A ok %3D stream.eatWhile(%2F[\d]%2F) %26%26 stream.eat("%3B")%3B%0A }%0A } else {%0A ok %3D stream.eatWhile(%2F[\w\.\-%3A]%2F) %26%26 stream.eat("%3B")%3B%0A }%0A return ok %3F "atom" %3A "error"%3B%0A }%0A else {%0A stream.eatWhile(%2F[^%26<]%2F)%3B%0A return null%3B%0A }%0A }%0A%0A function inTag(stream%2C state) {%0A var ch %3D stream.next()%3B%0A if (ch %3D%3D ">" || (ch %3D%3D "%2F" %26%26 stream.eat(">"))) {%0A state.tokenize %3D inText%3B%0A type %3D ch %3D%3D ">" %3F "endTag" %3A "selfcloseTag"%3B%0A return "tag"%3B%0A }%0A else if (ch %3D%3D "%3D") {%0A type %3D "equals"%3B%0A return null%3B%0A }%0A else if (%2F[\'\"]%2F.test(ch)) {%0A state.tokenize %3D inAttribute(ch)%3B%0A return state.tokenize(stream%2C state)%3B%0A }%0A else {%0A stream.eatWhile(%2F[^\s\u00a0%3D<>\"\'\%2F%3F]%2F)%3B%0A return "word"%3B%0A }%0A }%0A%0A function inAttribute(quote) {%0A return function(stream%2C state) {%0A while (!stream.eol()) {%0A if (stream.next() %3D%3D quote) {%0A state.tokenize %3D inTag%3B%0A break%3B%0A }%0A }%0A return "string"%3B%0A }%3B%0A }%0A%0A function inBlock(style%2C terminator) {%0A return function(stream%2C state) {%0A while (!stream.eol()) {%0A if (stream.match(terminator)) {%0A state.tokenize %3D inText%3B%0A break%3B%0A }%0A stream.next()%3B%0A }%0A return style%3B%0A }%3B%0A }%0A function doctype(depth) {%0A return function(stream%2C state) {%0A var ch%3B%0A while ((ch %3D stream.next()) !%3D null) {%0A if (ch %3D%3D "<") {%0A state.tokenize %3D doctype(depth %2B 1)%3B%0A return state.tokenize(stream%2C state)%3B%0A } else if (ch %3D%3D ">") {%0A if (depth %3D%3D 1) {%0A state.tokenize %3D inText%3B%0A break%3B%0A } else {%0A state.tokenize %3D doctype(depth - 1)%3B%0A return state.tokenize(stream%2C state)%3B%0A }%0A }%0A }%0A return "meta"%3B%0A }%3B%0A }%0A%0A var curState%2C setStyle%3B%0A function pass() {%0A for (var i %3D arguments.length - 1%3B i >%3D 0%3B i--) curState.cc.push(arguments[i])%3B%0A }%0A function cont() {%0A pass.apply(null%2C arguments)%3B%0A return true%3B%0A }%0A%0A function pushContext(tagName%2C startOfLine) {%0A var noIndent %3D Kludges.doNotIndent.hasOwnProperty(tagName) || (curState.context %26%26 curState.context.noIndent)%3B%0A curState.context %3D {%0A prev%3A curState.context%2C%0A tagName%3A tagName%2C%0A indent%3A curState.indented%2C%0A startOfLine%3A startOfLine%2C%0A noIndent%3A noIndent%0A }%3B%0A }%0A function popContext() {%0A if (curState.context) curState.context %3D curState.context.prev%3B%0A }%0A%0A function element(type) {%0A if (type %3D%3D "openTag") {%0A curState.tagName %3D tagName%3B%0A return cont(attributes%2C endtag(curState.startOfLine))%3B%0A } else if (type %3D%3D "closeTag") {%0A var err %3D false%3B%0A if (curState.context) {%0A if (curState.context.tagName !%3D tagName) {%0A if (Kludges.implicitlyClosed.hasOwnProperty(curState.context.tagName.toLowerCase())) {%0A popContext()%3B%0A }%0A err %3D !curState.context || curState.context.tagName !%3D tagName%3B%0A }%0A } else {%0A err %3D true%3B%0A }%0A if (err) setStyle %3D "error"%3B%0A return cont(endclosetag(err))%3B%0A }%0A return cont()%3B%0A }%0A function endtag(startOfLine) {%0A return function(type) {%0A if (type %3D%3D "selfcloseTag" ||%0A (type %3D%3D "endTag" %26%26 Kludges.autoSelfClosers.hasOwnProperty(curState.tagName.toLowerCase()))) {%0A maybePopContext(curState.tagName.toLowerCase())%3B%0A return cont()%3B%0A }%0A if (type %3D%3D "endTag") {%0A maybePopContext(curState.tagName.toLowerCase())%3B%0A pushContext(curState.tagName%2C startOfLine)%3B%0A return cont()%3B%0A }%0A return cont()%3B%0A }%3B%0A }%0A function endclosetag(err) {%0A return function(type) {%0A if (err) setStyle %3D "error"%3B%0A if (type %3D%3D "endTag") { popContext()%3B return cont()%3B }%0A setStyle %3D "error"%3B%0A return cont(arguments.callee)%3B%0A }%3B%0A }%0A function maybePopContext(nextTagName) {%0A var parentTagName%3B%0A while (true) {%0A if (!curState.context) {%0A return%3B%0A }%0A parentTagName %3D curState.context.tagName.toLowerCase()%3B%0A if (!Kludges.contextGrabbers.hasOwnProperty(parentTagName) ||%0A !Kludges.contextGrabbers[parentTagName].hasOwnProperty(nextTagName)) {%0A return%3B%0A }%0A popContext()%3B%0A }%0A }%0A%0A function attributes(type) {%0A if (type %3D%3D "word") {setStyle %3D "attribute"%3B return cont(attribute%2C attributes)%3B}%0A if (type %3D%3D "endTag" || type %3D%3D "selfcloseTag") return pass()%3B%0A setStyle %3D "error"%3B%0A return cont(attributes)%3B%0A }%0A function attribute(type) {%0A if (type %3D%3D "equals") return cont(attvalue%2C attributes)%3B%0A if (!Kludges.allowMissing) setStyle %3D "error"%3B%0A return (type %3D%3D "endTag" || type %3D%3D "selfcloseTag") %3F pass() %3A cont()%3B%0A }%0A function attvalue(type) {%0A if (type %3D%3D "string") return cont(attvaluemaybe)%3B%0A if (type %3D%3D "word" %26%26 Kludges.allowUnquoted) {setStyle %3D "string"%3B return cont()%3B}%0A setStyle %3D "error"%3B%0A return (type %3D%3D "endTag" || type %3D%3D "selfCloseTag") %3F pass() %3A cont()%3B%0A }%0A function attvaluemaybe(type) {%0A if (type %3D%3D "string") return cont(attvaluemaybe)%3B%0A else return pass()%3B%0A }%0A%0A return {%0A startState%3A function() {%0A return {tokenize%3A inText%2C cc%3A []%2C indented%3A 0%2C startOfLine%3A true%2C tagName%3A null%2C context%3A null}%3B%0A }%2C%0A%0A token%3A function(stream%2C state) {%0A if (stream.sol()) {%0A state.startOfLine %3D true%3B%0A state.indented %3D stream.indentation()%3B%0A }%0A if (stream.eatSpace()) return null%3B%0A%0A setStyle %3D type %3D tagName %3D null%3B%0A var style %3D state.tokenize(stream%2C state)%3B%0A state.type %3D type%3B%0A if ((style || type) %26%26 style !%3D "comment") {%0A curState %3D state%3B%0A while (true) {%0A var comb %3D state.cc.pop() || element%3B%0A if (comb(type || style)) break%3B%0A }%0A }%0A state.startOfLine %3D false%3B%0A return setStyle || style%3B%0A }%2C%0A%0A indent%3A function(state%2C textAfter%2C fullLine) {%0A var context %3D state.context%3B%0A if ((state.tokenize !%3D inTag %26%26 state.tokenize !%3D inText) ||%0A context %26%26 context.noIndent)%0A return fullLine %3F fullLine.match(%2F^(\s*)%2F)[0].length %3A 0%3B%0A if (alignCDATA %26%26 %2F<!\[CDATA\[%2F.test(textAfter)) return 0%3B%0A if (context %26%26 %2F^<\%2F%2F.test(textAfter))%0A context %3D context.prev%3B%0A while (context %26%26 !context.startOfLine)%0A context %3D context.prev%3B%0A if (context) return context.indent %2B indentUnit%3B%0A else return 0%3B%0A }%2C%0A%0A electricChars%3A "%2F"%0A }%3B%0A})%3B%0A%0ACodeMirror.defineMIME("text%2Fxml"%2C "xml")%3B%0ACodeMirror.defineMIME("application%2Fxml"%2C "xml")%3B%0Aif (!CodeMirror.mimeModes.hasOwnProperty("text%2Fhtml"))%0A CodeMirror.defineMIME("text%2Fhtml"%2C {name%3A "xml"%2C htmlMode%3A true})%3B%0A <%2Fscript>%0A %0A %0A %0A <!-- http%3A%2F%2Fcodemirror.net%2Fmode%2Fjavascript%2Fjavascript.js --><script>%0ACodeMirror.defineMode("javascript"%2C function(config%2C parserConfig) {%0A var indentUnit %3D config.indentUnit%3B%0A var jsonMode %3D parserConfig.json%3B%0A%0A %2F%2F Tokenizer%0A%0A var keywords %3D function(){%0A function kw(type) {return {type%3A type%2C style%3A "keyword"}%3B}%0A var A %3D kw("keyword a")%2C B %3D kw("keyword b")%2C C %3D kw("keyword c")%3B%0A var operator %3D kw("operator")%2C atom %3D {type%3A "atom"%2C style%3A "atom"}%3B%0A return {%0A "if"%3A A%2C "while"%3A A%2C "with"%3A A%2C "else"%3A B%2C "do"%3A B%2C "try"%3A B%2C "finally"%3A B%2C%0A "return"%3A C%2C "break"%3A C%2C "continue"%3A C%2C "new"%3A C%2C "delete"%3A C%2C "throw"%3A C%2C%0A "var"%3A kw("var")%2C "const"%3A kw("var")%2C "let"%3A kw("var")%2C%0A "function"%3A kw("function")%2C "catch"%3A kw("catch")%2C%0A "for"%3A kw("for")%2C "switch"%3A kw("switch")%2C "case"%3A kw("case")%2C "default"%3A kw("default")%2C%0A "in"%3A operator%2C "typeof"%3A operator%2C "instanceof"%3A operator%2C%0A "true"%3A atom%2C "false"%3A atom%2C "null"%3A atom%2C "undefined"%3A atom%2C "NaN"%3A atom%2C "Infinity"%3A atom%0A }%3B%0A }()%3B%0A%0A var isOperatorChar %3D %2F[%2B\-*%26%25%3D<>!%3F|]%2F%3B%0A%0A function chain(stream%2C state%2C f) {%0A state.tokenize %3D f%3B%0A return f(stream%2C state)%3B%0A }%0A%0A function nextUntilUnescaped(stream%2C end) {%0A var escaped %3D false%2C next%3B%0A while ((next %3D stream.next()) !%3D null) {%0A if (next %3D%3D end %26%26 !escaped)%0A return false%3B%0A escaped %3D !escaped %26%26 next %3D%3D "\\"%3B%0A }%0A return escaped%3B%0A }%0A%0A %2F%2F Used as scratch variables to communicate multiple values without%0A %2F%2F consing up tons of objects.%0A var type%2C content%3B%0A function ret(tp%2C style%2C cont) {%0A type %3D tp%3B content %3D cont%3B%0A return style%3B%0A }%0A%0A function jsTokenBase(stream%2C state) {%0A var ch %3D stream.next()%3B%0A if (ch %3D%3D '"' || ch %3D%3D "'")%0A return chain(stream%2C state%2C jsTokenString(ch))%3B%0A else if (%2F[\[\]{}\(\)%2C%3B\%3A\.]%2F.test(ch))%0A return ret(ch)%3B%0A else if (ch %3D%3D "0" %26%26 stream.eat(%2Fx%2Fi)) {%0A stream.eatWhile(%2F[\da-f]%2Fi)%3B%0A return ret("number"%2C "number")%3B%0A } %0A else if (%2F\d%2F.test(ch) || ch %3D%3D "-" %26%26 stream.eat(%2F\d%2F)) {%0A stream.match(%2F^\d*(%3F%3A\.\d*)%3F(%3F%3A[eE][%2B\-]%3F\d%2B)%3F%2F)%3B%0A return ret("number"%2C "number")%3B%0A }%0A else if (ch %3D%3D "%2F") {%0A if (stream.eat("*")) {%0A return chain(stream%2C state%2C jsTokenComment)%3B%0A }%0A else if (stream.eat("%2F")) {%0A stream.skipToEnd()%3B%0A return ret("comment"%2C "comment")%3B%0A }%0A else if (state.reAllowed) {%0A nextUntilUnescaped(stream%2C "%2F")%3B%0A stream.eatWhile(%2F[gimy]%2F)%3B %2F%2F 'y' is "sticky" option in Mozilla%0A return ret("regexp"%2C "string-2")%3B%0A }%0A else {%0A stream.eatWhile(isOperatorChar)%3B%0A return ret("operator"%2C null%2C stream.current())%3B%0A }%0A }%0A else if (ch %3D%3D "%23") {%0A stream.skipToEnd()%3B%0A return ret("error"%2C "error")%3B%0A }%0A else if (isOperatorChar.test(ch)) {%0A stream.eatWhile(isOperatorChar)%3B%0A return ret("operator"%2C null%2C stream.current())%3B%0A }%0A else {%0A stream.eatWhile(%2F[\w\%24_]%2F)%3B%0A var word %3D stream.current()%2C known %3D keywords.propertyIsEnumerable(word) %26%26 keywords[word]%3B%0A return (known %26%26 state.kwAllowed) %3F ret(known.type%2C known.style%2C word) %3A%0A ret("variable"%2C "variable"%2C word)%3B%0A }%0A }%0A%0A function jsTokenString(quote) {%0A return function(stream%2C state) {%0A if (!nextUntilUnescaped(stream%2C quote))%0A state.tokenize %3D jsTokenBase%3B%0A return ret("string"%2C "string")%3B%0A }%3B%0A }%0A%0A function jsTokenComment(stream%2C state) {%0A var maybeEnd %3D false%2C ch%3B%0A while (ch %3D stream.next()) {%0A if (ch %3D%3D "%2F" %26%26 maybeEnd) {%0A state.tokenize %3D jsTokenBase%3B%0A break%3B%0A }%0A maybeEnd %3D (ch %3D%3D "*")%3B%0A }%0A return ret("comment"%2C "comment")%3B%0A }%0A%0A %2F%2F Parser%0A%0A var atomicTypes %3D {"atom"%3A true%2C "number"%3A true%2C "variable"%3A true%2C "string"%3A true%2C "regexp"%3A true}%3B%0A%0A function JSLexical(indented%2C column%2C type%2C align%2C prev%2C info) {%0A this.indented %3D indented%3B%0A this.column %3D column%3B%0A this.type %3D type%3B%0A this.prev %3D prev%3B%0A this.info %3D info%3B%0A if (align !%3D null) this.align %3D align%3B%0A }%0A%0A function inScope(state%2C varname) {%0A for (var v %3D state.localVars%3B v%3B v %3D v.next)%0A if (v.name %3D%3D varname) return true%3B%0A }%0A%0A function parseJS(state%2C style%2C type%2C content%2C stream) {%0A var cc %3D state.cc%3B%0A %2F%2F Communicate our context to the combinators.%0A %2F%2F (Less wasteful than consing up a hundred closures on every call.)%0A cx.state %3D state%3B cx.stream %3D stream%3B cx.marked %3D null%2C cx.cc %3D cc%3B%0A %0A if (!state.lexical.hasOwnProperty("align"))%0A state.lexical.align %3D true%3B%0A%0A while(true) {%0A var combinator %3D cc.length %3F cc.pop() %3A jsonMode %3F expression %3A statement%3B%0A if (combinator(type%2C content)) {%0A while(cc.length %26%26 cc[cc.length - 1].lex)%0A cc.pop()()%3B%0A if (cx.marked) return cx.marked%3B%0A if (type %3D%3D "variable" %26%26 inScope(state%2C content)) return "variable-2"%3B%0A return style%3B%0A }%0A }%0A }%0A%0A %2F%2F Combinator utils%0A%0A var cx %3D {state%3A null%2C column%3A null%2C marked%3A null%2C cc%3A null}%3B%0A function pass() {%0A for (var i %3D arguments.length - 1%3B i >%3D 0%3B i--) cx.cc.push(arguments[i])%3B%0A }%0A function cont() {%0A pass.apply(null%2C arguments)%3B%0A return true%3B%0A }%0A function register(varname) {%0A var state %3D cx.state%3B%0A if (state.context) {%0A cx.marked %3D "def"%3B%0A for (var v %3D state.localVars%3B v%3B v %3D v.next)%0A if (v.name %3D%3D varname) return%3B%0A state.localVars %3D {name%3A varname%2C next%3A state.localVars}%3B%0A }%0A }%0A%0A %2F%2F Combinators%0A%0A var defaultVars %3D {name%3A "this"%2C next%3A {name%3A "arguments"}}%3B%0A function pushcontext() {%0A cx.state.context %3D {prev%3A cx.state.context%2C vars%3A cx.state.localVars}%3B%0A cx.state.localVars %3D defaultVars%3B%0A }%0A function popcontext() {%0A cx.state.localVars %3D cx.state.context.vars%3B%0A cx.state.context %3D cx.state.context.prev%3B%0A }%0A function pushlex(type%2C info) {%0A var result %3D function() {%0A var state %3D cx.state%3B%0A state.lexical %3D new JSLexical(state.indented%2C cx.stream.column()%2C type%2C null%2C state.lexical%2C info)%3B%0A }%3B%0A result.lex %3D true%3B%0A return result%3B%0A }%0A function poplex() {%0A var state %3D cx.state%3B%0A if (state.lexical.prev) {%0A if (state.lexical.type %3D%3D ")")%0A state.indented %3D state.lexical.indented%3B%0A state.lexical %3D state.lexical.prev%3B%0A }%0A }%0A poplex.lex %3D true%3B%0A%0A function expect(wanted) {%0A return function expecting(type) {%0A if (type %3D%3D wanted) return cont()%3B%0A else if (wanted %3D%3D "%3B") return pass()%3B%0A else return cont(arguments.callee)%3B%0A }%3B%0A }%0A%0A function statement(type) {%0A if (type %3D%3D "var") return cont(pushlex("vardef")%2C vardef1%2C expect("%3B")%2C poplex)%3B%0A if (type %3D%3D "keyword a") return cont(pushlex("form")%2C expression%2C statement%2C poplex)%3B%0A if (type %3D%3D "keyword b") return cont(pushlex("form")%2C statement%2C poplex)%3B%0A if (type %3D%3D "{") return cont(pushlex("}")%2C block%2C poplex)%3B%0A if (type %3D%3D "%3B") return cont()%3B%0A if (type %3D%3D "function") return cont(functiondef)%3B%0A if (type %3D%3D "for") return cont(pushlex("form")%2C expect("(")%2C pushlex(")")%2C forspec1%2C expect(")")%2C%0A poplex%2C statement%2C poplex)%3B%0A if (type %3D%3D "variable") return cont(pushlex("stat")%2C maybelabel)%3B%0A if (type %3D%3D "switch") return cont(pushlex("form")%2C expression%2C pushlex("}"%2C "switch")%2C expect("{")%2C%0A block%2C poplex%2C poplex)%3B%0A if (type %3D%3D "case") return cont(expression%2C expect("%3A"))%3B%0A if (type %3D%3D "default") return cont(expect("%3A"))%3B%0A if (type %3D%3D "catch") return cont(pushlex("form")%2C pushcontext%2C expect("(")%2C funarg%2C expect(")")%2C%0A statement%2C poplex%2C popcontext)%3B%0A return pass(pushlex("stat")%2C expression%2C expect("%3B")%2C poplex)%3B%0A }%0A function expression(type) {%0A if (atomicTypes.hasOwnProperty(type)) return cont(maybeoperator)%3B%0A if (type %3D%3D "function") return cont(functiondef)%3B%0A if (type %3D%3D "keyword c") return cont(maybeexpression)%3B%0A if (type %3D%3D "(") return cont(pushlex(")")%2C maybeexpression%2C expect(")")%2C poplex%2C maybeoperator)%3B%0A if (type %3D%3D "operator") return cont(expression)%3B%0A if (type %3D%3D "[") return cont(pushlex("]")%2C commasep(expression%2C "]")%2C poplex%2C maybeoperator)%3B%0A if (type %3D%3D "{") return cont(pushlex("}")%2C commasep(objprop%2C "}")%2C poplex%2C maybeoperator)%3B%0A return cont()%3B%0A }%0A function maybeexpression(type) {%0A if (type.match(%2F[%3B\}\)\]%2C]%2F)) return pass()%3B%0A return pass(expression)%3B%0A }%0A %0A function maybeoperator(type%2C value) {%0A if (type %3D%3D "operator" %26%26 %2F\%2B\%2B|--%2F.test(value)) return cont(maybeoperator)%3B%0A if (type %3D%3D "operator" %26%26 value %3D%3D "%3F") return cont(expression%2C expect("%3A")%2C expression)%3B%0A if (type %3D%3D "%3B") return%3B%0A if (type %3D%3D "(") return cont(pushlex(")")%2C commasep(expression%2C ")")%2C poplex%2C maybeoperator)%3B%0A if (type %3D%3D ".") return cont(property%2C maybeoperator)%3B%0A if (type %3D%3D "[") return cont(pushlex("]")%2C expression%2C expect("]")%2C poplex%2C maybeoperator)%3B%0A }%0A function maybelabel(type) {%0A if (type %3D%3D "%3A") return cont(poplex%2C statement)%3B%0A return pass(maybeoperator%2C expect("%3B")%2C poplex)%3B%0A }%0A function property(type) {%0A if (type %3D%3D "variable") {cx.marked %3D "property"%3B return cont()%3B}%0A }%0A function objprop(type) {%0A if (type %3D%3D "variable") cx.marked %3D "property"%3B%0A if (atomicTypes.hasOwnProperty(type)) return cont(expect("%3A")%2C expression)%3B%0A }%0A function commasep(what%2C end) {%0A function proceed(type) {%0A if (type %3D%3D "%2C") return cont(what%2C proceed)%3B%0A if (type %3D%3D end) return cont()%3B%0A return cont(expect(end))%3B%0A }%0A return function commaSeparated(type) {%0A if (type %3D%3D end) return cont()%3B%0A else return pass(what%2C proceed)%3B%0A }%3B%0A }%0A function block(type) {%0A if (type %3D%3D "}") return cont()%3B%0A return pass(statement%2C block)%3B%0A }%0A function vardef1(type%2C value) {%0A if (type %3D%3D "variable"){register(value)%3B return cont(vardef2)%3B}%0A return cont()%3B%0A }%0A function vardef2(type%2C value) {%0A if (value %3D%3D "%3D") return cont(expression%2C vardef2)%3B%0A if (type %3D%3D "%2C") return cont(vardef1)%3B%0A }%0A function forspec1(type) {%0A if (type %3D%3D "var") return cont(vardef1%2C forspec2)%3B%0A if (type %3D%3D "%3B") return pass(forspec2)%3B%0A if (type %3D%3D "variable") return cont(formaybein)%3B%0A return pass(forspec2)%3B%0A }%0A function formaybein(type%2C value) {%0A if (value %3D%3D "in") return cont(expression)%3B%0A return cont(maybeoperator%2C forspec2)%3B%0A }%0A function forspec2(type%2C value) {%0A if (type %3D%3D "%3B") return cont(forspec3)%3B%0A if (value %3D%3D "in") return cont(expression)%3B%0A return cont(expression%2C expect("%3B")%2C forspec3)%3B%0A }%0A function forspec3(type) {%0A if (type !%3D ")") cont(expression)%3B%0A }%0A function functiondef(type%2C value) {%0A if (type %3D%3D "variable") {register(value)%3B return cont(functiondef)%3B}%0A if (type %3D%3D "(") return cont(pushlex(")")%2C pushcontext%2C commasep(funarg%2C ")")%2C poplex%2C statement%2C popcontext)%3B%0A }%0A function funarg(type%2C value) {%0A if (type %3D%3D "variable") {register(value)%3B return cont()%3B}%0A }%0A%0A %2F%2F Interface%0A%0A return {%0A startState%3A function(basecolumn) {%0A return {%0A tokenize%3A jsTokenBase%2C%0A reAllowed%3A true%2C%0A kwAllowed%3A true%2C%0A cc%3A []%2C%0A lexical%3A new JSLexical((basecolumn || 0) - indentUnit%2C 0%2C "block"%2C false)%2C%0A localVars%3A parserConfig.localVars%2C%0A context%3A parserConfig.localVars %26%26 {vars%3A parserConfig.localVars}%2C%0A indented%3A 0%0A }%3B%0A }%2C%0A%0A token%3A function(stream%2C state) {%0A if (stream.sol()) {%0A if (!state.lexical.hasOwnProperty("align"))%0A state.lexical.align %3D false%3B%0A state.indented %3D stream.indentation()%3B%0A }%0A if (stream.eatSpace()) return null%3B%0A var style %3D state.tokenize(stream%2C state)%3B%0A if (type %3D%3D "comment") return style%3B%0A state.reAllowed %3D !!(type %3D%3D "operator" || type %3D%3D "keyword c" || type.match(%2F^[\[{}\(%2C%3B%3A]%24%2F))%3B%0A state.kwAllowed %3D type !%3D '.'%3B%0A return parseJS(state%2C style%2C type%2C content%2C stream)%3B%0A }%2C%0A%0A indent%3A function(state%2C textAfter) {%0A if (state.tokenize !%3D jsTokenBase) return 0%3B%0A var firstChar %3D textAfter %26%26 textAfter.charAt(0)%2C lexical %3D state.lexical%3B%0A if (lexical.type %3D%3D "stat" %26%26 firstChar %3D%3D "}") lexical %3D lexical.prev%3B%0A var type %3D lexical.type%2C closing %3D firstChar %3D%3D type%3B%0A if (type %3D%3D "vardef") return lexical.indented %2B 4%3B%0A else if (type %3D%3D "form" %26%26 firstChar %3D%3D "{") return lexical.indented%3B%0A else if (type %3D%3D "stat" || type %3D%3D "form") return lexical.indented %2B indentUnit%3B%0A else if (lexical.info %3D%3D "switch" %26%26 !closing)%0A return lexical.indented %2B (%2F^(%3F%3Acase|default)\b%2F.test(textAfter) %3F indentUnit %3A 2 * indentUnit)%3B%0A else if (lexical.align) return lexical.column %2B (closing %3F 0 %3A 1)%3B%0A else return lexical.indented %2B (closing %3F 0 %3A indentUnit)%3B%0A }%2C%0A%0A electricChars%3A "%3A{}"%0A }%3B%0A})%3B%0A%0ACodeMirror.defineMIME("text%2Fjavascript"%2C "javascript")%3B%0ACodeMirror.defineMIME("application%2Fjson"%2C {name%3A "javascript"%2C json%3A true})%3B%0A <%2Fscript>%0A %0A %0A %0A <!-- http%3A%2F%2Fcodemirror.net%2Fmode%2Fcss%2Fcss.js --><script>%0ACodeMirror.defineMode("css"%2C function(config) {%0A var indentUnit %3D config.indentUnit%2C type%3B%0A %0A var atMediaTypes %3D keySet([%0A "all"%2C "aural"%2C "braille"%2C "handheld"%2C "print"%2C "projection"%2C "screen"%2C%0A "tty"%2C "tv"%2C "embossed"%0A ])%3B%0A %0A var atMediaFeatures %3D keySet([%0A "width"%2C "min-width"%2C "max-width"%2C "height"%2C "min-height"%2C "max-height"%2C%0A "device-width"%2C "min-device-width"%2C "max-device-width"%2C "device-height"%2C%0A "min-device-height"%2C "max-device-height"%2C "aspect-ratio"%2C%0A "min-aspect-ratio"%2C "max-aspect-ratio"%2C "device-aspect-ratio"%2C%0A "min-device-aspect-ratio"%2C "max-device-aspect-ratio"%2C "color"%2C "min-color"%2C%0A "max-color"%2C "color-index"%2C "min-color-index"%2C "max-color-index"%2C%0A "monochrome"%2C "min-monochrome"%2C "max-monochrome"%2C "resolution"%2C%0A "min-resolution"%2C "max-resolution"%2C "scan"%2C "grid"%0A ])%3B%0A%0A var propertyKeywords %3D keySet([%0A "align-content"%2C "align-items"%2C "align-self"%2C "alignment-adjust"%2C%0A "alignment-baseline"%2C "anchor-point"%2C "animation"%2C "animation-delay"%2C%0A "animation-direction"%2C "animation-duration"%2C "animation-iteration-count"%2C%0A "animation-name"%2C "animation-play-state"%2C "animation-timing-function"%2C%0A "appearance"%2C "azimuth"%2C "backface-visibility"%2C "background"%2C%0A "background-attachment"%2C "background-clip"%2C "background-color"%2C%0A "background-image"%2C "background-origin"%2C "background-position"%2C%0A "background-repeat"%2C "background-size"%2C "baseline-shift"%2C "binding"%2C%0A "bleed"%2C "bookmark-label"%2C "bookmark-level"%2C "bookmark-state"%2C%0A "bookmark-target"%2C "border"%2C "border-bottom"%2C "border-bottom-color"%2C%0A "border-bottom-left-radius"%2C "border-bottom-right-radius"%2C%0A "border-bottom-style"%2C "border-bottom-width"%2C "border-collapse"%2C%0A "border-color"%2C "border-image"%2C "border-image-outset"%2C%0A "border-image-repeat"%2C "border-image-slice"%2C "border-image-source"%2C%0A "border-image-width"%2C "border-left"%2C "border-left-color"%2C%0A "border-left-style"%2C "border-left-width"%2C "border-radius"%2C "border-right"%2C%0A "border-right-color"%2C "border-right-style"%2C "border-right-width"%2C%0A "border-spacing"%2C "border-style"%2C "border-top"%2C "border-top-color"%2C%0A "border-top-left-radius"%2C "border-top-right-radius"%2C "border-top-style"%2C%0A "border-top-width"%2C "border-width"%2C "bottom"%2C "box-decoration-break"%2C%0A "box-shadow"%2C "box-sizing"%2C "break-after"%2C "break-before"%2C "break-inside"%2C%0A "caption-side"%2C "clear"%2C "clip"%2C "color"%2C "color-profile"%2C "column-count"%2C%0A "column-fill"%2C "column-gap"%2C "column-rule"%2C "column-rule-color"%2C%0A "column-rule-style"%2C "column-rule-width"%2C "column-span"%2C "column-width"%2C%0A "columns"%2C "content"%2C "counter-increment"%2C "counter-reset"%2C "crop"%2C "cue"%2C%0A "cue-after"%2C "cue-before"%2C "cursor"%2C "direction"%2C "display"%2C%0A "dominant-baseline"%2C "drop-initial-after-adjust"%2C%0A "drop-initial-after-align"%2C "drop-initial-before-adjust"%2C%0A "drop-initial-before-align"%2C "drop-initial-size"%2C "drop-initial-value"%2C%0A "elevation"%2C "empty-cells"%2C "fit"%2C "fit-position"%2C "flex"%2C "flex-basis"%2C%0A "flex-direction"%2C "flex-flow"%2C "flex-grow"%2C "flex-shrink"%2C "flex-wrap"%2C%0A "float"%2C "float-offset"%2C "font"%2C "font-feature-settings"%2C "font-family"%2C%0A "font-kerning"%2C "font-language-override"%2C "font-size"%2C "font-size-adjust"%2C%0A "font-stretch"%2C "font-style"%2C "font-synthesis"%2C "font-variant"%2C%0A "font-variant-alternates"%2C "font-variant-caps"%2C "font-variant-east-asian"%2C%0A "font-variant-ligatures"%2C "font-variant-numeric"%2C "font-variant-position"%2C%0A "font-weight"%2C "grid-cell"%2C "grid-column"%2C "grid-column-align"%2C%0A "grid-column-sizing"%2C "grid-column-span"%2C "grid-columns"%2C "grid-flow"%2C%0A "grid-row"%2C "grid-row-align"%2C "grid-row-sizing"%2C "grid-row-span"%2C%0A "grid-rows"%2C "grid-template"%2C "hanging-punctuation"%2C "height"%2C "hyphens"%2C%0A "icon"%2C "image-orientation"%2C "image-rendering"%2C "image-resolution"%2C%0A "inline-box-align"%2C "justify-content"%2C "left"%2C "letter-spacing"%2C%0A "line-break"%2C "line-height"%2C "line-stacking"%2C "line-stacking-ruby"%2C%0A "line-stacking-shift"%2C "line-stacking-strategy"%2C "list-style"%2C%0A "list-style-image"%2C "list-style-position"%2C "list-style-type"%2C "margin"%2C%0A "margin-bottom"%2C "margin-left"%2C "margin-right"%2C "margin-top"%2C%0A "marker-offset"%2C "marks"%2C "marquee-direction"%2C "marquee-loop"%2C%0A "marquee-play-count"%2C "marquee-speed"%2C "marquee-style"%2C "max-height"%2C%0A "max-width"%2C "min-height"%2C "min-width"%2C "move-to"%2C "nav-down"%2C "nav-index"%2C%0A "nav-left"%2C "nav-right"%2C "nav-up"%2C "opacity"%2C "order"%2C "orphans"%2C "outline"%2C%0A "outline-color"%2C "outline-offset"%2C "outline-style"%2C "outline-width"%2C%0A "overflow"%2C "overflow-style"%2C "overflow-wrap"%2C "overflow-x"%2C "overflow-y"%2C%0A "padding"%2C "padding-bottom"%2C "padding-left"%2C "padding-right"%2C "padding-top"%2C%0A "page"%2C "page-break-after"%2C "page-break-before"%2C "page-break-inside"%2C%0A "page-policy"%2C "pause"%2C "pause-after"%2C "pause-before"%2C "perspective"%2C%0A "perspective-origin"%2C "pitch"%2C "pitch-range"%2C "play-during"%2C "position"%2C%0A "presentation-level"%2C "punctuation-trim"%2C "quotes"%2C "rendering-intent"%2C%0A "resize"%2C "rest"%2C "rest-after"%2C "rest-before"%2C "richness"%2C "right"%2C%0A "rotation"%2C "rotation-point"%2C "ruby-align"%2C "ruby-overhang"%2C%0A "ruby-position"%2C "ruby-span"%2C "size"%2C "speak"%2C "speak-as"%2C "speak-header"%2C%0A "speak-numeral"%2C "speak-punctuation"%2C "speech-rate"%2C "stress"%2C "string-set"%2C%0A "tab-size"%2C "table-layout"%2C "target"%2C "target-name"%2C "target-new"%2C%0A "target-position"%2C "text-align"%2C "text-align-last"%2C "text-decoration"%2C%0A "text-decoration-color"%2C "text-decoration-line"%2C "text-decoration-skip"%2C%0A "text-decoration-style"%2C "text-emphasis"%2C "text-emphasis-color"%2C%0A "text-emphasis-position"%2C "text-emphasis-style"%2C "text-height"%2C%0A "text-indent"%2C "text-justify"%2C "text-outline"%2C "text-shadow"%2C%0A "text-space-collapse"%2C "text-transform"%2C "text-underline-position"%2C%0A "text-wrap"%2C "top"%2C "transform"%2C "transform-origin"%2C "transform-style"%2C%0A "transition"%2C "transition-delay"%2C "transition-duration"%2C%0A "transition-property"%2C "transition-timing-function"%2C "unicode-bidi"%2C%0A "vertical-align"%2C "visibility"%2C "voice-balance"%2C "voice-duration"%2C%0A "voice-family"%2C "voice-pitch"%2C "voice-range"%2C "voice-rate"%2C "voice-stress"%2C%0A "voice-volume"%2C "volume"%2C "white-space"%2C "widows"%2C "width"%2C "word-break"%2C%0A "word-spacing"%2C "word-wrap"%2C "z-index"%0A ])%3B%0A%0A var colorKeywords %3D keySet([%0A "black"%2C "silver"%2C "gray"%2C "white"%2C "maroon"%2C "red"%2C "purple"%2C "fuchsia"%2C%0A "green"%2C "lime"%2C "olive"%2C "yellow"%2C "navy"%2C "blue"%2C "teal"%2C "aqua"%0A ])%3B%0A %0A var valueKeywords %3D keySet([%0A "above"%2C "absolute"%2C "activeborder"%2C "activecaption"%2C "afar"%2C%0A "after-white-space"%2C "ahead"%2C "alias"%2C "all"%2C "all-scroll"%2C "alternate"%2C%0A "always"%2C "amharic"%2C "amharic-abegede"%2C "antialiased"%2C "appworkspace"%2C%0A "arabic-indic"%2C "armenian"%2C "asterisks"%2C "auto"%2C "avoid"%2C "background"%2C%0A "backwards"%2C "baseline"%2C "below"%2C "bidi-override"%2C "binary"%2C "bengali"%2C%0A "blink"%2C "block"%2C "block-axis"%2C "bold"%2C "bolder"%2C "border"%2C "border-box"%2C%0A "both"%2C "bottom"%2C "break-all"%2C "break-word"%2C "button"%2C "button-bevel"%2C%0A "buttonface"%2C "buttonhighlight"%2C "buttonshadow"%2C "buttontext"%2C "cambodian"%2C%0A "capitalize"%2C "caps-lock-indicator"%2C "caption"%2C "captiontext"%2C "caret"%2C%0A "cell"%2C "center"%2C "checkbox"%2C "circle"%2C "cjk-earthly-branch"%2C%0A "cjk-heavenly-stem"%2C "cjk-ideographic"%2C "clear"%2C "clip"%2C "close-quote"%2C%0A "col-resize"%2C "collapse"%2C "compact"%2C "condensed"%2C "contain"%2C "content"%2C%0A "content-box"%2C "context-menu"%2C "continuous"%2C "copy"%2C "cover"%2C "crop"%2C%0A "cross"%2C "crosshair"%2C "currentcolor"%2C "cursive"%2C "dashed"%2C "decimal"%2C%0A "decimal-leading-zero"%2C "default"%2C "default-button"%2C "destination-atop"%2C%0A "destination-in"%2C "destination-out"%2C "destination-over"%2C "devanagari"%2C%0A "disc"%2C "discard"%2C "document"%2C "dot-dash"%2C "dot-dot-dash"%2C "dotted"%2C%0A "double"%2C "down"%2C "e-resize"%2C "ease"%2C "ease-in"%2C "ease-in-out"%2C "ease-out"%2C%0A "element"%2C "ellipsis"%2C "embed"%2C "end"%2C "ethiopic"%2C "ethiopic-abegede"%2C%0A "ethiopic-abegede-am-et"%2C "ethiopic-abegede-gez"%2C "ethiopic-abegede-ti-er"%2C%0A "ethiopic-abegede-ti-et"%2C "ethiopic-halehame-aa-er"%2C%0A "ethiopic-halehame-aa-et"%2C "ethiopic-halehame-am-et"%2C%0A "ethiopic-halehame-gez"%2C "ethiopic-halehame-om-et"%2C%0A "ethiopic-halehame-sid-et"%2C "ethiopic-halehame-so-et"%2C%0A "ethiopic-halehame-ti-er"%2C "ethiopic-halehame-ti-et"%2C%0A "ethiopic-halehame-tig"%2C "ew-resize"%2C "expanded"%2C "extra-condensed"%2C%0A "extra-expanded"%2C "fantasy"%2C "fast"%2C "fill"%2C "fixed"%2C "flat"%2C "footnotes"%2C%0A "forwards"%2C "from"%2C "geometricPrecision"%2C "georgian"%2C "graytext"%2C "groove"%2C%0A "gujarati"%2C "gurmukhi"%2C "hand"%2C "hangul"%2C "hangul-consonant"%2C "hebrew"%2C%0A "help"%2C "hidden"%2C "hide"%2C "higher"%2C "highlight"%2C "highlighttext"%2C%0A "hiragana"%2C "hiragana-iroha"%2C "horizontal"%2C "hsl"%2C "hsla"%2C "icon"%2C "ignore"%2C%0A "inactiveborder"%2C "inactivecaption"%2C "inactivecaptiontext"%2C "infinite"%2C%0A "infobackground"%2C "infotext"%2C "inherit"%2C "initial"%2C "inline"%2C "inline-axis"%2C%0A "inline-block"%2C "inline-table"%2C "inset"%2C "inside"%2C "intrinsic"%2C "invert"%2C%0A "italic"%2C "justify"%2C "kannada"%2C "katakana"%2C "katakana-iroha"%2C "khmer"%2C%0A "landscape"%2C "lao"%2C "large"%2C "larger"%2C "left"%2C "level"%2C "lighter"%2C%0A "line-through"%2C "linear"%2C "lines"%2C "list-item"%2C "listbox"%2C "listitem"%2C%0A "local"%2C "logical"%2C "loud"%2C "lower"%2C "lower-alpha"%2C "lower-armenian"%2C%0A "lower-greek"%2C "lower-hexadecimal"%2C "lower-latin"%2C "lower-norwegian"%2C%0A "lower-roman"%2C "lowercase"%2C "ltr"%2C "malayalam"%2C "match"%2C%0A "media-controls-background"%2C "media-current-time-display"%2C%0A "media-fullscreen-button"%2C "media-mute-button"%2C "media-play-button"%2C%0A "media-return-to-realtime-button"%2C "media-rewind-button"%2C%0A "media-seek-back-button"%2C "media-seek-forward-button"%2C "media-slider"%2C%0A "media-sliderthumb"%2C "media-time-remaining-display"%2C "media-volume-slider"%2C%0A "media-volume-slider-container"%2C "media-volume-sliderthumb"%2C "medium"%2C%0A "menu"%2C "menulist"%2C "menulist-button"%2C "menulist-text"%2C%0A "menulist-textfield"%2C "menutext"%2C "message-box"%2C "middle"%2C "min-intrinsic"%2C%0A "mix"%2C "mongolian"%2C "monospace"%2C "move"%2C "multiple"%2C "myanmar"%2C "n-resize"%2C%0A "narrower"%2C "navy"%2C "ne-resize"%2C "nesw-resize"%2C "no-close-quote"%2C "no-drop"%2C%0A "no-open-quote"%2C "no-repeat"%2C "none"%2C "normal"%2C "not-allowed"%2C "nowrap"%2C%0A "ns-resize"%2C "nw-resize"%2C "nwse-resize"%2C "oblique"%2C "octal"%2C "open-quote"%2C%0A "optimizeLegibility"%2C "optimizeSpeed"%2C "oriya"%2C "oromo"%2C "outset"%2C%0A "outside"%2C "overlay"%2C "overline"%2C "padding"%2C "padding-box"%2C "painted"%2C%0A "paused"%2C "persian"%2C "plus-darker"%2C "plus-lighter"%2C "pointer"%2C "portrait"%2C%0A "pre"%2C "pre-line"%2C "pre-wrap"%2C "preserve-3d"%2C "progress"%2C "push-button"%2C%0A "radio"%2C "read-only"%2C "read-write"%2C "read-write-plaintext-only"%2C "relative"%2C%0A "repeat"%2C "repeat-x"%2C "repeat-y"%2C "reset"%2C "reverse"%2C "rgb"%2C "rgba"%2C%0A "ridge"%2C "right"%2C "round"%2C "row-resize"%2C "rtl"%2C "run-in"%2C "running"%2C%0A "s-resize"%2C "sans-serif"%2C "scroll"%2C "scrollbar"%2C "se-resize"%2C "searchfield"%2C%0A "searchfield-cancel-button"%2C "searchfield-decoration"%2C%0A "searchfield-results-button"%2C "searchfield-results-decoration"%2C%0A "semi-condensed"%2C "semi-expanded"%2C "separate"%2C "serif"%2C "show"%2C "sidama"%2C%0A "single"%2C "skip-white-space"%2C "slide"%2C "slider-horizontal"%2C%0A "slider-vertical"%2C "sliderthumb-horizontal"%2C "sliderthumb-vertical"%2C "slow"%2C%0A "small"%2C "small-caps"%2C "small-caption"%2C "smaller"%2C "solid"%2C "somali"%2C%0A "source-atop"%2C "source-in"%2C "source-out"%2C "source-over"%2C "space"%2C "square"%2C%0A "square-button"%2C "start"%2C "static"%2C "status-bar"%2C "stretch"%2C "stroke"%2C%0A "sub"%2C "subpixel-antialiased"%2C "super"%2C "sw-resize"%2C "table"%2C%0A "table-caption"%2C "table-cell"%2C "table-column"%2C "table-column-group"%2C%0A "table-footer-group"%2C "table-header-group"%2C "table-row"%2C "table-row-group"%2C%0A "telugu"%2C "text"%2C "text-bottom"%2C "text-top"%2C "textarea"%2C "textfield"%2C "thai"%2C%0A "thick"%2C "thin"%2C "threeddarkshadow"%2C "threedface"%2C "threedhighlight"%2C%0A "threedlightshadow"%2C "threedshadow"%2C "tibetan"%2C "tigre"%2C "tigrinya-er"%2C%0A "tigrinya-er-abegede"%2C "tigrinya-et"%2C "tigrinya-et-abegede"%2C "to"%2C "top"%2C%0A "transparent"%2C "ultra-condensed"%2C "ultra-expanded"%2C "underline"%2C "up"%2C%0A "upper-alpha"%2C "upper-armenian"%2C "upper-greek"%2C "upper-hexadecimal"%2C%0A "upper-latin"%2C "upper-norwegian"%2C "upper-roman"%2C "uppercase"%2C "urdu"%2C "url"%2C%0A "vertical"%2C "vertical-text"%2C "visible"%2C "visibleFill"%2C "visiblePainted"%2C%0A "visibleStroke"%2C "visual"%2C "w-resize"%2C "wait"%2C "wave"%2C "white"%2C "wider"%2C%0A "window"%2C "windowframe"%2C "windowtext"%2C "x-large"%2C "x-small"%2C "xor"%2C%0A "xx-large"%2C "xx-small"%2C "yellow"%0A ])%3B%0A%0A function keySet(array) { var keys %3D {}%3B for (var i %3D 0%3B i < array.length%3B %2B%2Bi) keys[array[i]] %3D true%3B return keys%3B }%0A function ret(style%2C tp) {type %3D tp%3B return style%3B}%0A%0A function tokenBase(stream%2C state) {%0A var ch %3D stream.next()%3B%0A if (ch %3D%3D "%40") {stream.eatWhile(%2F[\w\\\-]%2F)%3B return ret("def"%2C stream.current())%3B}%0A else if (ch %3D%3D "%2F" %26%26 stream.eat("*")) {%0A state.tokenize %3D tokenCComment%3B%0A return tokenCComment(stream%2C state)%3B%0A }%0A else if (ch %3D%3D "<" %26%26 stream.eat("!")) {%0A state.tokenize %3D tokenSGMLComment%3B%0A return tokenSGMLComment(stream%2C state)%3B%0A }%0A else if (ch %3D%3D "%3D") ret(null%2C "compare")%3B%0A else if ((ch %3D%3D "~" || ch %3D%3D "|") %26%26 stream.eat("%3D")) return ret(null%2C "compare")%3B%0A else if (ch %3D%3D "\"" || ch %3D%3D "'") {%0A state.tokenize %3D tokenString(ch)%3B%0A return state.tokenize(stream%2C state)%3B%0A }%0A else if (ch %3D%3D "%23") {%0A stream.eatWhile(%2F[\w\\\-]%2F)%3B%0A return ret("atom"%2C "hash")%3B%0A }%0A else if (ch %3D%3D "!") {%0A stream.match(%2F^\s*\w*%2F)%3B%0A return ret("keyword"%2C "important")%3B%0A }%0A else if (%2F\d%2F.test(ch)) {%0A stream.eatWhile(%2F[\w.%25]%2F)%3B%0A return ret("number"%2C "unit")%3B%0A }%0A else if (ch %3D%3D%3D "-") {%0A if (%2F\d%2F.test(stream.peek())) {%0A stream.eatWhile(%2F[\w.%25]%2F)%3B%0A return ret("number"%2C "unit")%3B%0A } else if (stream.match(%2F^[^-]%2B-%2F)) {%0A return ret("meta"%2C type)%3B%0A }%0A }%0A else if (%2F[%2C%2B>*\%2F]%2F.test(ch)) {%0A return ret(null%2C "select-op")%3B%0A }%0A else if (ch %3D%3D "." %26%26 stream.match(%2F^\w%2B%2F)) {%0A return ret("qualifier"%2C type)%3B%0A }%0A else if (ch %3D%3D "%3A") {%0A return ret("operator"%2C ch)%3B%0A }%0A else if (%2F[%3B{}\[\]\(\)]%2F.test(ch)) {%0A return ret(null%2C ch)%3B%0A }%0A else {%0A stream.eatWhile(%2F[\w\\\-]%2F)%3B%0A return ret("property"%2C "variable")%3B%0A }%0A }%0A%0A function tokenCComment(stream%2C state) {%0A var maybeEnd %3D false%2C ch%3B%0A while ((ch %3D stream.next()) !%3D null) {%0A if (maybeEnd %26%26 ch %3D%3D "%2F") {%0A state.tokenize %3D tokenBase%3B%0A break%3B%0A }%0A maybeEnd %3D (ch %3D%3D "*")%3B%0A }%0A return ret("comment"%2C "comment")%3B%0A }%0A%0A function tokenSGMLComment(stream%2C state) {%0A var dashes %3D 0%2C ch%3B%0A while ((ch %3D stream.next()) !%3D null) {%0A if (dashes >%3D 2 %26%26 ch %3D%3D ">") {%0A state.tokenize %3D tokenBase%3B%0A break%3B%0A }%0A dashes %3D (ch %3D%3D "-") %3F dashes %2B 1 %3A 0%3B%0A }%0A return ret("comment"%2C "comment")%3B%0A }%0A%0A function tokenString(quote) {%0A return function(stream%2C state) {%0A var escaped %3D false%2C ch%3B%0A while ((ch %3D stream.next()) !%3D null) {%0A if (ch %3D%3D quote %26%26 !escaped)%0A break%3B%0A escaped %3D !escaped %26%26 ch %3D%3D "\\"%3B%0A }%0A if (!escaped) state.tokenize %3D tokenBase%3B%0A return ret("string"%2C "string")%3B%0A }%3B%0A }%0A%0A return {%0A startState%3A function(base) {%0A return {tokenize%3A tokenBase%2C%0A baseIndent%3A base || 0%2C%0A stack%3A []}%3B%0A }%2C%0A%0A token%3A function(stream%2C state) {%0A %0A %2F%2F Use these terms when applicable (see http%3A%2F%2Fwww.xanthir.com%2Fblog%2Fb4E50)%0A %2F%2F %0A %2F%2F rule** or **ruleset%3A%0A %2F%2F A selector %2B braces combo%2C or an at-rule.%0A %2F%2F %0A %2F%2F declaration block%3A%0A %2F%2F A sequence of declarations.%0A %2F%2F %0A %2F%2F declaration%3A%0A %2F%2F A property %2B colon %2B value combo.%0A %2F%2F %0A %2F%2F property value%3A%0A %2F%2F The entire value of a property.%0A %2F%2F %0A %2F%2F component value%3A%0A %2F%2F A single piece of a property value. Like the 5px in%0A %2F%2F text-shadow%3A 0 0 5px blue%3B. Can also refer to things that are%0A %2F%2F multiple terms%2C like the 1-4 terms that make up the background-size%0A %2F%2F portion of the background shorthand.%0A %2F%2F %0A %2F%2F term%3A%0A %2F%2F The basic unit of author-facing CSS%2C like a single number (5)%2C%0A %2F%2F dimension (5px)%2C string ("foo")%2C or function. Officially defined%0A %2F%2F by the CSS 2.1 grammar (look for the 'term' production)%0A %2F%2F %0A %2F%2F %0A %2F%2F simple selector%3A%0A %2F%2F A single atomic selector%2C like a type selector%2C an attr selector%2C a%0A %2F%2F class selector%2C etc.%0A %2F%2F %0A %2F%2F compound selector%3A%0A %2F%2F One or more simple selectors without a combinator. div.example is%0A %2F%2F compound%2C div > .example is not.%0A %2F%2F %0A %2F%2F complex selector%3A%0A %2F%2F One or more compound selectors chained with combinators.%0A %2F%2F %0A %2F%2F combinator%3A%0A %2F%2F The parts of selectors that express relationships. There are four%0A %2F%2F currently - the space (descendant combinator)%2C the greater-than%0A %2F%2F bracket (child combinator)%2C the plus sign (next sibling combinator)%2C%0A %2F%2F and the tilda (following sibling combinator).%0A %2F%2F %0A %2F%2F sequence of selectors%3A%0A %2F%2F One or more of the named type of selector chained with commas.%0A%0A if (stream.eatSpace()) return null%3B%0A var style %3D state.tokenize(stream%2C state)%3B%0A%0A %2F%2F Changing style returned based on context%0A var context %3D state.stack[state.stack.length-1]%3B%0A if (style %3D%3D "property") {%0A if (context %3D%3D "propertyValue"){%0A if (valueKeywords[stream.current()]) {%0A style %3D "string-2"%3B%0A } else if (colorKeywords[stream.current()]) {%0A style %3D "keyword"%3B%0A } else {%0A style %3D "variable-2"%3B%0A }%0A } else if (context %3D%3D "rule") {%0A if (!propertyKeywords[stream.current()]) {%0A style %2B%3D " error"%3B%0A }%0A } else if (!context || context %3D%3D "%40media{") {%0A style %3D "tag"%3B%0A } else if (context %3D%3D "%40media") {%0A if (atMediaTypes[stream.current()]) {%0A style %3D "attribute"%3B %2F%2F Known attribute%0A } else if (%2F^(only|not)%24%2Fi.test(stream.current())) {%0A style %3D "keyword"%3B%0A } else if (stream.current().toLowerCase() %3D%3D "and") {%0A style %3D "error"%3B %2F%2F "and" is only allowed in %40mediaType%0A } else if (atMediaFeatures[stream.current()]) {%0A style %3D "error"%3B %2F%2F Known property%2C should be in %40mediaType(%0A } else {%0A %2F%2F Unknown%2C expecting keyword or attribute%2C assuming attribute%0A style %3D "attribute error"%3B%0A }%0A } else if (context %3D%3D "%40mediaType") {%0A if (atMediaTypes[stream.current()]) {%0A style %3D "attribute"%3B%0A } else if (stream.current().toLowerCase() %3D%3D "and") {%0A style %3D "operator"%3B%0A } else if (%2F^(only|not)%24%2Fi.test(stream.current())) {%0A style %3D "error"%3B %2F%2F Only allowed in %40media%0A } else if (atMediaFeatures[stream.current()]) {%0A style %3D "error"%3B %2F%2F Known property%2C should be in parentheses%0A } else {%0A %2F%2F Unknown attribute or property%2C but expecting property (preceded%0A %2F%2F by "and"). Should be in parentheses%0A style %3D "error"%3B%0A }%0A } else if (context %3D%3D "%40mediaType(") {%0A if (propertyKeywords[stream.current()]) {%0A %2F%2F do nothing%2C remains "property"%0A } else if (atMediaTypes[stream.current()]) {%0A style %3D "error"%3B %2F%2F Known property%2C should be in parentheses%0A } else if (stream.current().toLowerCase() %3D%3D "and") {%0A style %3D "operator"%3B%0A } else if (%2F^(only|not)%24%2Fi.test(stream.current())) {%0A style %3D "error"%3B %2F%2F Only allowed in %40media%0A } else {%0A style %2B%3D " error"%3B%0A }%0A } else {%0A style %3D "error"%3B%0A }%0A } else if (style %3D%3D "atom") {%0A if(!context || context %3D%3D "%40media{") {%0A style %3D "builtin"%3B%0A } else if (context %3D%3D "propertyValue") {%0A if (!%2F^%23([0-9a-fA-f]{3}|[0-9a-fA-f]{6})%24%2F.test(stream.current())) {%0A style %2B%3D " error"%3B%0A }%0A } else {%0A style %3D "error"%3B%0A }%0A } else if (context %3D%3D "%40media" %26%26 type %3D%3D "{") {%0A style %3D "error"%3B%0A }%0A%0A %2F%2F Push%2Fpop context stack%0A if (type %3D%3D "{") {%0A if (context %3D%3D "%40media" || context %3D%3D "%40mediaType") {%0A state.stack.pop()%3B%0A state.stack[state.stack.length-1] %3D "%40media{"%3B%0A }%0A else state.stack.push("rule")%3B%0A }%0A else if (type %3D%3D "}") {%0A state.stack.pop()%3B%0A if (context %3D%3D "propertyValue") state.stack.pop()%3B%0A }%0A else if (type %3D%3D "%40media") state.stack.push("%40media")%3B%0A else if (context %3D%3D "%40media" %26%26 %2F\b(keyword|attribute)\b%2F.test(style))%0A state.stack.push("%40mediaType")%3B%0A else if (context %3D%3D "%40mediaType" %26%26 stream.current() %3D%3D "%2C") state.stack.pop()%3B%0A else if (context %3D%3D "%40mediaType" %26%26 type %3D%3D "(") state.stack.push("%40mediaType(")%3B%0A else if (context %3D%3D "%40mediaType(" %26%26 type %3D%3D ")") state.stack.pop()%3B%0A else if (context %3D%3D "rule" %26%26 type %3D%3D "%3A") state.stack.push("propertyValue")%3B%0A else if (context %3D%3D "propertyValue" %26%26 type %3D%3D "%3B") state.stack.pop()%3B%0A return style%3B%0A }%2C%0A%0A indent%3A function(state%2C textAfter) {%0A var n %3D state.stack.length%3B%0A if (%2F^\}%2F.test(textAfter))%0A n -%3D state.stack[state.stack.length-1] %3D%3D "propertyValue" %3F 2 %3A 1%3B%0A return state.baseIndent %2B n * indentUnit%3B%0A }%2C%0A%0A electricChars%3A "}"%0A }%3B%0A})%3B%0A%0ACodeMirror.defineMIME("text%2Fcss"%2C "css")%3B%0A <%2Fscript>%0A %0A %0A %0A <!-- http%3A%2F%2Fcodemirror.net%2Fmode%2Fhtmlmixed%2Fhtmlmixed.js --><script>%0ACodeMirror.defineMode("htmlmixed"%2C function(config) {%0A var htmlMode %3D CodeMirror.getMode(config%2C {name%3A "xml"%2C htmlMode%3A true})%3B%0A var jsMode %3D CodeMirror.getMode(config%2C "javascript")%3B%0A var cssMode %3D CodeMirror.getMode(config%2C "css")%3B%0A%0A function html(stream%2C state) {%0A var style %3D htmlMode.token(stream%2C state.htmlState)%3B%0A if (style %3D%3D "tag" %26%26 stream.current() %3D%3D ">" %26%26 state.htmlState.context) {%0A if (%2F^script%24%2Fi.test(state.htmlState.context.tagName)) {%0A state.token %3D javascript%3B%0A state.localState %3D jsMode.startState(htmlMode.indent(state.htmlState%2C ""))%3B%0A }%0A else if (%2F^style%24%2Fi.test(state.htmlState.context.tagName)) {%0A state.token %3D css%3B%0A state.localState %3D cssMode.startState(htmlMode.indent(state.htmlState%2C ""))%3B%0A }%0A }%0A return style%3B%0A }%0A function maybeBackup(stream%2C pat%2C style) {%0A var cur %3D stream.current()%3B%0A var close %3D cur.search(pat)%2C m%3B%0A if (close > -1) stream.backUp(cur.length - close)%3B%0A else if (m %3D cur.match(%2F<\%2F%3F%24%2F)) {%0A stream.backUp(cur[0].length)%3B%0A if (!stream.match(pat%2C false)) stream.match(cur[0])%3B%0A }%0A return style%3B%0A }%0A function javascript(stream%2C state) {%0A if (stream.match(%2F^<\%2F\s*script\s*>%2Fi%2C false)) {%0A state.token %3D html%3B%0A state.localState %3D null%3B%0A return html(stream%2C state)%3B%0A }%0A return maybeBackup(stream%2C %2F<\%2F\s*script\s*>%2F%2C%0A jsMode.token(stream%2C state.localState))%3B%0A }%0A function css(stream%2C state) {%0A if (stream.match(%2F^<\%2F\s*style\s*>%2Fi%2C false)) {%0A state.token %3D html%3B%0A state.localState %3D null%3B%0A return html(stream%2C state)%3B%0A }%0A return maybeBackup(stream%2C %2F<\%2F\s*style\s*>%2F%2C%0A cssMode.token(stream%2C state.localState))%3B%0A }%0A%0A return {%0A startState%3A function() {%0A var state %3D htmlMode.startState()%3B%0A return {token%3A html%2C localState%3A null%2C mode%3A "html"%2C htmlState%3A state}%3B%0A }%2C%0A%0A copyState%3A function(state) {%0A if (state.localState)%0A var local %3D CodeMirror.copyState(state.token %3D%3D css %3F cssMode %3A jsMode%2C state.localState)%3B%0A return {token%3A state.token%2C localState%3A local%2C mode%3A state.mode%2C%0A htmlState%3A CodeMirror.copyState(htmlMode%2C state.htmlState)}%3B%0A }%2C%0A%0A token%3A function(stream%2C state) {%0A return state.token(stream%2C state)%3B%0A }%2C%0A%0A indent%3A function(state%2C textAfter) {%0A if (state.token %3D%3D html || %2F^\s*<\%2F%2F.test(textAfter))%0A return htmlMode.indent(state.htmlState%2C textAfter)%3B%0A else if (state.token %3D%3D javascript)%0A return jsMode.indent(state.localState%2C textAfter)%3B%0A else%0A return cssMode.indent(state.localState%2C textAfter)%3B%0A }%2C%0A%0A electricChars%3A "%2F{}%3A"%2C%0A%0A innerMode%3A function(state) {%0A var mode %3D state.token %3D%3D html %3F htmlMode %3A state.token %3D%3D javascript %3F jsMode %3A cssMode%3B%0A return {state%3A state.localState || state.htmlState%2C mode%3A mode}%3B%0A }%0A }%3B%0A}%2C "xml"%2C "javascript"%2C "css")%3B%0A%0ACodeMirror.defineMIME("text%2Fhtml"%2C "htmlmixed")%3B%0A <%2Fscript>%0A %0A %0A %0A <!-- http%3A%2F%2Fcodemirror.net%2Fmode%2Fmarkdown%2Fmarkdown.js --><script>%0ACodeMirror.defineMode("markdown"%2C function(cmCfg%2C modeCfg) {%0A%0A var htmlFound %3D CodeMirror.mimeModes.hasOwnProperty("text%2Fhtml")%3B%0A var htmlMode %3D CodeMirror.getMode(cmCfg%2C htmlFound %3F "text%2Fhtml" %3A "text%2Fplain")%3B%0A %0A var codeDepth %3D 0%3B%0A var prevLineHasContent %3D false%0A %2C thisLineHasContent %3D false%3B%0A%0A var header %3D 'header'%0A %2C code %3D 'comment'%0A %2C quote %3D 'quote'%0A %2C list %3D 'string'%0A %2C hr %3D 'hr'%0A %2C linkinline %3D 'link'%0A %2C linkemail %3D 'link'%0A %2C linktext %3D 'link'%0A %2C linkhref %3D 'string'%0A %2C em %3D 'em'%0A %2C strong %3D 'strong'%0A %2C emstrong %3D 'emstrong'%3B%0A%0A var hrRE %3D %2F^([*\-%3D_])(%3F%3A\s*\1){2%2C}\s*%24%2F%0A %2C ulRE %3D %2F^[*\-%2B]\s%2B%2F%0A %2C olRE %3D %2F^[0-9]%2B\.\s%2B%2F%0A %2C headerRE %3D %2F^(%3F%3A\%3D{1%2C}|-{1%2C})%24%2F%0A %2C textRE %3D %2F^[^\[*_\\<>` "'(]%2B%2F%3B%0A%0A function switchInline(stream%2C state%2C f) {%0A state.f %3D state.inline %3D f%3B%0A return f(stream%2C state)%3B%0A }%0A%0A function switchBlock(stream%2C state%2C f) {%0A state.f %3D state.block %3D f%3B%0A return f(stream%2C state)%3B%0A }%0A%0A%0A %2F%2F Blocks%0A%0A function blankLine(state) {%0A %2F%2F Reset linkTitle state%0A state.linkTitle %3D false%3B%0A %2F%2F Reset CODE state%0A state.code %3D false%3B%0A %2F%2F Reset EM state%0A state.em %3D false%3B%0A %2F%2F Reset STRONG state%0A state.strong %3D false%3B%0A %2F%2F Reset state.quote%0A state.quote %3D false%3B%0A if (!htmlFound %26%26 state.f %3D%3D htmlBlock) {%0A state.f %3D inlineNormal%3B%0A state.block %3D blockNormal%3B%0A }%0A return null%3B%0A }%0A%0A function blockNormal(stream%2C state) {%0A var match%3B%0A %0A if (state.list !%3D%3D false %26%26 state.indentationDiff >%3D 0) { %2F%2F Continued list%0A if (state.indentationDiff < 4) { %2F%2F Only adjust indentation if *not* a code block%0A state.indentation -%3D state.indentationDiff%3B%0A }%0A state.list %3D null%3B%0A } else { %2F%2F No longer a list%0A state.list %3D false%3B%0A }%0A %0A if (state.indentationDiff >%3D 4) {%0A state.indentation -%3D 4%3B%0A stream.skipToEnd()%3B%0A return code%3B%0A } else if (stream.eatSpace()) {%0A return null%3B%0A } else if (stream.peek() %3D%3D%3D '%23' || (prevLineHasContent %26%26 stream.match(headerRE)) ) {%0A state.header %3D true%3B%0A } else if (stream.eat('>')) {%0A state.indentation%2B%2B%3B%0A state.quote %3D true%3B%0A } else if (stream.peek() %3D%3D%3D '[') {%0A return switchInline(stream%2C state%2C footnoteLink)%3B%0A } else if (stream.match(hrRE%2C true)) {%0A return hr%3B%0A } else if (match %3D stream.match(ulRE%2C true) || stream.match(olRE%2C true)) {%0A state.indentation %2B%3D 4%3B%0A state.list %3D true%3B%0A }%0A %0A return switchInline(stream%2C state%2C state.inline)%3B%0A }%0A%0A function htmlBlock(stream%2C state) {%0A var style %3D htmlMode.token(stream%2C state.htmlState)%3B%0A if (htmlFound %26%26 style %3D%3D%3D 'tag' %26%26 state.htmlState.type !%3D%3D 'openTag' %26%26 !state.htmlState.context) {%0A state.f %3D inlineNormal%3B%0A state.block %3D blockNormal%3B%0A }%0A if (state.md_inside %26%26 stream.current().indexOf(">")!%3D-1) {%0A state.f %3D inlineNormal%3B%0A state.block %3D blockNormal%3B%0A state.htmlState.context %3D undefined%3B%0A }%0A return style%3B%0A }%0A%0A%0A %2F%2F Inline%0A function getType(state) {%0A var styles %3D []%3B%0A %0A if (state.strong) { styles.push(state.em %3F emstrong %3A strong)%3B }%0A else if (state.em) { styles.push(em)%3B }%0A %0A if (state.code) { styles.push(code)%3B }%0A %0A if (state.header) { styles.push(header)%3B }%0A if (state.quote) { styles.push(quote)%3B }%0A if (state.list !%3D%3D false) { styles.push(list)%3B }%0A%0A return styles.length %3F styles.join(' ') %3A null%3B%0A }%0A%0A function handleText(stream%2C state) {%0A if (stream.match(textRE%2C true)) {%0A return getType(state)%3B%0A }%0A return undefined%3B %0A }%0A%0A function inlineNormal(stream%2C state) {%0A var style %3D state.text(stream%2C state)%3B%0A if (typeof style !%3D%3D 'undefined')%0A return style%3B%0A %0A if (state.list) { %2F%2F List marker (*%2C %2B%2C -%2C 1.%2C etc)%0A state.list %3D null%3B%0A return list%3B%0A }%0A %0A var ch %3D stream.next()%3B%0A %0A if (ch %3D%3D%3D '\\') {%0A stream.next()%3B%0A return getType(state)%3B%0A }%0A %0A %2F%2F Matches link titles present on next line%0A if (state.linkTitle) {%0A state.linkTitle %3D false%3B%0A var matchCh %3D ch%3B%0A if (ch %3D%3D%3D '(') {%0A matchCh %3D ')'%3B%0A }%0A matchCh %3D (matchCh%2B'').replace(%2F([.%3F*%2B^%24[\]\\(){}|-])%2Fg%2C "\\%241")%3B%0A var regex %3D '^\\s*(%3F%3A[^' %2B matchCh %2B '\\\\]%2B|\\\\\\\\|\\\\.)' %2B matchCh%3B%0A if (stream.match(new RegExp(regex)%2C true)) {%0A return linkhref%3B%0A }%0A }%0A %0A if (ch %3D%3D%3D '`') {%0A var t %3D getType(state)%3B%0A var before %3D stream.pos%3B%0A stream.eatWhile('`')%3B%0A var difference %3D 1 %2B stream.pos - before%3B%0A if (!state.code) {%0A codeDepth %3D difference%3B%0A state.code %3D true%3B%0A return getType(state)%3B%0A } else {%0A if (difference %3D%3D%3D codeDepth) { %2F%2F Must be exact%0A state.code %3D false%3B%0A return t%3B%0A }%0A return getType(state)%3B%0A }%0A } else if (state.code) {%0A return getType(state)%3B%0A }%0A %0A if (ch %3D%3D%3D '[' %26%26 stream.match(%2F.*\] %3F(%3F%3A\(|\[)%2F%2C false)) {%0A return switchInline(stream%2C state%2C linkText)%3B%0A }%0A %0A if (ch %3D%3D%3D '<' %26%26 stream.match(%2F^(https%3F|ftps%3F)%3A\%2F\%2F(%3F%3A[^\\>]|\\.)%2B>%2F%2C true)) {%0A return switchInline(stream%2C state%2C inlineElement(linkinline%2C '>'))%3B%0A }%0A %0A if (ch %3D%3D%3D '<' %26%26 stream.match(%2F^[^> \\]%2B%40(%3F%3A[^\\>]|\\.)%2B>%2F%2C true)) {%0A return switchInline(stream%2C state%2C inlineElement(linkemail%2C '>'))%3B%0A }%0A %0A if (ch %3D%3D%3D '<' %26%26 stream.match(%2F^\w%2F%2C false)) {%0A var md_inside %3D false%3B%0A if (stream.string.indexOf(">")!%3D-1) {%0A var atts %3D stream.string.substring(1%2Cstream.string.indexOf(">"))%3B%0A if (%2Fmarkdown\s*%3D\s*('|"){0%2C1}1('|"){0%2C1}%2F.test(atts)) {%0A state.md_inside %3D true%3B%0A }%0A }%0A stream.backUp(1)%3B%0A return switchBlock(stream%2C state%2C htmlBlock)%3B%0A }%0A %0A if (ch %3D%3D%3D '<' %26%26 stream.match(%2F^\%2F\w*%3F>%2F)) {%0A state.md_inside %3D false%3B%0A return "tag"%3B%0A }%0A %0A var t %3D getType(state)%3B%0A if (ch %3D%3D%3D '*' || ch %3D%3D%3D '_') {%0A if (state.strong %3D%3D%3D ch %26%26 stream.eat(ch)) { %2F%2F Remove STRONG%0A state.strong %3D false%3B%0A return t%3B%0A } else if (!state.strong %26%26 stream.eat(ch)) { %2F%2F Add STRONG%0A state.strong %3D ch%3B%0A return getType(state)%3B%0A } else if (state.em %3D%3D%3D ch) { %2F%2F Remove EM%0A state.em %3D false%3B%0A return t%3B%0A } else if (!state.em) { %2F%2F Add EM%0A state.em %3D ch%3B%0A return getType(state)%3B%0A }%0A } else if (ch %3D%3D%3D ' ') {%0A if (stream.eat('*') || stream.eat('_')) { %2F%2F Probably surrounded by spaces%0A if (stream.peek() %3D%3D%3D ' ') { %2F%2F Surrounded by spaces%2C ignore%0A return getType(state)%3B%0A } else { %2F%2F Not surrounded by spaces%2C back up pointer%0A stream.backUp(1)%3B%0A }%0A }%0A }%0A %0A return getType(state)%3B%0A }%0A%0A function linkText(stream%2C state) {%0A while (!stream.eol()) {%0A var ch %3D stream.next()%3B%0A if (ch %3D%3D%3D '\\') stream.next()%3B%0A if (ch %3D%3D%3D ']') {%0A state.inline %3D state.f %3D linkHref%3B%0A return linktext%3B%0A }%0A }%0A return linktext%3B%0A }%0A%0A function linkHref(stream%2C state) {%0A %2F%2F Check if space%2C and return NULL if so (to avoid marking the space)%0A if(stream.eatSpace()){%0A return null%3B%0A }%0A var ch %3D stream.next()%3B%0A if (ch %3D%3D%3D '(' || ch %3D%3D%3D '[') {%0A return switchInline(stream%2C state%2C inlineElement(linkhref%2C ch %3D%3D%3D '(' %3F ')' %3A ']'))%3B%0A }%0A return 'error'%3B%0A }%0A%0A function footnoteLink(stream%2C state) {%0A if (stream.match(%2F^[^\]]*\]%3A%2F%2C true)) {%0A state.f %3D footnoteUrl%3B%0A return linktext%3B%0A }%0A return switchInline(stream%2C state%2C inlineNormal)%3B%0A }%0A%0A function footnoteUrl(stream%2C state) {%0A %2F%2F Check if space%2C and return NULL if so (to avoid marking the space)%0A if(stream.eatSpace()){%0A return null%3B%0A }%0A %2F%2F Match URL%0A stream.match(%2F^[^\s]%2B%2F%2C true)%3B%0A %2F%2F Check for link title%0A if (stream.peek() %3D%3D%3D undefined) { %2F%2F End of line%2C set flag to check next line%0A state.linkTitle %3D true%3B%0A } else { %2F%2F More content on line%2C check if link title%0A stream.match(%2F^(%3F%3A\s%2B(%3F%3A"(%3F%3A[^"\\]|\\\\|\\.)%2B"|'(%3F%3A[^'\\]|\\\\|\\.)%2B'|\((%3F%3A[^)\\]|\\\\|\\.)%2B\)))%3F%2F%2C true)%3B%0A }%0A state.f %3D state.inline %3D inlineNormal%3B%0A return linkhref%3B%0A }%0A%0A function inlineRE(endChar) {%0A if (!inlineRE[endChar]) {%0A %2F%2F Escape endChar for RegExp (taken from http%3A%2F%2Fstackoverflow.com%2Fa%2F494122%2F526741)%0A endChar %3D (endChar%2B'').replace(%2F([.%3F*%2B^%24[\]\\(){}|-])%2Fg%2C "\\%241")%3B%0A %2F%2F Match any non-endChar%2C escaped character%2C as well as the closing %0A %2F%2F endChar.%0A inlineRE[endChar] %3D new RegExp('^(%3F%3A[^\\\\]%2B%3F|\\\\.)*%3F(' %2B endChar %2B ')')%3B%0A }%0A return inlineRE[endChar]%3B%0A }%0A%0A function inlineElement(type%2C endChar%2C next) {%0A next %3D next || inlineNormal%3B%0A return function(stream%2C state) {%0A stream.match(inlineRE(endChar))%3B%0A state.inline %3D state.f %3D next%3B%0A return type%3B%0A }%3B%0A }%0A%0A return {%0A startState%3A function() {%0A return {%0A f%3A blockNormal%2C%0A %0A block%3A blockNormal%2C%0A htmlState%3A CodeMirror.startState(htmlMode)%2C%0A indentation%3A 0%2C%0A %0A inline%3A inlineNormal%2C%0A text%3A handleText%2C%0A linkTitle%3A false%2C%0A em%3A false%2C%0A strong%3A false%2C%0A header%3A false%2C%0A list%3A false%2C%0A quote%3A false%0A }%3B%0A }%2C%0A%0A copyState%3A function(s) {%0A return {%0A f%3A s.f%2C%0A %0A block%3A s.block%2C%0A htmlState%3A CodeMirror.copyState(htmlMode%2C s.htmlState)%2C%0A indentation%3A s.indentation%2C%0A %0A inline%3A s.inline%2C%0A text%3A s.text%2C%0A linkTitle%3A s.linkTitle%2C%0A em%3A s.em%2C%0A strong%3A s.strong%2C%0A header%3A s.header%2C%0A list%3A s.list%2C%0A quote%3A s.quote%2C%0A md_inside%3A s.md_inside%0A }%3B%0A }%2C%0A%0A token%3A function(stream%2C state) {%0A if (stream.sol()) {%0A if (stream.match(%2F^\s*%24%2F%2C true)) {%0A prevLineHasContent %3D false%3B%0A return blankLine(state)%3B%0A } else {%0A if(thisLineHasContent){%0A prevLineHasContent %3D true%3B%0A thisLineHasContent %3D false%3B%0A }%0A thisLineHasContent %3D true%3B%0A }%0A%0A %2F%2F Reset state.header%0A state.header %3D false%3B%0A%0A state.f %3D state.block%3B%0A var indentation %3D stream.match(%2F^\s*%2F%2C true)[0].replace(%2F\t%2Fg%2C ' ').length%3B%0A state.indentationDiff %3D indentation - state.indentation%3B%0A state.indentation %3D indentation%3B%0A if (indentation > 0) { return null%3B }%0A }%0A return state.f(stream%2C state)%3B%0A }%2C%0A%0A blankLine%3A blankLine%2C%0A%0A getType%3A getType%0A }%3B%0A%0A}%2C "xml")%3B%0A%0ACodeMirror.defineMIME("text%2Fx-markdown"%2C "markdown")%3B%0A <%2Fscript>%0A %0A %0A %0A <%2Fhead>%0A <body>%0A <div id%3D"editor"><%2Fdiv>%0A <p>%0A Local%3A%0A <input type%3D"file" onchange%3D"localLoad(this.files)%3B" %2F>%0A <input type%3D"submit" value%3D"save" onclick%3D"window.open(localSave())%3B">%0A |%0A <input type%3D"submit" value%3D"js" onclick%3D"myCodeMirror.setOption('mode'%2C 'javascript')%3B">%0A <input type%3D"submit" value%3D"html" onclick%3D"myCodeMirror.setOption('mode'%2C 'htmlmixed')%3B">%0A <input type%3D"submit" value%3D"markdown" onclick%3D"myCodeMirror.setOption('mode'%2C 'markdown')%3B">%0A <%2Fp>%0A %0A <%2Fbody>%0A <script>%0A %0A %2F%2FCODE MIRROR%0A var myCodeMirror %3D CodeMirror(document.getElementById('editor')%2C {%0A lineNumbers%3A true%0A })%3B%0A %0A %2F%2FLOCAL%0A function localSave() {%0A return 'data%3Atext%2Fplain%3Bcharset%3Dutf-8%2C'%2BencodeURIComponent(myCodeMirror.getValue())%3B%0A }%0A %0A function localLoad(files) {%0A if(files.length %3D%3D 1) {%0A document.title%3Descape(files[0].name)%3B%0A var reader %3D new FileReader()%3B%0A reader.onload %3D function(e) {%0A myCodeMirror.setValue(e.target.result)%3B%0A }%3B%0A reader.readAsText(files[0])%3B%0A }%0A }%0A %0A <%2Fscript>%0A<%2Fhtml>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment