aboutsummaryrefslogtreecommitdiff
path: root/js/codemirror/lib/codemirror.js
diff options
context:
space:
mode:
authorPierre Frisch2011-12-22 07:25:50 -0800
committerValerio Virgillito2012-01-27 11:18:17 -0800
commitb89a7ee8b956c96a1dcee995ea840feddc5d4b27 (patch)
tree0f3136ab0ecdbbbed6a83576581af0a53124d6f1 /js/codemirror/lib/codemirror.js
parent2401f05d1f4b94d45e4568b81fc73e67b969d980 (diff)
downloadninja-b89a7ee8b956c96a1dcee995ea840feddc5d4b27.tar.gz
First commit of Ninja to ninja-internal
Signed-off-by: Valerio Virgillito <rmwh84@motorola.com>
Diffstat (limited to 'js/codemirror/lib/codemirror.js')
-rw-r--r--js/codemirror/lib/codemirror.js2144
1 files changed, 2144 insertions, 0 deletions
diff --git a/js/codemirror/lib/codemirror.js b/js/codemirror/lib/codemirror.js
new file mode 100644
index 00000000..27bec72f
--- /dev/null
+++ b/js/codemirror/lib/codemirror.js
@@ -0,0 +1,2144 @@
1// All functions that need access to the editor's state live inside
2// the CodeMirror function. Below that, at the bottom of the file,
3// some utilities are defined.
4
5// CodeMirror is the only global var we claim
6var CodeMirror = (function() {
7 // This is the function that produces an editor instance. It's
8 // closure is used to store the editor state.
9 function CodeMirror(place, givenOptions) {
10 // Determine effective options based on given values and defaults.
11 var options = {}, defaults = CodeMirror.defaults;
12 for (var opt in defaults)
13 if (defaults.hasOwnProperty(opt))
14 options[opt] = (givenOptions && givenOptions.hasOwnProperty(opt) ? givenOptions : defaults)[opt];
15
16 var targetDocument = options["document"];
17 // The element in which the editor lives.
18 var wrapper = targetDocument.createElement("div");
19 wrapper.className = "CodeMirror";
20 // This mess creates the base DOM structure for the editor.
21 wrapper.innerHTML =
22 '<div style="overflow: hidden; position: relative; width: 1px; height: 0px;">' + // Wraps and hides input textarea
23 '<textarea style="position: absolute; width: 2px;" wrap="off"></textarea></div>' +
24 '<div class="CodeMirror-scroll cm-s-' + options.theme + '">' +
25 '<div style="position: relative">' + // Set to the height of the text, causes scrolling
26 '<div style="position: absolute; height: 0; width: 0; overflow: hidden;"></div>' +
27 '<div style="position: relative">' + // Moved around its parent to cover visible view
28 '<div class="CodeMirror-gutter"><div class="CodeMirror-gutter-text"></div></div>' +
29 // Provides positioning relative to (visible) text origin
30 '<div class="CodeMirror-lines"><div style="position: relative">' +
31 '<pre class="CodeMirror-cursor">&#160;</pre>' + // Absolutely positioned blinky cursor
32 '<div></div>' + // This DIV contains the actual code
33 '</div></div></div></div></div>';
34 if (place.appendChild) place.appendChild(wrapper); else place(wrapper);
35 // I've never seen more elegant code in my life.
36 var inputDiv = wrapper.firstChild, input = inputDiv.firstChild,
37 scroller = wrapper.lastChild, code = scroller.firstChild,
38 measure = code.firstChild, mover = measure.nextSibling,
39 gutter = mover.firstChild, gutterText = gutter.firstChild,
40 lineSpace = gutter.nextSibling.firstChild,
41 cursor = lineSpace.firstChild, lineDiv = cursor.nextSibling;
42 if (options.tabindex != null) input.tabindex = options.tabindex;
43 if (!options.gutter && !options.lineNumbers) gutter.style.display = "none";
44
45 // Delayed object wrap timeouts, making sure only one is active. blinker holds an interval.
46 var poll = new Delayed(), highlight = new Delayed(), blinker;
47
48 // mode holds a mode API object. lines an array of Line objects
49 // (see Line constructor), work an array of lines that should be
50 // parsed, and history the undo history (instance of History
51 // constructor).
52 var mode, lines = [new Line("")], work, history = new History(), focused;
53 loadMode();
54 // The selection. These are always maintained to point at valid
55 // positions. Inverted is used to remember that the user is
56 // selecting bottom-to-top.
57 var sel = {from: {line: 0, ch: 0}, to: {line: 0, ch: 0}, inverted: false};
58 // Selection-related flags. shiftSelecting obviously tracks
59 // whether the user is holding shift. reducedSelection is a hack
60 // to get around the fact that we can't create inverted
61 // selections. See below.
62 var shiftSelecting, reducedSelection, lastDoubleClick;
63 // Variables used by startOperation/endOperation to track what
64 // happened during the operation.
65 var updateInput, changes, textChanged, selectionChanged, leaveInputAlone;
66 // Current visible range (may be bigger than the view window).
67 var showingFrom = 0, showingTo = 0, lastHeight = 0, curKeyId = null;
68 // editing will hold an object describing the things we put in the
69 // textarea, to help figure out whether something changed.
70 // bracketHighlighted is used to remember that a backet has been
71 // marked.
72 var editing, bracketHighlighted;
73 // Tracks the maximum line length so that the horizontal scrollbar
74 // can be kept static when scrolling.
75 var maxLine = "", maxWidth;
76
77 // Initialize the content.
78 operation(function(){setValue(options.value || ""); updateInput = false;})();
79
80 // Register our event handlers.
81 connect(scroller, "mousedown", operation(onMouseDown));
82 // Gecko browsers fire contextmenu *after* opening the menu, at
83 // which point we can't mess with it anymore. Context menu is
84 // handled in onMouseDown for Gecko.
85 if (!gecko) connect(scroller, "contextmenu", onContextMenu);
86 connect(code, "dblclick", operation(onDblClick));
87 connect(scroller, "scroll", function() {updateDisplay([]); if (options.onScroll) options.onScroll(instance);});
88 connect(window, "resize", function() {updateDisplay(true);});
89 connect(input, "keyup", operation(onKeyUp));
90 connect(input, "keydown", operation(onKeyDown));
91 connect(input, "keypress", operation(onKeyPress));
92 connect(input, "focus", onFocus);
93 connect(input, "blur", onBlur);
94
95 connect(scroller, "dragenter", e_stop);
96 connect(scroller, "dragover", e_stop);
97 connect(scroller, "drop", operation(onDrop));
98 connect(scroller, "paste", function(){focusInput(); fastPoll();});
99 connect(input, "paste", function(){fastPoll();});
100 connect(input, "cut", function(){fastPoll();});
101
102 // IE throws unspecified error in certain cases, when
103 // trying to access activeElement before onload
104 var hasFocus; try { hasFocus = (targetDocument.activeElement == input); } catch(e) { }
105 if (hasFocus) setTimeout(onFocus, 20);
106 else onBlur();
107
108 function isLine(l) {return l >= 0 && l < lines.length;}
109 // The instance object that we'll return. Mostly calls out to
110 // local functions in the CodeMirror function. Some do some extra
111 // range checking and/or clipping. operation is used to wrap the
112 // call so that changes it makes are tracked, and the display is
113 // updated afterwards.
114 var instance = {
115 getValue: getValue,
116 setValue: operation(setValue),
117 getSelection: getSelection,
118 replaceSelection: operation(replaceSelection),
119 focus: function(){focusInput(); onFocus(); fastPoll();},
120 setOption: function(option, value) {
121 options[option] = value;
122 if (option == "lineNumbers" || option == "gutter") gutterChanged();
123 else if (option == "mode" || option == "indentUnit") loadMode();
124 else if (option == "readOnly" && value == "nocursor") input.blur();
125 else if (option == "theme") scroller.className = scroller.className.replace(/cm-s-\w+/, "cm-s-" + value);
126 },
127 getOption: function(option) {return options[option];},
128 undo: operation(undo),
129 redo: operation(redo),
130 indentLine: operation(function(n) {if (isLine(n)) indentLine(n, "smart");}),
131 historySize: function() {return {undo: history.done.length, redo: history.undone.length};},
132 matchBrackets: operation(function(){matchBrackets(true);}),
133 getTokenAt: function(pos) {
134 pos = clipPos(pos);
135 return lines[pos.line].getTokenAt(mode, getStateBefore(pos.line), pos.ch);
136 },
137 getStateAfter: function(line) {
138 line = clipLine(line == null ? lines.length - 1: line);
139 return getStateBefore(line + 1);
140 },
141 cursorCoords: function(start){
142 if (start == null) start = sel.inverted;
143 return pageCoords(start ? sel.from : sel.to);
144 },
145 charCoords: function(pos){return pageCoords(clipPos(pos));},
146 coordsChar: function(coords) {
147 var off = eltOffset(lineSpace);
148 var line = clipLine(Math.min(lines.length - 1, showingFrom + Math.floor((coords.y - off.top) / lineHeight())));
149 return clipPos({line: line, ch: charFromX(clipLine(line), coords.x - off.left)});
150 },
151 getSearchCursor: function(query, pos, caseFold) {return new SearchCursor(query, pos, caseFold);},
152 markText: operation(function(a, b, c){return operation(markText(a, b, c));}),
153 setMarker: addGutterMarker,
154 clearMarker: removeGutterMarker,
155 setLineClass: operation(setLineClass),
156 lineInfo: lineInfo,
157 addWidget: function(pos, node, scroll, where) {
158 pos = localCoords(clipPos(pos));
159 var top = pos.yBot, left = pos.x;
160 node.style.position = "absolute";
161 code.appendChild(node);
162 node.style.left = left + "px";
163 if (where == "over") top = pos.y;
164 else if (where == "near") {
165 var vspace = Math.max(scroller.offsetHeight, lines.length * lineHeight()),
166 hspace = Math.max(code.clientWidth, lineSpace.clientWidth) - paddingLeft();
167 if (pos.yBot + node.offsetHeight > vspace && pos.y > node.offsetHeight)
168 top = pos.y - node.offsetHeight;
169 if (left + node.offsetWidth > hspace)
170 left = hspace - node.offsetWidth;
171 }
172 node.style.top = (top + paddingTop()) + "px";
173 node.style.left = (left + paddingLeft()) + "px";
174 if (scroll)
175 scrollIntoView(left, top, left + node.offsetWidth, top + node.offsetHeight);
176 },
177
178 lineCount: function() {return lines.length;},
179 getCursor: function(start) {
180 if (start == null) start = sel.inverted;
181 return copyPos(start ? sel.from : sel.to);
182 },
183 somethingSelected: function() {return !posEq(sel.from, sel.to);},
184 setCursor: operation(function(line, ch) {
185 if (ch == null && typeof line.line == "number") setCursor(line.line, line.ch);
186 else setCursor(line, ch);
187 }),
188 setSelection: operation(function(from, to) {setSelection(clipPos(from), clipPos(to || from));}),
189 getLine: function(line) {if (isLine(line)) return lines[line].text;},
190 setLine: operation(function(line, text) {
191 if (isLine(line)) replaceRange(text, {line: line, ch: 0}, {line: line, ch: lines[line].text.length});
192 }),
193 removeLine: operation(function(line) {
194 if (isLine(line)) replaceRange("", {line: line, ch: 0}, clipPos({line: line+1, ch: 0}));
195 }),
196 replaceRange: operation(replaceRange),
197 getRange: function(from, to) {return getRange(clipPos(from), clipPos(to));},
198
199 operation: function(f){return operation(f)();},
200 refresh: function(){updateDisplay(true);},
201 getInputField: function(){return input;},
202 getWrapperElement: function(){return wrapper;},
203 getScrollerElement: function(){return scroller;}
204 };
205
206 function setValue(code) {
207 history = null;
208 var top = {line: 0, ch: 0};
209 updateLines(top, {line: lines.length - 1, ch: lines[lines.length-1].text.length},
210 splitLines(code), top, top);
211 history = new History();
212 }
213 function getValue(code) {
214 var text = [];
215 for (var i = 0, l = lines.length; i < l; ++i)
216 text.push(lines[i].text);
217 return text.join("\n");