codemirror-rails 2.24 → 2.32

Sign up to get free protection for your applications and to get access to all the features.
Files changed (90) hide show
  1. data/.gitignore +1 -0
  2. data/Rakefile +19 -0
  3. data/codemirror-rails.gemspec +6 -1
  4. data/lib/codemirror/rails/version.rb +2 -2
  5. data/test/dummy/README.rdoc +261 -0
  6. data/test/dummy/Rakefile +7 -0
  7. data/test/dummy/app/assets/javascripts/application.js +15 -0
  8. data/test/dummy/app/assets/stylesheets/application.css +13 -0
  9. data/test/dummy/app/controllers/application_controller.rb +3 -0
  10. data/test/dummy/app/helpers/application_helper.rb +2 -0
  11. data/test/dummy/app/mailers/.gitkeep +0 -0
  12. data/test/dummy/app/models/.gitkeep +0 -0
  13. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  14. data/test/dummy/config.ru +4 -0
  15. data/test/dummy/config/application.rb +56 -0
  16. data/test/dummy/config/boot.rb +10 -0
  17. data/test/dummy/config/environment.rb +5 -0
  18. data/test/dummy/config/environments/development.rb +37 -0
  19. data/test/dummy/config/environments/production.rb +67 -0
  20. data/test/dummy/config/environments/test.rb +37 -0
  21. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  22. data/test/dummy/config/initializers/inflections.rb +15 -0
  23. data/test/dummy/config/initializers/mime_types.rb +5 -0
  24. data/test/dummy/config/initializers/secret_token.rb +7 -0
  25. data/test/dummy/config/initializers/session_store.rb +8 -0
  26. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  27. data/test/dummy/config/locales/en.yml +5 -0
  28. data/test/dummy/config/routes.rb +58 -0
  29. data/test/dummy/lib/assets/.gitkeep +0 -0
  30. data/test/dummy/log/.gitkeep +0 -0
  31. data/test/dummy/public/404.html +26 -0
  32. data/test/dummy/public/422.html +26 -0
  33. data/test/dummy/public/500.html +25 -0
  34. data/test/dummy/public/favicon.ico +0 -0
  35. data/test/dummy/script/rails +6 -0
  36. data/test/integration/codemirror_rails_integration_test.rb +13 -0
  37. data/test/test_helper.rb +13 -0
  38. data/vendor/assets/javascripts/codemirror.js +381 -197
  39. data/vendor/assets/javascripts/codemirror/keymaps/emacs.js +1 -1
  40. data/vendor/assets/javascripts/codemirror/keymaps/vim.js +649 -94
  41. data/vendor/assets/javascripts/codemirror/modes/clike.js +53 -7
  42. data/vendor/assets/javascripts/codemirror/modes/coffeescript.js +12 -7
  43. data/vendor/assets/javascripts/codemirror/modes/diff.js +24 -5
  44. data/vendor/assets/javascripts/codemirror/modes/ecl.js +2 -2
  45. data/vendor/assets/javascripts/codemirror/modes/erlang.js +463 -0
  46. data/vendor/assets/javascripts/codemirror/modes/gfm.js +38 -2
  47. data/vendor/assets/javascripts/codemirror/modes/go.js +1 -1
  48. data/vendor/assets/javascripts/codemirror/modes/groovy.js +1 -1
  49. data/vendor/assets/javascripts/codemirror/modes/haxe.js +432 -0
  50. data/vendor/assets/javascripts/codemirror/modes/javascript.js +1 -1
  51. data/vendor/assets/javascripts/codemirror/modes/less.js +93 -93
  52. data/vendor/assets/javascripts/codemirror/modes/markdown.js +29 -6
  53. data/vendor/assets/javascripts/codemirror/modes/mysql.js +6 -8
  54. data/vendor/assets/javascripts/codemirror/modes/ocaml.js +114 -0
  55. data/vendor/assets/javascripts/codemirror/modes/pascal.js +1 -1
  56. data/vendor/assets/javascripts/codemirror/modes/pig.js +2 -2
  57. data/vendor/assets/javascripts/codemirror/modes/plsql.js +2 -2
  58. data/vendor/assets/javascripts/codemirror/modes/python.js +13 -16
  59. data/vendor/assets/javascripts/codemirror/modes/ruby.js +3 -8
  60. data/vendor/assets/javascripts/codemirror/modes/scheme.js +74 -46
  61. data/vendor/assets/javascripts/codemirror/modes/shell.js +22 -7
  62. data/vendor/assets/javascripts/codemirror/modes/stex.js +7 -5
  63. data/vendor/assets/javascripts/codemirror/modes/tiddlywiki.js +14 -14
  64. data/vendor/assets/javascripts/codemirror/modes/vb.js +260 -0
  65. data/vendor/assets/javascripts/codemirror/modes/verilog.js +1 -1
  66. data/vendor/assets/javascripts/codemirror/modes/xml.js +2 -1
  67. data/vendor/assets/javascripts/codemirror/modes/xquery.js +3 -3
  68. data/vendor/assets/javascripts/codemirror/utils/closetag.js +24 -34
  69. data/vendor/assets/javascripts/codemirror/utils/dialog.js +5 -1
  70. data/vendor/assets/javascripts/codemirror/utils/foldcode.js +10 -5
  71. data/vendor/assets/javascripts/codemirror/utils/formatting.js +8 -3
  72. data/vendor/assets/javascripts/codemirror/utils/loadmode.js +2 -1
  73. data/vendor/assets/javascripts/codemirror/utils/match-highlighter.js +1 -1
  74. data/vendor/assets/javascripts/codemirror/utils/multiplex.js +81 -0
  75. data/vendor/assets/javascripts/codemirror/utils/overlay.js +2 -1
  76. data/vendor/assets/javascripts/codemirror/utils/pig-hint.js +123 -0
  77. data/vendor/assets/javascripts/codemirror/utils/search.js +16 -12
  78. data/vendor/assets/javascripts/codemirror/utils/searchcursor.js +1 -1
  79. data/vendor/assets/javascripts/codemirror/utils/simple-hint.js +4 -0
  80. data/vendor/assets/javascripts/codemirror/utils/xml-hint.js +137 -0
  81. data/vendor/assets/stylesheets/codemirror.css +59 -4
  82. data/vendor/assets/stylesheets/codemirror/modes/tiddlywiki.css +14 -21
  83. data/vendor/assets/stylesheets/codemirror/themes/ambiance.css +1 -2
  84. data/vendor/assets/stylesheets/codemirror/themes/erlang-dark.css +21 -0
  85. data/vendor/assets/stylesheets/codemirror/themes/lesser-dark.css +2 -3
  86. data/vendor/assets/stylesheets/codemirror/themes/night.css +1 -1
  87. data/vendor/assets/stylesheets/codemirror/themes/vibrant-ink.css +27 -0
  88. data/vendor/assets/stylesheets/codemirror/utils/dialog.css +4 -0
  89. metadata +98 -5
  90. data/vendor/assets/javascripts/codemirror/modes/rpm-spec.css +0 -5
@@ -0,0 +1,260 @@
1
+ CodeMirror.defineMode("vb", function(conf, parserConf) {
2
+ var ERRORCLASS = 'error';
3
+
4
+ function wordRegexp(words) {
5
+ return new RegExp("^((" + words.join(")|(") + "))\\b", "i");
6
+ }
7
+
8
+ var singleOperators = new RegExp("^[\\+\\-\\*/%&\\\\|\\^~<>!]");
9
+ var singleDelimiters = new RegExp('^[\\(\\)\\[\\]\\{\\}@,:`=;\\.]');
10
+ var doubleOperators = new RegExp("^((==)|(<>)|(<=)|(>=)|(<>)|(<<)|(>>)|(//)|(\\*\\*))");
11
+ var doubleDelimiters = new RegExp("^((\\+=)|(\\-=)|(\\*=)|(%=)|(/=)|(&=)|(\\|=)|(\\^=))");
12
+ var tripleDelimiters = new RegExp("^((//=)|(>>=)|(<<=)|(\\*\\*=))");
13
+ var identifiers = new RegExp("^[_A-Za-z][_A-Za-z0-9]*");
14
+
15
+ var openingKeywords = ['class','module', 'sub','enum','select','while','if','function', 'get','set','property'];
16
+ var middleKeywords = ['else','elseif','case'];
17
+ var endKeywords = ['next','loop'];
18
+
19
+ var wordOperators = wordRegexp(['and', 'or', 'not', 'xor', 'in']);
20
+ var commonkeywords = ['as', 'dim', 'break', 'continue','optional', 'then', 'until',
21
+ 'goto', 'byval','byref','new','handles','property', 'return',
22
+ 'const','private', 'protected', 'friend', 'public', 'shared', 'static', 'true','false'];
23
+ var commontypes = ['integer','string','double','decimal','boolean','short','char', 'float','single'];
24
+
25
+ var keywords = wordRegexp(commonkeywords);
26
+ var types = wordRegexp(commontypes);
27
+ var stringPrefixes = '"';
28
+
29
+ var opening = wordRegexp(openingKeywords);
30
+ var middle = wordRegexp(middleKeywords);
31
+ var closing = wordRegexp(endKeywords);
32
+ var doubleClosing = wordRegexp(['end']);
33
+ var doOpening = wordRegexp(['do']);
34
+
35
+ var indentInfo = null;
36
+
37
+
38
+
39
+
40
+ function indent(stream, state) {
41
+ state.currentIndent++;
42
+ }
43
+
44
+ function dedent(stream, state) {
45
+ state.currentIndent--;
46
+ }
47
+ // tokenizers
48
+ function tokenBase(stream, state) {
49
+ if (stream.eatSpace()) {
50
+ return null;
51
+ }
52
+
53
+ var ch = stream.peek();
54
+
55
+ // Handle Comments
56
+ if (ch === "'") {
57
+ stream.skipToEnd();
58
+ return 'comment';
59
+ }
60
+
61
+
62
+ // Handle Number Literals
63
+ if (stream.match(/^((&H)|(&O))?[0-9\.a-f]/i, false)) {
64
+ var floatLiteral = false;
65
+ // Floats
66
+ if (stream.match(/^\d*\.\d+F?/i)) { floatLiteral = true; }
67
+ else if (stream.match(/^\d+\.\d*F?/)) { floatLiteral = true; }
68
+ else if (stream.match(/^\.\d+F?/)) { floatLiteral = true; }
69
+
70
+ if (floatLiteral) {
71
+ // Float literals may be "imaginary"
72
+ stream.eat(/J/i);
73
+ return 'number';
74
+ }
75
+ // Integers
76
+ var intLiteral = false;
77
+ // Hex
78
+ if (stream.match(/^&H[0-9a-f]+/i)) { intLiteral = true; }
79
+ // Octal
80
+ else if (stream.match(/^&O[0-7]+/i)) { intLiteral = true; }
81
+ // Decimal
82
+ else if (stream.match(/^[1-9]\d*F?/)) {
83
+ // Decimal literals may be "imaginary"
84
+ stream.eat(/J/i);
85
+ // TODO - Can you have imaginary longs?
86
+ intLiteral = true;
87
+ }
88
+ // Zero by itself with no other piece of number.
89
+ else if (stream.match(/^0(?![\dx])/i)) { intLiteral = true; }
90
+ if (intLiteral) {
91
+ // Integer literals may be "long"
92
+ stream.eat(/L/i);
93
+ return 'number';
94
+ }
95
+ }
96
+
97
+ // Handle Strings
98
+ if (stream.match(stringPrefixes)) {
99
+ state.tokenize = tokenStringFactory(stream.current());
100
+ return state.tokenize(stream, state);
101
+ }
102
+
103
+ // Handle operators and Delimiters
104
+ if (stream.match(tripleDelimiters) || stream.match(doubleDelimiters)) {
105
+ return null;
106
+ }
107
+ if (stream.match(doubleOperators)
108
+ || stream.match(singleOperators)
109
+ || stream.match(wordOperators)) {
110
+ return 'operator';
111
+ }
112
+ if (stream.match(singleDelimiters)) {
113
+ return null;
114
+ }
115
+ if (stream.match(doOpening)) {
116
+ indent(stream,state);
117
+ state.doInCurrentLine = true;
118
+ return 'keyword';
119
+ }
120
+ if (stream.match(opening)) {
121
+ if (! state.doInCurrentLine)
122
+ indent(stream,state);
123
+ else
124
+ state.doInCurrentLine = false;
125
+ return 'keyword';
126
+ }
127
+ if (stream.match(middle)) {
128
+ return 'keyword';
129
+ }
130
+
131
+ if (stream.match(doubleClosing)) {
132
+ dedent(stream,state);
133
+ dedent(stream,state);
134
+ return 'keyword';
135
+ }
136
+ if (stream.match(closing)) {
137
+ dedent(stream,state);
138
+ return 'keyword';
139
+ }
140
+
141
+ if (stream.match(types)) {
142
+ return 'keyword';
143
+ }
144
+
145
+ if (stream.match(keywords)) {
146
+ return 'keyword';
147
+ }
148
+
149
+ if (stream.match(identifiers)) {
150
+ return 'variable';
151
+ }
152
+
153
+ // Handle non-detected items
154
+ stream.next();
155
+ return ERRORCLASS;
156
+ }
157
+
158
+ function tokenStringFactory(delimiter) {
159
+ var singleline = delimiter.length == 1;
160
+ var OUTCLASS = 'string';
161
+
162
+ return function tokenString(stream, state) {
163
+ while (!stream.eol()) {
164
+ stream.eatWhile(/[^'"]/);
165
+ if (stream.match(delimiter)) {
166
+ state.tokenize = tokenBase;
167
+ return OUTCLASS;
168
+ } else {
169
+ stream.eat(/['"]/);
170
+ }
171
+ }
172
+ if (singleline) {
173
+ if (parserConf.singleLineStringErrors) {
174
+ return ERRORCLASS;
175
+ } else {
176
+ state.tokenize = tokenBase;
177
+ }
178
+ }
179
+ return OUTCLASS;
180
+ };
181
+ }
182
+
183
+
184
+ function tokenLexer(stream, state) {
185
+ var style = state.tokenize(stream, state);
186
+ var current = stream.current();
187
+
188
+ // Handle '.' connected identifiers
189
+ if (current === '.') {
190
+ style = state.tokenize(stream, state);
191
+ current = stream.current();
192
+ if (style === 'variable') {
193
+ return 'variable';
194
+ } else {
195
+ return ERRORCLASS;
196
+ }
197
+ }
198
+
199
+
200
+ var delimiter_index = '[({'.indexOf(current);
201
+ if (delimiter_index !== -1) {
202
+ indent(stream, state );
203
+ }
204
+ if (indentInfo === 'dedent') {
205
+ if (dedent(stream, state)) {
206
+ return ERRORCLASS;
207
+ }
208
+ }
209
+ delimiter_index = '])}'.indexOf(current);
210
+ if (delimiter_index !== -1) {
211
+ if (dedent(stream, state)) {
212
+ return ERRORCLASS;
213
+ }
214
+ }
215
+
216
+ return style;
217
+ }
218
+
219
+ var external = {
220
+ electricChars:"dDpPtTfFeE ",
221
+ startState: function(basecolumn) {
222
+ return {
223
+ tokenize: tokenBase,
224
+ lastToken: null,
225
+ currentIndent: 0,
226
+ nextLineIndent: 0,
227
+ doInCurrentLine: false
228
+
229
+
230
+ };
231
+ },
232
+
233
+ token: function(stream, state) {
234
+ if (stream.sol()) {
235
+ state.currentIndent += state.nextLineIndent;
236
+ state.nextLineIndent = 0;
237
+ state.doInCurrentLine = 0;
238
+ }
239
+ var style = tokenLexer(stream, state);
240
+
241
+ state.lastToken = {style:style, content: stream.current()};
242
+
243
+
244
+
245
+ return style;
246
+ },
247
+
248
+ indent: function(state, textAfter) {
249
+ var trueText = textAfter.replace(/^\s+|\s+$/g, '') ;
250
+ if (trueText.match(closing) || trueText.match(doubleClosing) || trueText.match(middle)) return conf.indentUnit*(state.currentIndent-1);
251
+ if(state.currentIndent < 0) return 0;
252
+ return state.currentIndent * conf.indentUnit;
253
+ }
254
+
255
+ };
256
+ return external;
257
+ });
258
+
259
+ CodeMirror.defineMIME("text/x-vb", "vb");
260
+
@@ -48,7 +48,7 @@ CodeMirror.defineMode("verilog", function(config, parserConfig) {
48
48
  return "keyword";
49
49
  }
50
50
  if (atoms.propertyIsEnumerable(cur)) return "atom";
51
- return "word";
51
+ return "variable";
52
52
  }
53
53
 
54
54
  function tokenString(quote) {
@@ -312,7 +312,7 @@ CodeMirror.defineMode("xml", function(config, parserConfig) {
312
312
  if (a.indented != b.indented || a.tokenize != b.tokenize) return false;
313
313
  for (var ca = a.context, cb = b.context; ; ca = ca.prev, cb = cb.prev) {
314
314
  if (!ca || !cb) return ca == cb;
315
- if (ca.tagName != cb.tagName) return false;
315
+ if (ca.tagName != cb.tagName || ca.indent != cb.indent) return false;
316
316
  }
317
317
  },
318
318
 
@@ -320,6 +320,7 @@ CodeMirror.defineMode("xml", function(config, parserConfig) {
320
320
  };
321
321
  });
322
322
 
323
+ CodeMirror.defineMIME("text/xml", "xml");
323
324
  CodeMirror.defineMIME("application/xml", "xml");
324
325
  if (!CodeMirror.mimeModes.hasOwnProperty("text/html"))
325
326
  CodeMirror.defineMIME("text/html", {name: "xml", htmlMode: true});
@@ -137,7 +137,7 @@ CodeMirror.defineMode("xquery", function(config, parserConfig) {
137
137
  return ret("tag", "tag");
138
138
  }
139
139
  else
140
- return ret("word", "word");
140
+ return ret("word", "variable");
141
141
  }
142
142
  // if a number
143
143
  else if (/\d/.test(ch)) {
@@ -213,7 +213,7 @@ CodeMirror.defineMode("xquery", function(config, parserConfig) {
213
213
  // if the previous word was element, attribute, axis specifier, this word should be the name of that
214
214
  if(isInXmlConstructor(state)) {
215
215
  popStateStack(state);
216
- return ret("word", "word", word);
216
+ return ret("word", "variable", word);
217
217
  }
218
218
  // as previously checked, if the word is element,attribute, axis specifier, call it an "xmlconstructor" and
219
219
  // push the stack so we know to look for it on the next word
@@ -221,7 +221,7 @@ CodeMirror.defineMode("xquery", function(config, parserConfig) {
221
221
 
222
222
  // if the word is known, return the details of that else just call this a generic 'word'
223
223
  return known ? ret(known.type, known.style, word) :
224
- ret("word", "word", word);
224
+ ret("word", "variable", word);
225
225
  }
226
226
  }
227
227
 
@@ -10,7 +10,6 @@
10
10
  * following CodeMirror modes and will ignore all others:
11
11
  * - htmlmixed
12
12
  * - xml
13
- * - xmlpure
14
13
  *
15
14
  * See demos/closetag.html for a usage example.
16
15
  *
@@ -24,21 +23,25 @@
24
23
  /** Array of tag names to add indentation after the start tag for. Default is the list of block-level html tags. */
25
24
  CodeMirror.defaults['closeTagIndent'] = ['applet', 'blockquote', 'body', 'button', 'div', 'dl', 'fieldset', 'form', 'frameset', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'html', 'iframe', 'layer', 'legend', 'object', 'ol', 'p', 'select', 'table', 'ul'];
26
25
 
26
+ /** Array of tag names where an end tag is forbidden. */
27
+ CodeMirror.defaults['closeTagVoid'] = ['area', 'base', 'br', 'col', 'command', 'embed', 'hr', 'img', 'input', 'keygen', 'link', 'meta', 'param', 'source', 'track', 'wbr'];
28
+
27
29
  /**
28
30
  * Call during key processing to close tags. Handles the key event if the tag is closed, otherwise throws CodeMirror.Pass.
29
31
  * - cm: The editor instance.
30
32
  * - ch: The character being processed.
31
- * - indent: Optional. Omit or pass true to use the default indentation tag list defined in the 'closeTagIndent' option.
33
+ * - indent: Optional. An array of tag names to indent when closing. Omit or pass true to use the default indentation tag list defined in the 'closeTagIndent' option.
32
34
  * Pass false to disable indentation. Pass an array to override the default list of tag names.
35
+ * - vd: Optional. An array of tag names that should not be closed. Omit to use the default void (end tag forbidden) tag list defined in the 'closeTagVoid' option. Ignored in xml mode.
33
36
  */
34
- CodeMirror.defineExtension("closeTag", function(cm, ch, indent) {
37
+ CodeMirror.defineExtension("closeTag", function(cm, ch, indent, vd) {
35
38
  if (!cm.getOption('closeTagEnabled')) {
36
39
  throw CodeMirror.Pass;
37
40
  }
38
41
 
39
42
  var mode = cm.getOption('mode');
40
43
 
41
- if (mode == 'text/html') {
44
+ if (mode == 'text/html' || mode == 'xml') {
42
45
 
43
46
  /*
44
47
  * Relevant structure of token:
@@ -48,6 +51,7 @@
48
51
  * state
49
52
  * htmlState
50
53
  * type
54
+ * tagName
51
55
  * context
52
56
  * tagName
53
57
  * mode
@@ -83,8 +87,8 @@
83
87
  type = state.htmlState ? state.htmlState.type : state.type; // htmlmixed : xml
84
88
 
85
89
  if (tok.className == 'tag' && type != 'selfcloseTag') {
86
- var tagName = state.htmlState ? state.htmlState.context.tagName : state.tagName; // htmlmixed : xml
87
- if (tagName.length > 0) {
90
+ var tagName = state.htmlState ? state.htmlState.tagName : state.tagName; // htmlmixed : xml
91
+ if (tagName.length > 0 && shouldClose(cm, vd, tagName)) {
88
92
  insertEndTag(cm, indent, pos, tagName);
89
93
  }
90
94
  return;
@@ -96,7 +100,7 @@
96
100
 
97
101
  } else if (ch == '/') {
98
102
  if (tok.className == 'tag' && tok.string == '<') {
99
- var tagName = state.htmlState ? (state.htmlState.context ? state.htmlState.context.tagName : '') : state.context.tagName; // htmlmixed : xml # extra htmlmized check is for '</' edge case
103
+ var tagName = state.htmlState ? (state.htmlState.context ? state.htmlState.context.tagName : '') : (state.context ? state.context.tagName : ''); // htmlmixed : xml
100
104
  if (tagName.length > 0) {
101
105
  completeEndTag(cm, pos, tagName);
102
106
  return;
@@ -104,33 +108,6 @@
104
108
  }
105
109
  }
106
110
 
107
- } else if (mode == 'xmlpure') {
108
-
109
- var pos = cm.getCursor();
110
- var tok = cm.getTokenAt(pos);
111
- var tagName = tok.state.context.tagName;
112
-
113
- if (ch == '>') {
114
- // <foo> tagName=foo, string=foo
115
- // <foo /> tagName=foo, string=/ # ignore
116
- // <foo></foo> tagName=foo, string=/foo # ignore
117
- if (tok.string == tagName) {
118
- cm.replaceSelection('>'); // parity w/html modes
119
- pos = {line: pos.line, ch: pos.ch + 1};
120
- cm.setCursor(pos);
121
-
122
- insertEndTag(cm, indent, pos, tagName);
123
- return;
124
- }
125
-
126
- } else if (ch == '/') {
127
- // <foo / tagName=foo, string= # ignore
128
- // <foo></ tagName=foo, string=<
129
- if (tok.string == '<') {
130
- completeEndTag(cm, pos, tagName);
131
- return;
132
- }
133
- }
134
111
  }
135
112
 
136
113
  throw CodeMirror.Pass; // Bubble if not handled
@@ -158,6 +135,19 @@
158
135
  return indexOf(indent, tagName.toLowerCase()) != -1;
159
136
  }
160
137
 
138
+ function shouldClose(cm, vd, tagName) {
139
+ if (cm.getOption('mode') == 'xml') {
140
+ return true; // always close xml tags
141
+ }
142
+ if (typeof vd == 'undefined' || vd == null) {
143
+ vd = cm.getOption('closeTagVoid');
144
+ }
145
+ if (!vd) {
146
+ vd = [];
147
+ }
148
+ return indexOf(vd, tagName.toLowerCase()) == -1;
149
+ }
150
+
161
151
  // C&P from codemirror.js...would be nice if this were visible to utilities.
162
152
  function indexOf(collection, elt) {
163
153
  if (collection.indexOf) return collection.indexOf(elt);
@@ -17,7 +17,7 @@
17
17
  closed = true;
18
18
  dialog.parentNode.removeChild(dialog);
19
19
  }
20
- var inp = dialog.getElementsByTagName("input")[0];
20
+ var inp = dialog.getElementsByTagName("input")[0], button;
21
21
  if (inp) {
22
22
  CodeMirror.connect(inp, "keydown", function(e) {
23
23
  if (e.keyCode == 13 || e.keyCode == 27) {
@@ -29,6 +29,10 @@
29
29
  });
30
30
  inp.focus();
31
31
  CodeMirror.connect(inp, "blur", close);
32
+ } else if (button = dialog.getElementsByTagName("button")[0]) {
33
+ CodeMirror.connect(button, "click", close);
34
+ button.focus();
35
+ CodeMirror.connect(button, "blur", close);
32
36
  }
33
37
  return close;
34
38
  });