puffer_pages 0.0.18 → 0.0.19

Sign up to get free protection for your applications and to get access to all the features.
Files changed (35) hide show
  1. data/Gemfile.lock +41 -51
  2. data/VERSION +1 -1
  3. data/app/assets/javascripts/puffer/codemirror.js +2197 -0
  4. data/app/assets/javascripts/puffer/codemirror/css.js +124 -0
  5. data/app/assets/javascripts/puffer/codemirror/htmlmixed.js +84 -0
  6. data/app/assets/javascripts/puffer/codemirror/javascript.js +352 -0
  7. data/app/assets/javascripts/puffer/codemirror/xml.js +231 -0
  8. data/app/assets/javascripts/puffer/overlay.js +51 -0
  9. data/app/assets/javascripts/{puffer_pages → puffer}/puffer_pages.js +21 -11
  10. data/app/assets/javascripts/{puffer_pages → puffer}/right-tabs-src.js +0 -0
  11. data/app/assets/stylesheets/puffer/codemirror.css +68 -0
  12. data/app/assets/stylesheets/puffer/codemirror/cobalt.css +17 -0
  13. data/app/assets/stylesheets/puffer/codemirror/default.css +19 -0
  14. data/app/assets/stylesheets/puffer/codemirror/eclipse.css +24 -0
  15. data/app/assets/stylesheets/puffer/codemirror/elegant.css +9 -0
  16. data/app/assets/stylesheets/puffer/codemirror/neat.css +8 -0
  17. data/app/assets/stylesheets/puffer/codemirror/night.css +20 -0
  18. data/app/assets/stylesheets/puffer/puffer_pages.css +7 -0
  19. data/app/components/page_parts/form.html.erb +7 -6
  20. data/app/controllers/puffer_pages/layouts_base.rb +1 -2
  21. data/app/controllers/puffer_pages/pages_base.rb +1 -2
  22. data/app/controllers/puffer_pages/snippets_base.rb +1 -2
  23. data/puffer_pages.gemspec +18 -12
  24. data/spec/dummy/app/controllers/application_controller.rb +4 -0
  25. data/spec/dummy/config/environments/development.rb +3 -0
  26. data/spec/dummy/db/schema.rb +1 -0
  27. metadata +51 -45
  28. data/app/assets/javascripts/puffer_pages/application.js +0 -3
  29. data/app/assets/javascripts/puffer_pages/codemirror-base.js +0 -1
  30. data/app/assets/javascripts/puffer_pages/codemirror-parser.js +0 -1
  31. data/app/assets/javascripts/puffer_pages/codemirror.js +0 -1
  32. data/app/assets/stylesheets/puffer_pages/application.css +0 -3
  33. data/app/assets/stylesheets/puffer_pages/codemirror.css +0 -135
  34. data/app/assets/stylesheets/puffer_pages/puffer_pages.css +0 -12
  35. data/app/views/layouts/puffer_pages.html.erb +0 -9
@@ -0,0 +1,124 @@
1
+ CodeMirror.defineMode("css", function(config) {
2
+ var indentUnit = config.indentUnit, type;
3
+ function ret(style, tp) {type = tp; return style;}
4
+
5
+ function tokenBase(stream, state) {
6
+ var ch = stream.next();
7
+ if (ch == "@") {stream.eatWhile(/[\w\\\-]/); return ret("meta", stream.current());}
8
+ else if (ch == "/" && stream.eat("*")) {
9
+ state.tokenize = tokenCComment;
10
+ return tokenCComment(stream, state);
11
+ }
12
+ else if (ch == "<" && stream.eat("!")) {
13
+ state.tokenize = tokenSGMLComment;
14
+ return tokenSGMLComment(stream, state);
15
+ }
16
+ else if (ch == "=") ret(null, "compare");
17
+ else if ((ch == "~" || ch == "|") && stream.eat("=")) return ret(null, "compare");
18
+ else if (ch == "\"" || ch == "'") {
19
+ state.tokenize = tokenString(ch);
20
+ return state.tokenize(stream, state);
21
+ }
22
+ else if (ch == "#") {
23
+ stream.eatWhile(/[\w\\\-]/);
24
+ return ret("atom", "hash");
25
+ }
26
+ else if (ch == "!") {
27
+ stream.match(/^\s*\w*/);
28
+ return ret("keyword", "important");
29
+ }
30
+ else if (/\d/.test(ch)) {
31
+ stream.eatWhile(/[\w.%]/);
32
+ return ret("number", "unit");
33
+ }
34
+ else if (/[,.+>*\/]/.test(ch)) {
35
+ return ret(null, "select-op");
36
+ }
37
+ else if (/[;{}:\[\]]/.test(ch)) {
38
+ return ret(null, ch);
39
+ }
40
+ else {
41
+ stream.eatWhile(/[\w\\\-]/);
42
+ return ret("variable", "variable");
43
+ }
44
+ }
45
+
46
+ function tokenCComment(stream, state) {
47
+ var maybeEnd = false, ch;
48
+ while ((ch = stream.next()) != null) {
49
+ if (maybeEnd && ch == "/") {
50
+ state.tokenize = tokenBase;
51
+ break;
52
+ }
53
+ maybeEnd = (ch == "*");
54
+ }
55
+ return ret("comment", "comment");
56
+ }
57
+
58
+ function tokenSGMLComment(stream, state) {
59
+ var dashes = 0, ch;
60
+ while ((ch = stream.next()) != null) {
61
+ if (dashes >= 2 && ch == ">") {
62
+ state.tokenize = tokenBase;
63
+ break;
64
+ }
65
+ dashes = (ch == "-") ? dashes + 1 : 0;
66
+ }
67
+ return ret("comment", "comment");
68
+ }
69
+
70
+ function tokenString(quote) {
71
+ return function(stream, state) {
72
+ var escaped = false, ch;
73
+ while ((ch = stream.next()) != null) {
74
+ if (ch == quote && !escaped)
75
+ break;
76
+ escaped = !escaped && ch == "\\";
77
+ }
78
+ if (!escaped) state.tokenize = tokenBase;
79
+ return ret("string", "string");
80
+ };
81
+ }
82
+
83
+ return {
84
+ startState: function(base) {
85
+ return {tokenize: tokenBase,
86
+ baseIndent: base || 0,
87
+ stack: []};
88
+ },
89
+
90
+ token: function(stream, state) {
91
+ if (stream.eatSpace()) return null;
92
+ var style = state.tokenize(stream, state);
93
+
94
+ var context = state.stack[state.stack.length-1];
95
+ if (type == "hash" && context == "rule") style = "atom";
96
+ else if (style == "variable") {
97
+ if (context == "rule") style = "number";
98
+ else if (!context || context == "@media{") style = "tag";
99
+ }
100
+
101
+ if (context == "rule" && /^[\{\};]$/.test(type))
102
+ state.stack.pop();
103
+ if (type == "{") {
104
+ if (context == "@media") state.stack[state.stack.length-1] = "@media{";
105
+ else state.stack.push("{");
106
+ }
107
+ else if (type == "}") state.stack.pop();
108
+ else if (type == "@media") state.stack.push("@media");
109
+ else if (context == "{" && type != "comment") state.stack.push("rule");
110
+ return style;
111
+ },
112
+
113
+ indent: function(state, textAfter) {
114
+ var n = state.stack.length;
115
+ if (/^\}/.test(textAfter))
116
+ n -= state.stack[state.stack.length-1] == "rule" ? 2 : 1;
117
+ return state.baseIndent + n * indentUnit;
118
+ },
119
+
120
+ electricChars: "}"
121
+ };
122
+ });
123
+
124
+ CodeMirror.defineMIME("text/css", "css");
@@ -0,0 +1,84 @@
1
+ //= require ./xml
2
+ //= require ./css
3
+ //= require ./javascript
4
+ //= require_self
5
+
6
+ CodeMirror.defineMode("htmlmixed", function(config, parserConfig) {
7
+ var htmlMode = CodeMirror.getMode(config, {name: "xml", htmlMode: true});
8
+ var jsMode = CodeMirror.getMode(config, "javascript");
9
+ var cssMode = CodeMirror.getMode(config, "css");
10
+
11
+ function html(stream, state) {
12
+ var style = htmlMode.token(stream, state.htmlState);
13
+ if (style == "tag" && stream.current() == ">" && state.htmlState.context) {
14
+ if (/^script$/i.test(state.htmlState.context.tagName)) {
15
+ state.token = javascript;
16
+ state.localState = jsMode.startState(htmlMode.indent(state.htmlState, ""));
17
+ state.mode = "javascript";
18
+ }
19
+ else if (/^style$/i.test(state.htmlState.context.tagName)) {
20
+ state.token = css;
21
+ state.localState = cssMode.startState(htmlMode.indent(state.htmlState, ""));
22
+ state.mode = "css";
23
+ }
24
+ }
25
+ return style;
26
+ }
27
+ function maybeBackup(stream, pat, style) {
28
+ var cur = stream.current();
29
+ var close = cur.search(pat);
30
+ if (close > -1) stream.backUp(cur.length - close);
31
+ return style;
32
+ }
33
+ function javascript(stream, state) {
34
+ if (stream.match(/^<\/\s*script\s*>/i, false)) {
35
+ state.token = html;
36
+ state.curState = null;
37
+ state.mode = "html";
38
+ return html(stream, state);
39
+ }
40
+ return maybeBackup(stream, /<\/\s*script\s*>/,
41
+ jsMode.token(stream, state.localState));
42
+ }
43
+ function css(stream, state) {
44
+ if (stream.match(/^<\/\s*style\s*>/i, false)) {
45
+ state.token = html;
46
+ state.localState = null;
47
+ state.mode = "html";
48
+ return html(stream, state);
49
+ }
50
+ return maybeBackup(stream, /<\/\s*style\s*>/,
51
+ cssMode.token(stream, state.localState));
52
+ }
53
+
54
+ return {
55
+ startState: function() {
56
+ var state = htmlMode.startState();
57
+ return {token: html, localState: null, mode: "html", htmlState: state};
58
+ },
59
+
60
+ copyState: function(state) {
61
+ if (state.localState)
62
+ var local = CodeMirror.copyState(state.token == css ? cssMode : jsMode, state.localState);
63
+ return {token: state.token, localState: local, mode: state.mode,
64
+ htmlState: CodeMirror.copyState(htmlMode, state.htmlState)};
65
+ },
66
+
67
+ token: function(stream, state) {
68
+ return state.token(stream, state);
69
+ },
70
+
71
+ indent: function(state, textAfter) {
72
+ if (state.token == html || /^\s*<\//.test(textAfter))
73
+ return htmlMode.indent(state.htmlState, textAfter);
74
+ else if (state.token == javascript)
75
+ return jsMode.indent(state.localState, textAfter);
76
+ else
77
+ return cssMode.indent(state.localState, textAfter);
78
+ },
79
+
80
+ electricChars: "/{}:"
81
+ }
82
+ });
83
+
84
+ CodeMirror.defineMIME("text/html", "htmlmixed");
@@ -0,0 +1,352 @@
1
+ CodeMirror.defineMode("javascript", function(config, parserConfig) {
2
+ var indentUnit = config.indentUnit;
3
+ var jsonMode = parserConfig.json;
4
+
5
+ // Tokenizer
6
+
7
+ var keywords = function(){
8
+ function kw(type) {return {type: type, style: "keyword"};}
9
+ var A = kw("keyword a"), B = kw("keyword b"), C = kw("keyword c");
10
+ var operator = kw("operator"), atom = {type: "atom", style: "atom"};
11
+ return {
12
+ "if": A, "while": A, "with": A, "else": B, "do": B, "try": B, "finally": B,
13
+ "return": C, "break": C, "continue": C, "new": C, "delete": C, "throw": C,
14
+ "var": kw("var"), "function": kw("function"), "catch": kw("catch"),
15
+ "for": kw("for"), "switch": kw("switch"), "case": kw("case"), "default": kw("default"),
16
+ "in": operator, "typeof": operator, "instanceof": operator,
17
+ "true": atom, "false": atom, "null": atom, "undefined": atom, "NaN": atom, "Infinity": atom
18
+ };
19
+ }();
20
+
21
+ var isOperatorChar = /[+\-*&%=<>!?|]/;
22
+
23
+ function chain(stream, state, f) {
24
+ state.tokenize = f;
25
+ return f(stream, state);
26
+ }
27
+
28
+ function nextUntilUnescaped(stream, end) {
29
+ var escaped = false, next;
30
+ while ((next = stream.next()) != null) {
31
+ if (next == end && !escaped)
32
+ return false;
33
+ escaped = !escaped && next == "\\";
34
+ }
35
+ return escaped;
36
+ }
37
+
38
+ // Used as scratch variables to communicate multiple values without
39
+ // consing up tons of objects.
40
+ var type, content;
41
+ function ret(tp, style, cont) {
42
+ type = tp; content = cont;
43
+ return style;
44
+ }
45
+
46
+ function jsTokenBase(stream, state) {
47
+ var ch = stream.next();
48
+ if (ch == '"' || ch == "'")
49
+ return chain(stream, state, jsTokenString(ch));
50
+ else if (/[\[\]{}\(\),;\:\.]/.test(ch))
51
+ return ret(ch);
52
+ else if (ch == "0" && stream.eat(/x/i)) {
53
+ stream.eatWhile(/[\da-f]/i);
54
+ return ret("number", "number");
55
+ }
56
+ else if (/\d/.test(ch)) {
57
+ stream.match(/^\d*(?:\.\d*)?(?:e[+\-]?\d+)?/);
58
+ return ret("number", "number");
59
+ }
60
+ else if (ch == "/") {
61
+ if (stream.eat("*")) {
62
+ return chain(stream, state, jsTokenComment);
63
+ }
64
+ else if (stream.eat("/")) {
65
+ stream.skipToEnd();
66
+ return ret("comment", "comment");
67
+ }
68
+ else if (state.reAllowed) {
69
+ nextUntilUnescaped(stream, "/");
70
+ stream.eatWhile(/[gimy]/); // 'y' is "sticky" option in Mozilla
71
+ return ret("regexp", "string");
72
+ }
73
+ else {
74
+ stream.eatWhile(isOperatorChar);
75
+ return ret("operator", null, stream.current());
76
+ }
77
+ }
78
+ else if (ch == "#") {
79
+ stream.skipToEnd();
80
+ return ret("error", "error");
81
+ }
82
+ else if (isOperatorChar.test(ch)) {
83
+ stream.eatWhile(isOperatorChar);
84
+ return ret("operator", null, stream.current());
85
+ }
86
+ else {
87
+ stream.eatWhile(/[\w\$_]/);
88
+ var word = stream.current(), known = keywords.propertyIsEnumerable(word) && keywords[word];
89
+ return known ? ret(known.type, known.style, word) :
90
+ ret("variable", "variable", word);
91
+ }
92
+ }
93
+
94
+ function jsTokenString(quote) {
95
+ return function(stream, state) {
96
+ if (!nextUntilUnescaped(stream, quote))
97
+ state.tokenize = jsTokenBase;
98
+ return ret("string", "string");
99
+ };
100
+ }
101
+
102
+ function jsTokenComment(stream, state) {
103
+ var maybeEnd = false, ch;
104
+ while (ch = stream.next()) {
105
+ if (ch == "/" && maybeEnd) {
106
+ state.tokenize = jsTokenBase;
107
+ break;
108
+ }
109
+ maybeEnd = (ch == "*");
110
+ }
111
+ return ret("comment", "comment");
112
+ }
113
+
114
+ // Parser
115
+
116
+ var atomicTypes = {"atom": true, "number": true, "variable": true, "string": true, "regexp": true};
117
+
118
+ function JSLexical(indented, column, type, align, prev, info) {
119
+ this.indented = indented;
120
+ this.column = column;
121
+ this.type = type;
122
+ this.prev = prev;
123
+ this.info = info;
124
+ if (align != null) this.align = align;
125
+ }
126
+
127
+ function inScope(state, varname) {
128
+ for (var v = state.localVars; v; v = v.next)
129
+ if (v.name == varname) return true;
130
+ }
131
+
132
+ function parseJS(state, style, type, content, stream) {
133
+ var cc = state.cc;
134
+ // Communicate our context to the combinators.
135
+ // (Less wasteful than consing up a hundred closures on every call.)
136
+ cx.state = state; cx.stream = stream; cx.marked = null, cx.cc = cc;
137
+
138
+ if (!state.lexical.hasOwnProperty("align"))
139
+ state.lexical.align = true;
140
+
141
+ while(true) {
142
+ var combinator = cc.length ? cc.pop() : jsonMode ? expression : statement;
143
+ if (combinator(type, content)) {
144
+ while(cc.length && cc[cc.length - 1].lex)
145
+ cc.pop()();
146
+ if (cx.marked) return cx.marked;
147
+ if (type == "variable" && inScope(state, content)) return "variable-2";
148
+ return style;
149
+ }
150
+ }
151
+ }
152
+
153
+ // Combinator utils
154
+
155
+ var cx = {state: null, column: null, marked: null, cc: null};
156
+ function pass() {
157
+ for (var i = arguments.length - 1; i >= 0; i--) cx.cc.push(arguments[i]);
158
+ }
159
+ function cont() {
160
+ pass.apply(null, arguments);
161
+ return true;
162
+ }
163
+ function register(varname) {
164
+ var state = cx.state;
165
+ if (state.context) {
166
+ cx.marked = "def";
167
+ for (var v = state.localVars; v; v = v.next)
168
+ if (v.name == varname) return;
169
+ state.localVars = {name: varname, next: state.localVars};
170
+ }
171
+ }
172
+
173
+ // Combinators
174
+
175
+ var defaultVars = {name: "this", next: {name: "arguments"}};
176
+ function pushcontext() {
177
+ if (!cx.state.context) cx.state.localVars = defaultVars;
178
+ cx.state.context = {prev: cx.state.context, vars: cx.state.localVars};
179
+ }
180
+ function popcontext() {
181
+ cx.state.localVars = cx.state.context.vars;
182
+ cx.state.context = cx.state.context.prev;
183
+ }
184
+ function pushlex(type, info) {
185
+ var result = function() {
186
+ var state = cx.state;
187
+ state.lexical = new JSLexical(state.indented, cx.stream.column(), type, null, state.lexical, info)
188
+ };
189
+ result.lex = true;
190
+ return result;
191
+ }
192
+ function poplex() {
193
+ var state = cx.state;
194
+ if (state.lexical.prev) {
195
+ if (state.lexical.type == ")")
196
+ state.indented = state.lexical.indented;
197
+ state.lexical = state.lexical.prev;
198
+ }
199
+ }
200
+ poplex.lex = true;
201
+
202
+ function expect(wanted) {
203
+ return function expecting(type) {
204
+ if (type == wanted) return cont();
205
+ else if (wanted == ";") return pass();
206
+ else return cont(arguments.callee);
207
+ };
208
+ }
209
+
210
+ function statement(type) {
211
+ if (type == "var") return cont(pushlex("vardef"), vardef1, expect(";"), poplex);
212
+ if (type == "keyword a") return cont(pushlex("form"), expression, statement, poplex);
213
+ if (type == "keyword b") return cont(pushlex("form"), statement, poplex);
214
+ if (type == "{") return cont(pushlex("}"), block, poplex);
215
+ if (type == ";") return cont();
216
+ if (type == "function") return cont(functiondef);
217
+ if (type == "for") return cont(pushlex("form"), expect("("), pushlex(")"), forspec1, expect(")"),
218
+ poplex, statement, poplex);
219
+ if (type == "variable") return cont(pushlex("stat"), maybelabel);
220
+ if (type == "switch") return cont(pushlex("form"), expression, pushlex("}", "switch"), expect("{"),
221
+ block, poplex, poplex);
222
+ if (type == "case") return cont(expression, expect(":"));
223
+ if (type == "default") return cont(expect(":"));
224
+ if (type == "catch") return cont(pushlex("form"), pushcontext, expect("("), funarg, expect(")"),
225
+ statement, poplex, popcontext);
226
+ return pass(pushlex("stat"), expression, expect(";"), poplex);
227
+ }
228
+ function expression(type) {
229
+ if (atomicTypes.hasOwnProperty(type)) return cont(maybeoperator);
230
+ if (type == "function") return cont(functiondef);
231
+ if (type == "keyword c") return cont(expression);
232
+ if (type == "(") return cont(pushlex(")"), expression, expect(")"), poplex, maybeoperator);
233
+ if (type == "operator") return cont(expression);
234
+ if (type == "[") return cont(pushlex("]"), commasep(expression, "]"), poplex, maybeoperator);
235
+ if (type == "{") return cont(pushlex("}"), commasep(objprop, "}"), poplex, maybeoperator);
236
+ return cont();
237
+ }
238
+ function maybeoperator(type, value) {
239
+ if (type == "operator" && /\+\+|--/.test(value)) return cont(maybeoperator);
240
+ if (type == "operator") return cont(expression);
241
+ if (type == ";") return;
242
+ if (type == "(") return cont(pushlex(")"), commasep(expression, ")"), poplex, maybeoperator);
243
+ if (type == ".") return cont(property, maybeoperator);
244
+ if (type == "[") return cont(pushlex("]"), expression, expect("]"), poplex, maybeoperator);
245
+ }
246
+ function maybelabel(type) {
247
+ if (type == ":") return cont(poplex, statement);
248
+ return pass(maybeoperator, expect(";"), poplex);
249
+ }
250
+ function property(type) {
251
+ if (type == "variable") {cx.marked = "property"; return cont();}
252
+ }
253
+ function objprop(type) {
254
+ if (type == "variable") cx.marked = "property";
255
+ if (atomicTypes.hasOwnProperty(type)) return cont(expect(":"), expression);
256
+ }
257
+ function commasep(what, end) {
258
+ function proceed(type) {
259
+ if (type == ",") return cont(what, proceed);
260
+ if (type == end) return cont();
261
+ return cont(expect(end));
262
+ }
263
+ return function commaSeparated(type) {
264
+ if (type == end) return cont();
265
+ else return pass(what, proceed);
266
+ };
267
+ }
268
+ function block(type) {
269
+ if (type == "}") return cont();
270
+ return pass(statement, block);
271
+ }
272
+ function vardef1(type, value) {
273
+ if (type == "variable"){register(value); return cont(vardef2);}
274
+ return cont();
275
+ }
276
+ function vardef2(type, value) {
277
+ if (value == "=") return cont(expression, vardef2);
278
+ if (type == ",") return cont(vardef1);
279
+ }
280
+ function forspec1(type) {
281
+ if (type == "var") return cont(vardef1, forspec2);
282
+ if (type == ";") return pass(forspec2);
283
+ if (type == "variable") return cont(formaybein);
284
+ return pass(forspec2);
285
+ }
286
+ function formaybein(type, value) {
287
+ if (value == "in") return cont(expression);
288
+ return cont(maybeoperator, forspec2);
289
+ }
290
+ function forspec2(type, value) {
291
+ if (type == ";") return cont(forspec3);
292
+ if (value == "in") return cont(expression);
293
+ return cont(expression, expect(";"), forspec3);
294
+ }
295
+ function forspec3(type) {
296
+ if (type != ")") cont(expression);
297
+ }
298
+ function functiondef(type, value) {
299
+ if (type == "variable") {register(value); return cont(functiondef);}
300
+ if (type == "(") return cont(pushlex(")"), pushcontext, commasep(funarg, ")"), poplex, statement, popcontext);
301
+ }
302
+ function funarg(type, value) {
303
+ if (type == "variable") {register(value); return cont();}
304
+ }
305
+
306
+ // Interface
307
+
308
+ return {
309
+ startState: function(basecolumn) {
310
+ return {
311
+ tokenize: jsTokenBase,
312
+ reAllowed: true,
313
+ cc: [],
314
+ lexical: new JSLexical((basecolumn || 0) - indentUnit, 0, "block", false),
315
+ localVars: null,
316
+ context: null,
317
+ indented: 0
318
+ };
319
+ },
320
+
321
+ token: function(stream, state) {
322
+ if (stream.sol()) {
323
+ if (!state.lexical.hasOwnProperty("align"))
324
+ state.lexical.align = false;
325
+ state.indented = stream.indentation();
326
+ }
327
+ if (stream.eatSpace()) return null;
328
+ var style = state.tokenize(stream, state);
329
+ if (type == "comment") return style;
330
+ state.reAllowed = type == "operator" || type == "keyword c" || type.match(/^[\[{}\(,;:]$/);
331
+ return parseJS(state, style, type, content, stream);
332
+ },
333
+
334
+ indent: function(state, textAfter) {
335
+ if (state.tokenize != jsTokenBase) return 0;
336
+ var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical,
337
+ type = lexical.type, closing = firstChar == type;
338
+ if (type == "vardef") return lexical.indented + 4;
339
+ else if (type == "form" && firstChar == "{") return lexical.indented;
340
+ else if (type == "stat" || type == "form") return lexical.indented + indentUnit;
341
+ else if (lexical.info == "switch" && !closing)
342
+ return lexical.indented + (/^(?:case|default)\b/.test(textAfter) ? indentUnit : 2 * indentUnit);
343
+ else if (lexical.align) return lexical.column + (closing ? 0 : 1);
344
+ else return lexical.indented + (closing ? 0 : indentUnit);
345
+ },
346
+
347
+ electricChars: ":{}"
348
+ };
349
+ });
350
+
351
+ CodeMirror.defineMIME("text/javascript", "javascript");
352
+ CodeMirror.defineMIME("application/json", {name: "javascript", json: true});