qless 0.9.1 → 0.9.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. data/bin/install_phantomjs +7 -0
  2. data/lib/qless.rb +4 -0
  3. data/lib/qless/job.rb +40 -38
  4. data/lib/qless/qless-core/cancel.lua +9 -9
  5. data/lib/qless/qless-core/failed.lua +1 -1
  6. data/lib/qless/qless-core/peek.lua +22 -12
  7. data/lib/qless/qless-core/pop.lua +31 -16
  8. data/lib/qless/qless-core/recur.lua +12 -3
  9. data/lib/qless/server.rb +96 -66
  10. data/lib/qless/server/static/css/bootstrap-responsive.css +686 -0
  11. data/lib/qless/server/static/css/bootstrap-responsive.min.css +12 -0
  12. data/lib/qless/server/static/css/bootstrap.css +3991 -0
  13. data/lib/qless/server/static/css/bootstrap.min.css +689 -0
  14. data/lib/qless/server/static/css/codemirror.css +112 -0
  15. data/lib/qless/server/static/css/docs.css +819 -0
  16. data/lib/qless/server/static/css/jquery.noty.css +105 -0
  17. data/lib/qless/server/static/css/noty_theme_twitter.css +137 -0
  18. data/lib/qless/server/static/css/style.css +204 -0
  19. data/lib/qless/server/static/favicon.ico +0 -0
  20. data/lib/qless/server/static/img/glyphicons-halflings-white.png +0 -0
  21. data/lib/qless/server/static/img/glyphicons-halflings.png +0 -0
  22. data/lib/qless/server/static/js/bootstrap-alert.js +94 -0
  23. data/lib/qless/server/static/js/bootstrap-scrollspy.js +125 -0
  24. data/lib/qless/server/static/js/bootstrap-tab.js +130 -0
  25. data/lib/qless/server/static/js/bootstrap-tooltip.js +270 -0
  26. data/lib/qless/server/static/js/bootstrap-typeahead.js +285 -0
  27. data/lib/qless/server/static/js/bootstrap.js +1726 -0
  28. data/lib/qless/server/static/js/bootstrap.min.js +6 -0
  29. data/lib/qless/server/static/js/codemirror.js +2972 -0
  30. data/lib/qless/server/static/js/jquery.noty.js +220 -0
  31. data/lib/qless/server/static/js/mode/javascript.js +360 -0
  32. data/lib/qless/server/static/js/theme/cobalt.css +18 -0
  33. data/lib/qless/server/static/js/theme/eclipse.css +25 -0
  34. data/lib/qless/server/static/js/theme/elegant.css +10 -0
  35. data/lib/qless/server/static/js/theme/lesser-dark.css +45 -0
  36. data/lib/qless/server/static/js/theme/monokai.css +28 -0
  37. data/lib/qless/server/static/js/theme/neat.css +9 -0
  38. data/lib/qless/server/static/js/theme/night.css +21 -0
  39. data/lib/qless/server/static/js/theme/rubyblue.css +21 -0
  40. data/lib/qless/server/static/js/theme/xq-dark.css +46 -0
  41. data/lib/qless/server/views/_job.erb +219 -0
  42. data/lib/qless/server/views/_job_list.erb +8 -0
  43. data/lib/qless/server/views/_pagination.erb +7 -0
  44. data/lib/qless/server/views/about.erb +130 -0
  45. data/lib/qless/server/views/config.erb +14 -0
  46. data/lib/qless/server/views/failed.erb +48 -0
  47. data/lib/qless/server/views/failed_type.erb +18 -0
  48. data/lib/qless/server/views/job.erb +17 -0
  49. data/lib/qless/server/views/layout.erb +341 -0
  50. data/lib/qless/server/views/overview.erb +90 -0
  51. data/lib/qless/server/views/queue.erb +122 -0
  52. data/lib/qless/server/views/queues.erb +26 -0
  53. data/lib/qless/server/views/tag.erb +6 -0
  54. data/lib/qless/server/views/track.erb +69 -0
  55. data/lib/qless/server/views/worker.erb +34 -0
  56. data/lib/qless/server/views/workers.erb +14 -0
  57. data/lib/qless/version.rb +1 -1
  58. data/lib/qless/worker.rb +11 -2
  59. metadata +72 -6
  60. data/lib/qless/qless-core/ruby/lib/qless-core.rb +0 -1
  61. data/lib/qless/qless-core/ruby/lib/qless/core.rb +0 -13
  62. data/lib/qless/qless-core/ruby/lib/qless/core/version.rb +0 -5
  63. data/lib/qless/qless-core/ruby/spec/qless_core_spec.rb +0 -13
@@ -0,0 +1,220 @@
1
+ /**
2
+ * jQuery Noty Plugin v1.1.1
3
+ * Authors: Nedim Arabacı (http://ned.im), Muhittin Özer (http://muhittinozer.com)
4
+ *
5
+ * Examples and Documentation - http://needim.github.com/noty/
6
+ *
7
+ * Licensed under the MIT licenses:
8
+ * http://www.opensource.org/licenses/mit-license.php
9
+ *
10
+ **/
11
+ (function($) {
12
+ $.noty = function(options, customContainer) {
13
+
14
+ var base = this;
15
+ var $noty = null;
16
+ var isCustom = false;
17
+
18
+ base.init = function(options) {
19
+ base.options = $.extend({}, $.noty.defaultOptions, options);
20
+ base.options.type = base.options.cssPrefix+base.options.type;
21
+ base.options.id = base.options.type+'_'+new Date().getTime();
22
+ base.options.layout = base.options.cssPrefix+'layout_'+base.options.layout;
23
+
24
+ if (base.options.custom.container) customContainer = base.options.custom.container;
25
+ isCustom = ($.type(customContainer) === 'object') ? true : false;
26
+
27
+ return base.addQueue();
28
+ };
29
+
30
+ // Push notification to queue
31
+ base.addQueue = function() {
32
+ var isGrowl = ($.inArray(base.options.layout, $.noty.growls) == -1) ? false : true;
33
+ if (!isGrowl) (base.options.force) ? $.noty.queue.unshift({options: base.options}) : $.noty.queue.push({options: base.options});
34
+ return base.render(isGrowl);
35
+ };
36
+
37
+ // Render the noty
38
+ base.render = function(isGrowl) {
39
+
40
+ // Layout spesific container settings
41
+ var container = (isCustom) ? customContainer.addClass(base.options.theme+' '+base.options.layout+' noty_custom_container') : $('body');
42
+ if (isGrowl) {
43
+ if ($('ul.noty_cont.' + base.options.layout).length == 0)
44
+ container.prepend($('<ul/>').addClass('noty_cont ' + base.options.layout));
45
+ container = $('ul.noty_cont.' + base.options.layout);
46
+ } else {
47
+ if ($.noty.available) {
48
+ var fromQueue = $.noty.queue.shift(); // Get noty from queue
49
+ if ($.type(fromQueue) === 'object') {
50
+ $.noty.available = false;
51
+ base.options = fromQueue.options;
52
+ } else {
53
+ $.noty.available = true; // Queue is over
54
+ return base.options.id;
55
+ }
56
+ } else {
57
+ return base.options.id;
58
+ }
59
+ }
60
+ base.container = container;
61
+
62
+ // Generating noty bar
63
+ base.bar = $('<div class="noty_bar"/>').attr('id', base.options.id).addClass(base.options.theme+' '+base.options.layout+' '+base.options.type);
64
+ $noty = base.bar;
65
+ $noty.append(base.options.template).find('.noty_text').html(base.options.text);
66
+ $noty.data('noty_options', base.options);
67
+
68
+ // Close button display
69
+ (base.options.closeButton) ? $noty.addClass('noty_closable').find('.noty_close').show() : $noty.find('.noty_close').remove();
70
+
71
+ // Bind close event to button
72
+ $noty.find('.noty_close').bind('click', function() { $noty.trigger('noty.close'); });
73
+
74
+ // If we have a button we must disable closeOnSelfClick and closeOnSelfOver option
75
+ if (base.options.buttons) base.options.closeOnSelfClick = base.options.closeOnSelfOver = false;
76
+ // Close on self click
77
+ if (base.options.closeOnSelfClick) $noty.bind('click', function() { $noty.trigger('noty.close'); }).css('cursor', 'pointer');
78
+ // Close on self mouseover
79
+ if (base.options.closeOnSelfOver) $noty.bind('mouseover', function() { $noty.trigger('noty.close'); }).css('cursor', 'pointer');
80
+
81
+ // Set buttons if available
82
+ if (base.options.buttons) {
83
+ $buttons = $('<div/>').addClass('noty_buttons');
84
+ $noty.find('.noty_message').append($buttons);
85
+ $.each(base.options.buttons, function(i, button) {
86
+ bclass = (button.type) ? button.type : 'gray';
87
+ $button = $('<button/>').addClass(bclass).html(button.text).appendTo($noty.find('.noty_buttons'))
88
+ .bind('click', function() {
89
+ if ($.isFunction(button.click)) {
90
+ button.click.call($button, $noty);
91
+ }
92
+ });
93
+ });
94
+ }
95
+
96
+ return base.show(isGrowl);
97
+ };
98
+
99
+ base.show = function(isGrowl) {
100
+
101
+ // is Modal?
102
+ if (base.options.modal) $('<div/>').addClass('noty_modal').addClass(base.options.theme).prependTo($('body')).fadeIn('fast');
103
+
104
+ $noty.close = function() { return this.trigger('noty.close'); };
105
+
106
+ // Prepend noty to container
107
+ (isGrowl) ? base.container.prepend($('<li/>').append($noty)) : base.container.prepend($noty);
108
+
109
+ // topCenter and center specific options
110
+ if (base.options.layout == 'noty_layout_topCenter' || base.options.layout == 'noty_layout_center') {
111
+ $.noty.reCenter($noty);
112
+ }
113
+
114
+ $noty.bind('noty.setText', function(event, text) {
115
+ $noty.find('.noty_text').html(text); $.noty.reCenter($noty);
116
+ });
117
+
118
+ $noty.bind('noty.getId', function(event) {
119
+ return $noty.data('noty_options').id;
120
+ });
121
+
122
+ // Bind close event
123
+ $noty.one('noty.close', function(event) {
124
+ var options = $noty.data('noty_options');
125
+
126
+ // Modal Cleaning
127
+ if (options.modal) $('.noty_modal').fadeOut('fast', function() { $(this).remove(); });
128
+
129
+ $noty.clearQueue().stop().animate(
130
+ $noty.data('noty_options').animateClose,
131
+ $noty.data('noty_options').speed,
132
+ $noty.data('noty_options').easing,
133
+ $noty.data('noty_options').onClose)
134
+ .promise().done(function() {
135
+
136
+ // Layout spesific cleaning
137
+ if ($.inArray($noty.data('noty_options').layout, $.noty.growls) > -1) {
138
+ $noty.parent().remove();
139
+ } else {
140
+ $noty.remove();
141
+
142
+ // queue render
143
+ $.noty.available = true;
144
+ base.render(false);
145
+ }
146
+
147
+ });
148
+ });
149
+
150
+ // Start the show
151
+ $noty.animate(base.options.animateOpen, base.options.speed, base.options.easing, base.options.onShow);
152
+
153
+ // If noty is have a timeout option
154
+ if (base.options.timeout) $noty.delay(base.options.timeout).promise().done(function() { $noty.trigger('noty.close'); });
155
+ return base.options.id;
156
+ };
157
+
158
+ // Run initializer
159
+ return base.init(options);
160
+ };
161
+
162
+ // API
163
+ $.noty.get = function(id) { return $('#'+id); };
164
+ $.noty.close = function(id) {
165
+ $.noty.get(id).trigger('noty.close');
166
+ };
167
+ $.noty.setText = function(id, text) {
168
+ $.noty.get(id).trigger('noty.setText', text);
169
+ };
170
+ $.noty.closeAll = function() {
171
+ $.noty.clearQueue();
172
+ $('.noty_bar').trigger('noty.close');
173
+ };
174
+ $.noty.reCenter = function(noty) {
175
+ noty.css({'left': ($(window).width() - noty.outerWidth()) / 2 + 'px'});
176
+ };
177
+ $.noty.clearQueue = function() {
178
+ $.noty.queue = [];
179
+ };
180
+
181
+ $.noty.queue = [];
182
+ $.noty.growls = ['noty_layout_topLeft', 'noty_layout_topRight', 'noty_layout_bottomLeft', 'noty_layout_bottomRight'];
183
+ $.noty.available = true;
184
+ $.noty.defaultOptions = {
185
+ layout: 'top',
186
+ theme: 'noty_theme_default',
187
+ animateOpen: {height: 'toggle'},
188
+ animateClose: {height: 'toggle'},
189
+ easing: 'swing',
190
+ text: '',
191
+ type: 'alert',
192
+ speed: 500,
193
+ timeout: 5000,
194
+ closeButton: false,
195
+ closeOnSelfClick: true,
196
+ closeOnSelfOver: false,
197
+ force: false,
198
+ onShow: false,
199
+ onClose: false,
200
+ buttons: false,
201
+ modal: false,
202
+ template: '<div class="noty_message"><span class="noty_text"></span><div class="noty_close"></div></div>',
203
+ cssPrefix: 'noty_',
204
+ custom: {
205
+ container: null
206
+ }
207
+ };
208
+
209
+ $.fn.noty = function(options) {
210
+ return this.each(function() {
211
+ (new $.noty(options, $(this)));
212
+ });
213
+ };
214
+
215
+ })(jQuery);
216
+
217
+ //Helper
218
+ function noty(options) {
219
+ return jQuery.noty(options); // returns an id
220
+ }
@@ -0,0 +1,360 @@
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"), "const": kw("var"), "let": kw("var"),
15
+ "function": kw("function"), "catch": kw("catch"),
16
+ "for": kw("for"), "switch": kw("switch"), "case": kw("case"), "default": kw("default"),
17
+ "in": operator, "typeof": operator, "instanceof": operator,
18
+ "true": atom, "false": atom, "null": atom, "undefined": atom, "NaN": atom, "Infinity": atom
19
+ };
20
+ }();
21
+
22
+ var isOperatorChar = /[+\-*&%=<>!?|]/;
23
+
24
+ function chain(stream, state, f) {
25
+ state.tokenize = f;
26
+ return f(stream, state);
27
+ }
28
+
29
+ function nextUntilUnescaped(stream, end) {
30
+ var escaped = false, next;
31
+ while ((next = stream.next()) != null) {
32
+ if (next == end && !escaped)
33
+ return false;
34
+ escaped = !escaped && next == "\\";
35
+ }
36
+ return escaped;
37
+ }
38
+
39
+ // Used as scratch variables to communicate multiple values without
40
+ // consing up tons of objects.
41
+ var type, content;
42
+ function ret(tp, style, cont) {
43
+ type = tp; content = cont;
44
+ return style;
45
+ }
46
+
47
+ function jsTokenBase(stream, state) {
48
+ var ch = stream.next();
49
+ if (ch == '"' || ch == "'")
50
+ return chain(stream, state, jsTokenString(ch));
51
+ else if (/[\[\]{}\(\),;\:\.]/.test(ch))
52
+ return ret(ch);
53
+ else if (ch == "0" && stream.eat(/x/i)) {
54
+ stream.eatWhile(/[\da-f]/i);
55
+ return ret("number", "number");
56
+ }
57
+ else if (/\d/.test(ch)) {
58
+ stream.match(/^\d*(?:\.\d*)?(?:[eE][+\-]?\d+)?/);
59
+ return ret("number", "number");
60
+ }
61
+ else if (ch == "/") {
62
+ if (stream.eat("*")) {
63
+ return chain(stream, state, jsTokenComment);
64
+ }
65
+ else if (stream.eat("/")) {
66
+ stream.skipToEnd();
67
+ return ret("comment", "comment");
68
+ }
69
+ else if (state.reAllowed) {
70
+ nextUntilUnescaped(stream, "/");
71
+ stream.eatWhile(/[gimy]/); // 'y' is "sticky" option in Mozilla
72
+ return ret("regexp", "string-2");
73
+ }
74
+ else {
75
+ stream.eatWhile(isOperatorChar);
76
+ return ret("operator", null, stream.current());
77
+ }
78
+ }
79
+ else if (ch == "#") {
80
+ stream.skipToEnd();
81
+ return ret("error", "error");
82
+ }
83
+ else if (isOperatorChar.test(ch)) {
84
+ stream.eatWhile(isOperatorChar);
85
+ return ret("operator", null, stream.current());
86
+ }
87
+ else {
88
+ stream.eatWhile(/[\w\$_]/);
89
+ var word = stream.current(), known = keywords.propertyIsEnumerable(word) && keywords[word];
90
+ return (known && state.kwAllowed) ? ret(known.type, known.style, word) :
91
+ ret("variable", "variable", word);
92
+ }
93
+ }
94
+
95
+ function jsTokenString(quote) {
96
+ return function(stream, state) {
97
+ if (!nextUntilUnescaped(stream, quote))
98
+ state.tokenize = jsTokenBase;
99
+ return ret("string", "string");
100
+ };
101
+ }
102
+
103
+ function jsTokenComment(stream, state) {
104
+ var maybeEnd = false, ch;
105
+ while (ch = stream.next()) {
106
+ if (ch == "/" && maybeEnd) {
107
+ state.tokenize = jsTokenBase;
108
+ break;
109
+ }
110
+ maybeEnd = (ch == "*");
111
+ }
112
+ return ret("comment", "comment");
113
+ }
114
+
115
+ // Parser
116
+
117
+ var atomicTypes = {"atom": true, "number": true, "variable": true, "string": true, "regexp": true};
118
+
119
+ function JSLexical(indented, column, type, align, prev, info) {
120
+ this.indented = indented;
121
+ this.column = column;
122
+ this.type = type;
123
+ this.prev = prev;
124
+ this.info = info;
125
+ if (align != null) this.align = align;
126
+ }
127
+
128
+ function inScope(state, varname) {
129
+ for (var v = state.localVars; v; v = v.next)
130
+ if (v.name == varname) return true;
131
+ }
132
+
133
+ function parseJS(state, style, type, content, stream) {
134
+ var cc = state.cc;
135
+ // Communicate our context to the combinators.
136
+ // (Less wasteful than consing up a hundred closures on every call.)
137
+ cx.state = state; cx.stream = stream; cx.marked = null, cx.cc = cc;
138
+
139
+ if (!state.lexical.hasOwnProperty("align"))
140
+ state.lexical.align = true;
141
+
142
+ while(true) {
143
+ var combinator = cc.length ? cc.pop() : jsonMode ? expression : statement;
144
+ if (combinator(type, content)) {
145
+ while(cc.length && cc[cc.length - 1].lex)
146
+ cc.pop()();
147
+ if (cx.marked) return cx.marked;
148
+ if (type == "variable" && inScope(state, content)) return "variable-2";
149
+ return style;
150
+ }
151
+ }
152
+ }
153
+
154
+ // Combinator utils
155
+
156
+ var cx = {state: null, column: null, marked: null, cc: null};
157
+ function pass() {
158
+ for (var i = arguments.length - 1; i >= 0; i--) cx.cc.push(arguments[i]);
159
+ }
160
+ function cont() {
161
+ pass.apply(null, arguments);
162
+ return true;
163
+ }
164
+ function register(varname) {
165
+ var state = cx.state;
166
+ if (state.context) {
167
+ cx.marked = "def";
168
+ for (var v = state.localVars; v; v = v.next)
169
+ if (v.name == varname) return;
170
+ state.localVars = {name: varname, next: state.localVars};
171
+ }
172
+ }
173
+
174
+ // Combinators
175
+
176
+ var defaultVars = {name: "this", next: {name: "arguments"}};
177
+ function pushcontext() {
178
+ if (!cx.state.context) cx.state.localVars = defaultVars;
179
+ cx.state.context = {prev: cx.state.context, vars: cx.state.localVars};
180
+ }
181
+ function popcontext() {
182
+ cx.state.localVars = cx.state.context.vars;
183
+ cx.state.context = cx.state.context.prev;
184
+ }
185
+ function pushlex(type, info) {
186
+ var result = function() {
187
+ var state = cx.state;
188
+ state.lexical = new JSLexical(state.indented, cx.stream.column(), type, null, state.lexical, info)
189
+ };
190
+ result.lex = true;
191
+ return result;
192
+ }
193
+ function poplex() {
194
+ var state = cx.state;
195
+ if (state.lexical.prev) {
196
+ if (state.lexical.type == ")")
197
+ state.indented = state.lexical.indented;
198
+ state.lexical = state.lexical.prev;
199
+ }
200
+ }
201
+ poplex.lex = true;
202
+
203
+ function expect(wanted) {
204
+ return function expecting(type) {
205
+ if (type == wanted) return cont();
206
+ else if (wanted == ";") return pass();
207
+ else return cont(arguments.callee);
208
+ };
209
+ }
210
+
211
+ function statement(type) {
212
+ if (type == "var") return cont(pushlex("vardef"), vardef1, expect(";"), poplex);
213
+ if (type == "keyword a") return cont(pushlex("form"), expression, statement, poplex);
214
+ if (type == "keyword b") return cont(pushlex("form"), statement, poplex);
215
+ if (type == "{") return cont(pushlex("}"), block, poplex);
216
+ if (type == ";") return cont();
217
+ if (type == "function") return cont(functiondef);
218
+ if (type == "for") return cont(pushlex("form"), expect("("), pushlex(")"), forspec1, expect(")"),
219
+ poplex, statement, poplex);
220
+ if (type == "variable") return cont(pushlex("stat"), maybelabel);
221
+ if (type == "switch") return cont(pushlex("form"), expression, pushlex("}", "switch"), expect("{"),
222
+ block, poplex, poplex);
223
+ if (type == "case") return cont(expression, expect(":"));
224
+ if (type == "default") return cont(expect(":"));
225
+ if (type == "catch") return cont(pushlex("form"), pushcontext, expect("("), funarg, expect(")"),
226
+ statement, poplex, popcontext);
227
+ return pass(pushlex("stat"), expression, expect(";"), poplex);
228
+ }
229
+ function expression(type) {
230
+ if (atomicTypes.hasOwnProperty(type)) return cont(maybeoperator);
231
+ if (type == "function") return cont(functiondef);
232
+ if (type == "keyword c") return cont(maybeexpression);
233
+ if (type == "(") return cont(pushlex(")"), maybeexpression, expect(")"), poplex, maybeoperator);
234
+ if (type == "operator") return cont(expression);
235
+ if (type == "[") return cont(pushlex("]"), commasep(expression, "]"), poplex, maybeoperator);
236
+ if (type == "{") return cont(pushlex("}"), commasep(objprop, "}"), poplex, maybeoperator);
237
+ return cont();
238
+ }
239
+ function maybeexpression(type) {
240
+ if (type.match(/[;\}\)\],]/)) return pass();
241
+ return pass(expression);
242
+ }
243
+
244
+ function maybeoperator(type, value) {
245
+ if (type == "operator" && /\+\+|--/.test(value)) return cont(maybeoperator);
246
+ if (type == "operator") return cont(expression);
247
+ if (type == ";") return;
248
+ if (type == "(") return cont(pushlex(")"), commasep(expression, ")"), poplex, maybeoperator);
249
+ if (type == ".") return cont(property, maybeoperator);
250
+ if (type == "[") return cont(pushlex("]"), expression, expect("]"), poplex, maybeoperator);
251
+ }
252
+ function maybelabel(type) {
253
+ if (type == ":") return cont(poplex, statement);
254
+ return pass(maybeoperator, expect(";"), poplex);
255
+ }
256
+ function property(type) {
257
+ if (type == "variable") {cx.marked = "property"; return cont();}
258
+ }
259
+ function objprop(type) {
260
+ if (type == "variable") cx.marked = "property";
261
+ if (atomicTypes.hasOwnProperty(type)) return cont(expect(":"), expression);
262
+ }
263
+ function commasep(what, end) {
264
+ function proceed(type) {
265
+ if (type == ",") return cont(what, proceed);
266
+ if (type == end) return cont();
267
+ return cont(expect(end));
268
+ }
269
+ return function commaSeparated(type) {
270
+ if (type == end) return cont();
271
+ else return pass(what, proceed);
272
+ };
273
+ }
274
+ function block(type) {
275
+ if (type == "}") return cont();
276
+ return pass(statement, block);
277
+ }
278
+ function vardef1(type, value) {
279
+ if (type == "variable"){register(value); return cont(vardef2);}
280
+ return cont();
281
+ }
282
+ function vardef2(type, value) {
283
+ if (value == "=") return cont(expression, vardef2);
284
+ if (type == ",") return cont(vardef1);
285
+ }
286
+ function forspec1(type) {
287
+ if (type == "var") return cont(vardef1, forspec2);
288
+ if (type == ";") return pass(forspec2);
289
+ if (type == "variable") return cont(formaybein);
290
+ return pass(forspec2);
291
+ }
292
+ function formaybein(type, value) {
293
+ if (value == "in") return cont(expression);
294
+ return cont(maybeoperator, forspec2);
295
+ }
296
+ function forspec2(type, value) {
297
+ if (type == ";") return cont(forspec3);
298
+ if (value == "in") return cont(expression);
299
+ return cont(expression, expect(";"), forspec3);
300
+ }
301
+ function forspec3(type) {
302
+ if (type != ")") cont(expression);
303
+ }
304
+ function functiondef(type, value) {
305
+ if (type == "variable") {register(value); return cont(functiondef);}
306
+ if (type == "(") return cont(pushlex(")"), pushcontext, commasep(funarg, ")"), poplex, statement, popcontext);
307
+ }
308
+ function funarg(type, value) {
309
+ if (type == "variable") {register(value); return cont();}
310
+ }
311
+
312
+ // Interface
313
+
314
+ return {
315
+ startState: function(basecolumn) {
316
+ return {
317
+ tokenize: jsTokenBase,
318
+ reAllowed: true,
319
+ kwAllowed: true,
320
+ cc: [],
321
+ lexical: new JSLexical((basecolumn || 0) - indentUnit, 0, "block", false),
322
+ localVars: parserConfig.localVars,
323
+ context: parserConfig.localVars && {vars: parserConfig.localVars},
324
+ indented: 0
325
+ };
326
+ },
327
+
328
+ token: function(stream, state) {
329
+ if (stream.sol()) {
330
+ if (!state.lexical.hasOwnProperty("align"))
331
+ state.lexical.align = false;
332
+ state.indented = stream.indentation();
333
+ }
334
+ if (stream.eatSpace()) return null;
335
+ var style = state.tokenize(stream, state);
336
+ if (type == "comment") return style;
337
+ state.reAllowed = !!(type == "operator" || type == "keyword c" || type.match(/^[\[{}\(,;:]$/));
338
+ state.kwAllowed = type != '.';
339
+ return parseJS(state, style, type, content, stream);
340
+ },
341
+
342
+ indent: function(state, textAfter) {
343
+ if (state.tokenize != jsTokenBase) return 0;
344
+ var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical,
345
+ type = lexical.type, closing = firstChar == type;
346
+ if (type == "vardef") return lexical.indented + 4;
347
+ else if (type == "form" && firstChar == "{") return lexical.indented;
348
+ else if (type == "stat" || type == "form") return lexical.indented + indentUnit;
349
+ else if (lexical.info == "switch" && !closing)
350
+ return lexical.indented + (/^(?:case|default)\b/.test(textAfter) ? indentUnit : 2 * indentUnit);
351
+ else if (lexical.align) return lexical.column + (closing ? 0 : 1);
352
+ else return lexical.indented + (closing ? 0 : indentUnit);
353
+ },
354
+
355
+ electricChars: ":{}"
356
+ };
357
+ });
358
+
359
+ CodeMirror.defineMIME("text/javascript", "javascript");
360
+ CodeMirror.defineMIME("application/json", {name: "javascript", json: true});