puffer_pages 0.1.1 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (197) hide show
  1. data/.gitignore +5 -0
  2. data/.rspec +3 -1
  3. data/.rvmrc +1 -1
  4. data/.travis.yml +13 -5
  5. data/CHANGELOG.md +130 -7
  6. data/Gemfile +10 -1
  7. data/README.md +18 -20
  8. data/Rakefile +1 -1
  9. data/app/assets/javascripts/puffer/codemirror.js +4237 -2223
  10. data/app/assets/javascripts/puffer/codemirror/css.js +359 -18
  11. data/app/assets/javascripts/puffer/codemirror/htmlmixed.js +15 -14
  12. data/app/assets/javascripts/puffer/codemirror/javascript.js +91 -29
  13. data/app/assets/javascripts/puffer/codemirror/liquid.js +185 -0
  14. data/app/assets/javascripts/puffer/codemirror/xml.js +99 -27
  15. data/app/assets/javascripts/puffer/codemirror/yaml.js +95 -0
  16. data/app/assets/javascripts/puffer/liquid.js +28 -12
  17. data/app/assets/javascripts/puffer/matchbrackets.js +63 -0
  18. data/app/assets/javascripts/puffer/multiplex.js +95 -0
  19. data/app/assets/javascripts/puffer/puffer_pages.js +140 -44
  20. data/app/assets/stylesheets/puffer/codemirror.css +203 -67
  21. data/app/assets/stylesheets/puffer/codemirror/ambiance-mobile.css +6 -0
  22. data/app/assets/stylesheets/puffer/codemirror/ambiance.css +76 -0
  23. data/app/assets/stylesheets/puffer/codemirror/blackboard.css +25 -0
  24. data/app/assets/stylesheets/puffer/codemirror/cobalt.css +4 -4
  25. data/app/assets/stylesheets/puffer/codemirror/eclipse.css +1 -1
  26. data/app/assets/stylesheets/puffer/codemirror/elegant.css +2 -2
  27. data/app/assets/stylesheets/puffer/codemirror/erlang-dark.css +21 -0
  28. data/app/assets/stylesheets/puffer/codemirror/lesser-dark.css +44 -0
  29. data/app/assets/stylesheets/puffer/codemirror/monokai.css +4 -4
  30. data/app/assets/stylesheets/puffer/codemirror/neat.css +3 -3
  31. data/app/assets/stylesheets/puffer/codemirror/night.css +4 -4
  32. data/app/assets/stylesheets/puffer/codemirror/rubyblue.css +5 -5
  33. data/app/assets/stylesheets/puffer/codemirror/solarized.css +207 -0
  34. data/app/assets/stylesheets/puffer/codemirror/twilight.css +26 -0
  35. data/app/assets/stylesheets/puffer/codemirror/vibrant-ink.css +27 -0
  36. data/app/assets/stylesheets/puffer/codemirror/xq-dark.css +46 -0
  37. data/app/assets/stylesheets/puffer/puffer_pages.css +64 -35
  38. data/app/components/codemirror/form.html.erb +22 -6
  39. data/app/components/codemirror_component.rb +1 -8
  40. data/app/components/handlers/form.html.erb +8 -0
  41. data/app/components/handlers_component.rb +8 -0
  42. data/app/components/page_parts/_page_part.html.erb +6 -0
  43. data/app/components/page_parts/form.html.erb +8 -27
  44. data/app/components/page_parts_component.rb +1 -3
  45. data/app/components/render/_tree_page.html.erb +3 -2
  46. data/app/controllers/admin/layouts_controller.rb +1 -1
  47. data/app/controllers/admin/origins_controller.rb +3 -0
  48. data/app/controllers/admin/pages_controller.rb +1 -1
  49. data/app/controllers/admin/snippets_controller.rb +1 -1
  50. data/app/controllers/pages_controller.rb +3 -3
  51. data/app/helpers/puffer_pages_helper.rb +3 -3
  52. data/app/models/puffer_pages/layout.rb +2 -7
  53. data/app/models/puffer_pages/origin.rb +2 -0
  54. data/app/models/puffer_pages/page.rb +1 -117
  55. data/app/models/puffer_pages/page_part.rb +2 -22
  56. data/app/models/puffer_pages/snippet.rb +2 -5
  57. data/config/routes.rb +3 -0
  58. data/db/migrate/20120812100913_create_origins.rb +16 -0
  59. data/db/migrate/20120924120226_migrate_to_uuid.rb +126 -0
  60. data/db/migrate/20130110144030_add_handler_to_page_parts.rb +9 -0
  61. data/db/migrate/20130118064524_add_locales_to_pages.rb +9 -0
  62. data/gemfiles/Gemfile.rails-3-1 +7 -0
  63. data/gemfiles/Gemfile.rails-3-2 +7 -0
  64. data/gemfiles/Gemfile.rails-head +7 -0
  65. data/lib/puffer_pages.rb +43 -7
  66. data/lib/puffer_pages/backends.rb +16 -0
  67. data/{app/controllers/puffer_pages → lib/puffer_pages/backends/controllers}/layouts_base.rb +2 -5
  68. data/lib/puffer_pages/backends/controllers/origins_base.rb +43 -0
  69. data/lib/puffer_pages/backends/controllers/pages_base.rb +52 -0
  70. data/{app/controllers/puffer_pages → lib/puffer_pages/backends/controllers}/snippets_base.rb +2 -5
  71. data/lib/puffer_pages/backends/models/layout.rb +34 -0
  72. data/lib/puffer_pages/backends/models/mixins/importable.rb +42 -0
  73. data/lib/puffer_pages/backends/models/mixins/localable.rb +65 -0
  74. data/lib/puffer_pages/backends/models/mixins/renderable.rb +153 -0
  75. data/lib/puffer_pages/backends/models/mixins/translatable.rb +52 -0
  76. data/lib/puffer_pages/backends/models/origin.rb +59 -0
  77. data/lib/puffer_pages/backends/models/page.rb +221 -0
  78. data/lib/puffer_pages/backends/models/page_part.rb +71 -0
  79. data/lib/puffer_pages/backends/models/snippet.rb +34 -0
  80. data/lib/puffer_pages/engine.rb +13 -2
  81. data/lib/puffer_pages/extensions/context.rb +31 -0
  82. data/lib/puffer_pages/extensions/core.rb +1 -8
  83. data/lib/puffer_pages/extensions/pagenator.rb +69 -0
  84. data/lib/puffer_pages/extensions/renderer.rb +31 -0
  85. data/lib/puffer_pages/globalize/migrator.rb +23 -0
  86. data/lib/puffer_pages/handlers.rb +29 -0
  87. data/lib/puffer_pages/handlers/base.rb +21 -0
  88. data/lib/puffer_pages/handlers/yaml.rb +20 -0
  89. data/lib/puffer_pages/helpers.rb +14 -0
  90. data/lib/puffer_pages/liquid/backend.rb +16 -0
  91. data/lib/puffer_pages/liquid/file_system.rb +36 -12
  92. data/lib/puffer_pages/liquid/page_drop.rb +26 -23
  93. data/lib/puffer_pages/liquid/tags/array.rb +39 -0
  94. data/lib/puffer_pages/liquid/tags/{javascripts.rb → assets.rb} +13 -4
  95. data/lib/puffer_pages/liquid/tags/helper.rb +15 -0
  96. data/lib/puffer_pages/liquid/tags/include.rb +32 -0
  97. data/lib/puffer_pages/liquid/tags/javascript.rb +15 -0
  98. data/lib/puffer_pages/liquid/tags/partials.rb +22 -0
  99. data/lib/puffer_pages/liquid/tags/render.rb +28 -0
  100. data/lib/puffer_pages/liquid/tags/scope.rb +31 -0
  101. data/lib/puffer_pages/liquid/tags/super.rb +36 -0
  102. data/lib/puffer_pages/liquid/tags/translate.rb +56 -0
  103. data/lib/puffer_pages/liquid/tags/url.rb +53 -0
  104. data/lib/puffer_pages/liquid/tags/yield.rb +3 -1
  105. data/lib/puffer_pages/log_subscriber.rb +29 -0
  106. data/lib/puffer_pages/migrations.rb +31 -0
  107. data/lib/puffer_pages/renderer.rb +25 -0
  108. data/lib/puffer_pages/rspec/matchers.rb +27 -0
  109. data/lib/puffer_pages/rspec/matchers/render_page.rb +90 -0
  110. data/lib/puffer_pages/version.rb +1 -1
  111. data/puffer_pages.gemspec +18 -18
  112. data/spec/controllers/pages_controller_spec.rb +44 -0
  113. data/spec/controllers/puffer_pages_controller_spec.rb +194 -0
  114. data/spec/data/broken.json +8 -0
  115. data/spec/data/import.json +55 -0
  116. data/spec/data/localized.json +106 -0
  117. data/spec/data/unlocalized.json +82 -0
  118. data/spec/dummy/.rvmrc +1 -0
  119. data/spec/dummy/app/controllers/application_controller.rb +6 -0
  120. data/spec/dummy/app/views/layouts/sample.en.erb +1 -0
  121. data/spec/dummy/app/views/layouts/sample.ru.erb +1 -0
  122. data/spec/dummy/app/views/shared/_first.html.erb +1 -0
  123. data/spec/dummy/config/application.rb +21 -2
  124. data/spec/dummy/config/boot.rb +0 -2
  125. data/spec/dummy/config/database.yml +7 -1
  126. data/spec/dummy/config/environments/development.rb +11 -2
  127. data/spec/dummy/config/environments/pg_test.rb +6 -6
  128. data/spec/dummy/config/environments/production.rb +19 -3
  129. data/spec/dummy/config/environments/test.rb +6 -6
  130. data/spec/dummy/config/initializers/inflections.rb +5 -0
  131. data/spec/dummy/config/initializers/puffer_pages.rb +4 -0
  132. data/spec/dummy/config/initializers/secret_token.rb +1 -1
  133. data/spec/dummy/config/initializers/wrap_parameters.rb +5 -3
  134. data/spec/dummy/config/routes.rb +2 -1
  135. data/spec/dummy/db/migrate/{20090422092419_create_pages.rb → 20130118071511_create_pages.rb} +1 -0
  136. data/spec/dummy/db/migrate/{20090504132337_create_page_parts.rb → 20130118071512_create_page_parts.rb} +1 -0
  137. data/spec/dummy/db/migrate/{20090506102004_create_layouts.rb → 20130118071513_create_layouts.rb} +1 -0
  138. data/spec/dummy/db/migrate/{20090510121824_create_snippets.rb → 20130118071514_create_snippets.rb} +1 -0
  139. data/spec/dummy/db/migrate/20130118071515_create_origins.rb +17 -0
  140. data/spec/dummy/db/migrate/20130118071516_migrate_to_uuid.rb +127 -0
  141. data/spec/dummy/db/migrate/20130118071517_add_handler_to_page_parts.rb +10 -0
  142. data/spec/dummy/db/migrate/20130118071518_add_locales_to_pages.rb +10 -0
  143. data/spec/dummy/db/migrate/20130118071519_add_translations.rb +9 -0
  144. data/spec/dummy/db/schema.rb +65 -17
  145. data/spec/fabricators/articles_fabricator.rb +2 -2
  146. data/spec/fabricators/layouts_fabricator.rb +24 -3
  147. data/spec/fabricators/origin_fabricator.rb +5 -0
  148. data/spec/fabricators/page_parts_fabricator.rb +17 -2
  149. data/spec/fabricators/pages_fabricator.rb +20 -5
  150. data/spec/fabricators/snippets_fabricator.rb +14 -3
  151. data/spec/lib/handlers/base_spec.rb +10 -0
  152. data/spec/lib/handlers/yaml_spec.rb +34 -0
  153. data/spec/lib/handlers_spec.rb +36 -0
  154. data/spec/lib/liquid/backend_spec.rb +20 -0
  155. data/spec/lib/liquid/interpolation_spec.rb +25 -0
  156. data/spec/lib/liquid/tags/include_spec.rb +38 -0
  157. data/spec/lib/liquid/tags/partials_spec.rb +39 -0
  158. data/spec/lib/liquid/tags/scope_spec.rb +18 -0
  159. data/spec/lib/liquid/tags/translate_spec.rb +107 -0
  160. data/spec/lib/liquid/tags_spec.rb +81 -0
  161. data/spec/lib/page_drop_spec.rb +65 -0
  162. data/spec/lib/pagenator_spec.rb +176 -0
  163. data/spec/lib/rspec/matchers/render_page_spec.rb +107 -0
  164. data/spec/models/puffer_pages/layout_spec.rb +15 -0
  165. data/spec/models/puffer_pages/localable_spec.rb +62 -0
  166. data/spec/models/puffer_pages/origin_spec.rb +112 -0
  167. data/spec/models/puffer_pages/page_part_spec.rb +14 -0
  168. data/spec/models/puffer_pages/page_spec.rb +307 -0
  169. data/spec/models/puffer_pages/renderable_spec.rb +84 -0
  170. data/spec/models/puffer_pages/snippet_spec.rb +15 -0
  171. data/spec/requests/origins_requests_spec.rb +37 -0
  172. data/spec/spec_helper.rb +7 -6
  173. metadata +349 -87
  174. data/Gemfile.lock +0 -176
  175. data/app/assets/javascripts/puffer/overlay.js +0 -51
  176. data/app/controllers/puffer_pages/pages_base.rb +0 -38
  177. data/app/models/layout.rb +0 -2
  178. data/app/models/page.rb +0 -2
  179. data/app/models/page_part.rb +0 -2
  180. data/app/models/snippet.rb +0 -2
  181. data/app/views/layouts/puffer_pages_layout.html.erb +0 -2
  182. data/config/puffer_routes.rb +0 -3
  183. data/gemfiles/Gemfile-rails-3.1 +0 -5
  184. data/gemfiles/Gemfile-rails-3.1.lock +0 -173
  185. data/gemfiles/Gemfile-rails-3.2 +0 -5
  186. data/gemfiles/Gemfile-rails-3.2.lock +0 -171
  187. data/lib/puffer_pages/extensions/controller.rb +0 -30
  188. data/lib/puffer_pages/extensions/mapper.rb +0 -23
  189. data/lib/puffer_pages/liquid/tags/page_attribute.rb +0 -39
  190. data/lib/puffer_pages/liquid/tags/stylesheets.rb +0 -38
  191. data/spec/controllers/articles_controller_spec.rb +0 -65
  192. data/spec/dummy/app/controllers/articles_controller.rb +0 -9
  193. data/spec/integration/navigation_spec.rb +0 -9
  194. data/spec/lib/drops_spec.rb +0 -55
  195. data/spec/lib/tags_spec.rb +0 -98
  196. data/spec/models/page_spec.rb +0 -235
  197. data/spec/puffer_pages_spec.rb +0 -7
@@ -1,6 +1,9 @@
1
+ // TODO actually recognize syntax of TypeScript constructs
2
+
1
3
  CodeMirror.defineMode("javascript", function(config, parserConfig) {
2
4
  var indentUnit = config.indentUnit;
3
5
  var jsonMode = parserConfig.json;
6
+ var isTS = parserConfig.typescript;
4
7
 
5
8
  // Tokenizer
6
9
 
@@ -8,7 +11,8 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
8
11
  function kw(type) {return {type: type, style: "keyword"};}
9
12
  var A = kw("keyword a"), B = kw("keyword b"), C = kw("keyword c");
10
13
  var operator = kw("operator"), atom = {type: "atom", style: "atom"};
11
- return {
14
+
15
+ var jsKeywords = {
12
16
  "if": A, "while": A, "with": A, "else": B, "do": B, "try": B, "finally": B,
13
17
  "return": C, "break": C, "continue": C, "new": C, "delete": C, "throw": C,
14
18
  "var": kw("var"), "const": kw("var"), "let": kw("var"),
@@ -17,6 +21,35 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
17
21
  "in": operator, "typeof": operator, "instanceof": operator,
18
22
  "true": atom, "false": atom, "null": atom, "undefined": atom, "NaN": atom, "Infinity": atom
19
23
  };
24
+
25
+ // Extend the 'normal' keywords with the TypeScript language extensions
26
+ if (isTS) {
27
+ var type = {type: "variable", style: "variable-3"};
28
+ var tsKeywords = {
29
+ // object-like things
30
+ "interface": kw("interface"),
31
+ "class": kw("class"),
32
+ "extends": kw("extends"),
33
+ "constructor": kw("constructor"),
34
+
35
+ // scope modifiers
36
+ "public": kw("public"),
37
+ "private": kw("private"),
38
+ "protected": kw("protected"),
39
+ "static": kw("static"),
40
+
41
+ "super": kw("super"),
42
+
43
+ // types
44
+ "string": type, "number": type, "bool": type, "any": type
45
+ };
46
+
47
+ for (var attr in tsKeywords) {
48
+ jsKeywords[attr] = tsKeywords[attr];
49
+ }
50
+ }
51
+
52
+ return jsKeywords;
20
53
  }();
21
54
 
22
55
  var isOperatorChar = /[+\-*&%=<>!?|]/;
@@ -54,7 +87,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
54
87
  stream.eatWhile(/[\da-f]/i);
55
88
  return ret("number", "number");
56
89
  }
57
- else if (/\d/.test(ch)) {
90
+ else if (/\d/.test(ch) || ch == "-" && stream.eat(/\d/)) {
58
91
  stream.match(/^\d*(?:\.\d*)?(?:[eE][+\-]?\d+)?/);
59
92
  return ret("number", "number");
60
93
  }
@@ -66,10 +99,11 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
66
99
  stream.skipToEnd();
67
100
  return ret("comment", "comment");
68
101
  }
69
- else if (state.reAllowed) {
102
+ else if (state.lastType == "operator" || state.lastType == "keyword c" ||
103
+ /^[\[{}\(,;:]$/.test(state.lastType)) {
70
104
  nextUntilUnescaped(stream, "/");
71
105
  stream.eatWhile(/[gimy]/); // 'y' is "sticky" option in Mozilla
72
- return ret("regexp", "string");
106
+ return ret("regexp", "string-2");
73
107
  }
74
108
  else {
75
109
  stream.eatWhile(isOperatorChar);
@@ -87,7 +121,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
87
121
  else {
88
122
  stream.eatWhile(/[\w\$_]/);
89
123
  var word = stream.current(), known = keywords.propertyIsEnumerable(word) && keywords[word];
90
- return (known && state.kwAllowed) ? ret(known.type, known.style, word) :
124
+ return (known && state.lastType != ".") ? ret(known.type, known.style, word) :
91
125
  ret("variable", "variable", word);
92
126
  }
93
127
  }
@@ -162,12 +196,19 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
162
196
  return true;
163
197
  }
164
198
  function register(varname) {
199
+ function inList(list) {
200
+ for (var v = list; v; v = v.next)
201
+ if (v.name == varname) return true;
202
+ return false;
203
+ }
165
204
  var state = cx.state;
166
205
  if (state.context) {
167
206
  cx.marked = "def";
168
- for (var v = state.localVars; v; v = v.next)
169
- if (v.name == varname) return;
207
+ if (inList(state.localVars)) return;
170
208
  state.localVars = {name: varname, next: state.localVars};
209
+ } else {
210
+ if (inList(state.globalVars)) return;
211
+ state.globalVars = {name: varname, next: state.globalVars};
171
212
  }
172
213
  }
173
214
 
@@ -175,8 +216,8 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
175
216
 
176
217
  var defaultVars = {name: "this", next: {name: "arguments"}};
177
218
  function pushcontext() {
178
- if (!cx.state.context) cx.state.localVars = defaultVars;
179
219
  cx.state.context = {prev: cx.state.context, vars: cx.state.localVars};
220
+ cx.state.localVars = defaultVars;
180
221
  }
181
222
  function popcontext() {
182
223
  cx.state.localVars = cx.state.context.vars;
@@ -185,7 +226,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
185
226
  function pushlex(type, info) {
186
227
  var result = function() {
187
228
  var state = cx.state;
188
- state.lexical = new JSLexical(state.indented, cx.stream.column(), type, null, state.lexical, info)
229
+ state.lexical = new JSLexical(state.indented, cx.stream.column(), type, null, state.lexical, info);
189
230
  };
190
231
  result.lex = true;
191
232
  return result;
@@ -230,7 +271,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
230
271
  if (atomicTypes.hasOwnProperty(type)) return cont(maybeoperator);
231
272
  if (type == "function") return cont(functiondef);
232
273
  if (type == "keyword c") return cont(maybeexpression);
233
- if (type == "(") return cont(pushlex(")"), expression, expect(")"), poplex, maybeoperator);
274
+ if (type == "(") return cont(pushlex(")"), maybeexpression, expect(")"), poplex, maybeoperator);
234
275
  if (type == "operator") return cont(expression);
235
276
  if (type == "[") return cont(pushlex("]"), commasep(expression, "]"), poplex, maybeoperator);
236
277
  if (type == "{") return cont(pushlex("}"), commasep(objprop, "}"), poplex, maybeoperator);
@@ -243,7 +284,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
243
284
 
244
285
  function maybeoperator(type, value) {
245
286
  if (type == "operator" && /\+\+|--/.test(value)) return cont(maybeoperator);
246
- if (type == "operator") return cont(expression);
287
+ if (type == "operator" && value == "?") return cont(expression, expect(":"), expression);
247
288
  if (type == ";") return;
248
289
  if (type == "(") return cont(pushlex(")"), commasep(expression, ")"), poplex, maybeoperator);
249
290
  if (type == ".") return cont(property, maybeoperator);
@@ -275,21 +316,32 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
275
316
  if (type == "}") return cont();
276
317
  return pass(statement, block);
277
318
  }
319
+ function maybetype(type) {
320
+ if (type == ":") return cont(typedef);
321
+ return pass();
322
+ }
323
+ function typedef(type) {
324
+ if (type == "variable"){cx.marked = "variable-3"; return cont();}
325
+ return pass();
326
+ }
278
327
  function vardef1(type, value) {
279
- if (type == "variable"){register(value); return cont(vardef2);}
280
- return cont();
328
+ if (type == "variable") {
329
+ register(value);
330
+ return isTS ? cont(maybetype, vardef2) : cont(vardef2);
331
+ }
332
+ return pass();
281
333
  }
282
334
  function vardef2(type, value) {
283
335
  if (value == "=") return cont(expression, vardef2);
284
336
  if (type == ",") return cont(vardef1);
285
337
  }
286
338
  function forspec1(type) {
287
- if (type == "var") return cont(vardef1, forspec2);
288
- if (type == ";") return pass(forspec2);
339
+ if (type == "var") return cont(vardef1, expect(";"), forspec2);
340
+ if (type == ";") return cont(forspec2);
289
341
  if (type == "variable") return cont(formaybein);
290
- return pass(forspec2);
342
+ return cont(forspec2);
291
343
  }
292
- function formaybein(type, value) {
344
+ function formaybein(_type, value) {
293
345
  if (value == "in") return cont(expression);
294
346
  return cont(maybeoperator, forspec2);
295
347
  }
@@ -306,7 +358,7 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
306
358
  if (type == "(") return cont(pushlex(")"), pushcontext, commasep(funarg, ")"), poplex, statement, popcontext);
307
359
  }
308
360
  function funarg(type, value) {
309
- if (type == "variable") {register(value); return cont();}
361
+ if (type == "variable") {register(value); return isTS ? cont(maybetype) : cont();}
310
362
  }
311
363
 
312
364
  // Interface
@@ -315,12 +367,12 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
315
367
  startState: function(basecolumn) {
316
368
  return {
317
369
  tokenize: jsTokenBase,
318
- reAllowed: true,
319
- kwAllowed: true,
370
+ lastType: null,
320
371
  cc: [],
321
372
  lexical: new JSLexical((basecolumn || 0) - indentUnit, 0, "block", false),
322
- localVars: null,
323
- context: null,
373
+ localVars: parserConfig.localVars,
374
+ globalVars: parserConfig.globalVars,
375
+ context: parserConfig.localVars && {vars: parserConfig.localVars},
324
376
  indented: 0
325
377
  };
326
378
  },
@@ -334,27 +386,37 @@ CodeMirror.defineMode("javascript", function(config, parserConfig) {
334
386
  if (stream.eatSpace()) return null;
335
387
  var style = state.tokenize(stream, state);
336
388
  if (type == "comment") return style;
337
- state.reAllowed = type == "operator" || type == "keyword c" || type.match(/^[\[{}\(,;:]$/);
338
- state.kwAllowed = type != '.';
389
+ state.lastType = type;
339
390
  return parseJS(state, style, type, content, stream);
340
391
  },
341
392
 
342
393
  indent: function(state, textAfter) {
394
+ if (state.tokenize == jsTokenComment) return CodeMirror.Pass;
343
395
  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;
396
+ var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical;
397
+ if (lexical.type == "stat" && firstChar == "}") lexical = lexical.prev;
398
+ var type = lexical.type, closing = firstChar == type;
399
+ if (type == "vardef") return lexical.indented + (state.lastType == "operator" || state.lastType == "," ? 4 : 0);
347
400
  else if (type == "form" && firstChar == "{") return lexical.indented;
348
- else if (type == "stat" || type == "form") return lexical.indented + indentUnit;
401
+ else if (type == "form") return lexical.indented + indentUnit;
402
+ else if (type == "stat")
403
+ return lexical.indented + (state.lastType == "operator" || state.lastType == "," ? indentUnit : 0);
349
404
  else if (lexical.info == "switch" && !closing)
350
405
  return lexical.indented + (/^(?:case|default)\b/.test(textAfter) ? indentUnit : 2 * indentUnit);
351
406
  else if (lexical.align) return lexical.column + (closing ? 0 : 1);
352
407
  else return lexical.indented + (closing ? 0 : indentUnit);
353
408
  },
354
409
 
355
- electricChars: ":{}"
410
+ electricChars: ":{}",
411
+
412
+ jsonMode: jsonMode
356
413
  };
357
414
  });
358
415
 
359
416
  CodeMirror.defineMIME("text/javascript", "javascript");
417
+ CodeMirror.defineMIME("text/ecmascript", "javascript");
418
+ CodeMirror.defineMIME("application/javascript", "javascript");
419
+ CodeMirror.defineMIME("application/ecmascript", "javascript");
360
420
  CodeMirror.defineMIME("application/json", {name: "javascript", json: true});
421
+ CodeMirror.defineMIME("text/typescript", { name: "javascript", typescript: true });
422
+ CodeMirror.defineMIME("application/typescript", { name: "javascript", typescript: true });
@@ -0,0 +1,185 @@
1
+ (function(CodeMirror) {
2
+ inString = function(stream, state) {
3
+ var matched = stream.next();
4
+
5
+ while (stream.peek()) {
6
+ if (stream.match('}}') || stream.match('%}')) {
7
+ stream.backUp(2);
8
+ break;
9
+ } else if (stream.next() == matched) {
10
+ break;
11
+ }
12
+ }
13
+
14
+ return 'string';
15
+ }
16
+
17
+ CodeMirror.defineMode("liquid", function(config, parserConfig) {
18
+ var tagMode = CodeMirror.getMode(config, "liquid-tag");
19
+ var tagState = null;
20
+ var variableMode = CodeMirror.getMode(config, "liquid-variable");
21
+ var variableState = null;
22
+
23
+
24
+ var tokenize = function(stream, state) {
25
+ var token = null;
26
+
27
+ if (stream.match(/^\{\%\s*comment\s*\%\}/)) {
28
+ state.tokenizer = inComment;
29
+ token = "comment";
30
+ } else if (stream.match('{{')) {
31
+ variableState = variableMode.startState();
32
+ state.tokenizer = inVariable;
33
+ token = 'tag';
34
+ } else if (stream.match('{%')) {
35
+ tagState = tagMode.startState();
36
+ state.tokenizer = inTag;
37
+ token = 'tag';
38
+ } else {
39
+ stream.next();
40
+ }
41
+
42
+ return token;
43
+ }
44
+
45
+ var inComment = function(stream, state) {
46
+ if (stream.match(/^\{\%\s*endcomment\s*\%\}/)) {
47
+ state.tokenizer = tokenize;
48
+ } else {
49
+ stream.next();
50
+ }
51
+ return 'comment';
52
+ }
53
+
54
+ var inVariable = function(stream, state) {
55
+ var token = null;
56
+
57
+ if (stream.match('}}')) {
58
+ state.tokenizer = tokenize;
59
+ token = 'tag';
60
+ } else {
61
+ token = variableMode.token(stream, variableState);
62
+ }
63
+
64
+ return token;
65
+ }
66
+
67
+ var inTag = function(stream, state) {
68
+ var token = null;
69
+
70
+ if (stream.match('%}')) {
71
+ state.tokenizer = tokenize;
72
+ token = 'tag';
73
+ } else {
74
+ token = tagMode.token(stream, tagState);
75
+ }
76
+
77
+ return token;
78
+ }
79
+
80
+ return {
81
+ startState: function() {
82
+ return {tokenizer: tokenize, mode: null};
83
+ },
84
+ token: function(stream, state) {
85
+ return state.tokenizer(stream, state);
86
+ },
87
+ electricChars: ""
88
+ }
89
+ });
90
+
91
+ CodeMirror.defineMode("liquid-variable", function(config, parserConfig) {
92
+ var tokenize = function(stream, state) {
93
+ var token = null;
94
+
95
+ if (stream.peek() == '\'' || stream.peek() == '"') {
96
+ token = inString(stream, state);
97
+ state.filterParsing = false;
98
+ } else if (stream.match(/^-?\d+(:?\.(\d+))?/)) {
99
+ token = 'number';
100
+ state.filterParsing = false;
101
+ } else if (stream.peek() == '|') {
102
+ stream.next();
103
+ state.filterParsing = true;
104
+ } else if (stream.match(/^\w+/)) {
105
+ if (state.filterParsing) {
106
+ token = 'attribute';
107
+ state.filterParsing = false;
108
+ } else {
109
+ token = 'variable';
110
+ }
111
+ } else {
112
+ stream.next();
113
+ }
114
+
115
+ return token;
116
+ }
117
+
118
+ return {
119
+ startState: function() {
120
+ return {tokenizer: tokenize, filterParsing: false};
121
+ },
122
+ token: function(stream, state) {
123
+ return state.tokenizer(stream, state);
124
+ },
125
+ electricChars: ""
126
+ }
127
+ });
128
+
129
+ CodeMirror.defineMode("liquid-tag", function(config, parserConfig) {
130
+ var tokenize = function(stream, state) {
131
+ var token = null;
132
+
133
+ if (stream.peek() == '\'' || stream.peek() == '"') {
134
+ token = inString(stream, state);
135
+ if (state.translationTagParsed && !state.translationStringParsed) {
136
+ token = 'translation';
137
+ }
138
+ state.translationStringParsed = true;
139
+ } else if (stream.match(/^-?\d+(:?\.(\d+))?/)) {
140
+ token = 'number';
141
+ state.translationStringParsed = true;
142
+ } else if (stream.match(/^(nil|null|true|false|empty|blank)\s/)) {
143
+ token = 'builtin';
144
+ stream.backUp(1);
145
+ state.translationStringParsed = true;
146
+ } else if (stream.match(/^(==|!=|<>|>|<|>=|<=)/)) {
147
+ token = 'operator';
148
+ state.translationStringParsed = true;
149
+ } else if (stream.match(/^(in|contains)\s/)) {
150
+ token = 'operator';
151
+ stream.backUp(1);
152
+ state.translationStringParsed = true;
153
+ } else if (tag = stream.match(/^\w+/)) {
154
+ if (state.tagParsed) {
155
+ token = 'variable';
156
+ state.translationStringParsed = true;
157
+ } else {
158
+ token = 'keyword';
159
+ state.tagParsed = true;
160
+ if (tag == 't' || tag == 'translate') {
161
+ state.translationTagParsed = true;
162
+ }
163
+ }
164
+ } else {
165
+ stream.next();
166
+ }
167
+
168
+ return token;
169
+ }
170
+
171
+ return {
172
+ startState: function() {
173
+ return {tokenizer: tokenize, tagParsed: false, translationTagParsed: false, translationStringParsed: false};
174
+ },
175
+ token: function(stream, state) {
176
+ return state.tokenizer(stream, state);
177
+ },
178
+ electricChars: ""
179
+ }
180
+ });
181
+ })(CodeMirror)
182
+
183
+ CodeMirror.defineMIME("text/x-liquid", "liquid");
184
+ CodeMirror.defineMIME("text/x-liquid-tag", "liquid-tag");
185
+ CodeMirror.defineMIME("text/x-liquid-variable", "liquid-variable");
@@ -1,11 +1,44 @@
1
1
  CodeMirror.defineMode("xml", function(config, parserConfig) {
2
2
  var indentUnit = config.indentUnit;
3
3
  var Kludges = parserConfig.htmlMode ? {
4
- autoSelfClosers: {"br": true, "img": true, "hr": true, "link": true, "input": true,
5
- "meta": true, "col": true, "frame": true, "base": true, "area": true},
4
+ autoSelfClosers: {'area': true, 'base': true, 'br': true, 'col': true, 'command': true,
5
+ 'embed': true, 'frame': true, 'hr': true, 'img': true, 'input': true,
6
+ 'keygen': true, 'link': true, 'meta': true, 'param': true, 'source': true,
7
+ 'track': true, 'wbr': true},
8
+ implicitlyClosed: {'dd': true, 'li': true, 'optgroup': true, 'option': true, 'p': true,
9
+ 'rp': true, 'rt': true, 'tbody': true, 'td': true, 'tfoot': true,
10
+ 'th': true, 'tr': true},
11
+ contextGrabbers: {
12
+ 'dd': {'dd': true, 'dt': true},
13
+ 'dt': {'dd': true, 'dt': true},
14
+ 'li': {'li': true},
15
+ 'option': {'option': true, 'optgroup': true},
16
+ 'optgroup': {'optgroup': true},
17
+ 'p': {'address': true, 'article': true, 'aside': true, 'blockquote': true, 'dir': true,
18
+ 'div': true, 'dl': true, 'fieldset': true, 'footer': true, 'form': true,
19
+ 'h1': true, 'h2': true, 'h3': true, 'h4': true, 'h5': true, 'h6': true,
20
+ 'header': true, 'hgroup': true, 'hr': true, 'menu': true, 'nav': true, 'ol': true,
21
+ 'p': true, 'pre': true, 'section': true, 'table': true, 'ul': true},
22
+ 'rp': {'rp': true, 'rt': true},
23
+ 'rt': {'rp': true, 'rt': true},
24
+ 'tbody': {'tbody': true, 'tfoot': true},
25
+ 'td': {'td': true, 'th': true},
26
+ 'tfoot': {'tbody': true},
27
+ 'th': {'td': true, 'th': true},
28
+ 'thead': {'tbody': true, 'tfoot': true},
29
+ 'tr': {'tr': true}
30
+ },
6
31
  doNotIndent: {"pre": true},
7
- allowUnquoted: true
8
- } : {autoSelfClosers: {}, doNotIndent: {}, allowUnquoted: false};
32
+ allowUnquoted: true,
33
+ allowMissing: true
34
+ } : {
35
+ autoSelfClosers: {},
36
+ implicitlyClosed: {},
37
+ contextGrabbers: {},
38
+ doNotIndent: {},
39
+ allowUnquoted: false,
40
+ allowMissing: false
41
+ };
9
42
  var alignCDATA = parserConfig.alignCDATA;
10
43
 
11
44
  // Return variables for tokenizers
@@ -37,19 +70,28 @@ CodeMirror.defineMode("xml", function(config, parserConfig) {
37
70
  return "meta";
38
71
  }
39
72
  else {
40
- type = stream.eat("/") ? "closeTag" : "openTag";
41
- stream.eatSpace();
73
+ var isClose = stream.eat("/");
42
74
  tagName = "";
43
75
  var c;
44
76
  while ((c = stream.eat(/[^\s\u00a0=<>\"\'\/?]/))) tagName += c;
77
+ if (!tagName) return "error";
78
+ type = isClose ? "closeTag" : "openTag";
45
79
  state.tokenize = inTag;
46
80
  return "tag";
47
81
  }
48
82
  }
49
83
  else if (ch == "&") {
50
- stream.eatWhile(/[^;]/);
51
- stream.eat(";");
52
- return "atom";
84
+ var ok;
85
+ if (stream.eat("#")) {
86
+ if (stream.eat("x")) {
87
+ ok = stream.eatWhile(/[a-fA-F\d]/) && stream.eat(";");
88
+ } else {
89
+ ok = stream.eatWhile(/[\d]/) && stream.eat(";");
90
+ }
91
+ } else {
92
+ ok = stream.eatWhile(/[\w\.\-:]/) && stream.eat(";");
93
+ }
94
+ return ok ? "atom" : "error";
53
95
  }
54
96
  else {
55
97
  stream.eatWhile(/[^&<]/);
@@ -73,7 +115,7 @@ CodeMirror.defineMode("xml", function(config, parserConfig) {
73
115
  return state.tokenize(stream, state);
74
116
  }
75
117
  else {
76
- stream.eatWhile(/[^\s\u00a0=<>\"\'\/?]/);
118
+ stream.eatWhile(/[^\s\u00a0=<>\"\']/);
77
119
  return "word";
78
120
  }
79
121
  }
@@ -153,7 +195,12 @@ CodeMirror.defineMode("xml", function(config, parserConfig) {
153
195
  } else if (type == "closeTag") {
154
196
  var err = false;
155
197
  if (curState.context) {
156
- err = curState.context.tagName != tagName;
198
+ if (curState.context.tagName != tagName) {
199
+ if (Kludges.implicitlyClosed.hasOwnProperty(curState.context.tagName.toLowerCase())) {
200
+ popContext();
201
+ }
202
+ err = !curState.context || curState.context.tagName != tagName;
203
+ }
157
204
  } else {
158
205
  err = true;
159
206
  }
@@ -164,10 +211,18 @@ CodeMirror.defineMode("xml", function(config, parserConfig) {
164
211
  }
165
212
  function endtag(startOfLine) {
166
213
  return function(type) {
214
+ var tagName = curState.tagName;
215
+ curState.tagName = null;
167
216
  if (type == "selfcloseTag" ||
168
- (type == "endTag" && Kludges.autoSelfClosers.hasOwnProperty(curState.tagName.toLowerCase())))
217
+ (type == "endTag" && Kludges.autoSelfClosers.hasOwnProperty(tagName.toLowerCase()))) {
218
+ maybePopContext(tagName.toLowerCase());
169
219
  return cont();
170
- if (type == "endTag") {pushContext(curState.tagName, startOfLine); return cont();}
220
+ }
221
+ if (type == "endTag") {
222
+ maybePopContext(tagName.toLowerCase());
223
+ pushContext(tagName, startOfLine);
224
+ return cont();
225
+ }
171
226
  return cont();
172
227
  };
173
228
  }
@@ -177,19 +232,40 @@ CodeMirror.defineMode("xml", function(config, parserConfig) {
177
232
  if (type == "endTag") { popContext(); return cont(); }
178
233
  setStyle = "error";
179
234
  return cont(arguments.callee);
235
+ };
236
+ }
237
+ function maybePopContext(nextTagName) {
238
+ var parentTagName;
239
+ while (true) {
240
+ if (!curState.context) {
241
+ return;
242
+ }
243
+ parentTagName = curState.context.tagName.toLowerCase();
244
+ if (!Kludges.contextGrabbers.hasOwnProperty(parentTagName) ||
245
+ !Kludges.contextGrabbers[parentTagName].hasOwnProperty(nextTagName)) {
246
+ return;
247
+ }
248
+ popContext();
180
249
  }
181
250
  }
182
251
 
183
252
  function attributes(type) {
184
- if (type == "word") {setStyle = "attribute"; return cont(attributes);}
253
+ if (type == "word") {setStyle = "attribute"; return cont(attribute, attributes);}
254
+ if (type == "endTag" || type == "selfcloseTag") return pass();
255
+ setStyle = "error";
256
+ return cont(attributes);
257
+ }
258
+ function attribute(type) {
185
259
  if (type == "equals") return cont(attvalue, attributes);
186
- if (type == "string") {setStyle = "error"; return cont(attributes);}
187
- return pass();
260
+ if (!Kludges.allowMissing) setStyle = "error";
261
+ else if (type == "word") setStyle = "attribute";
262
+ return (type == "endTag" || type == "selfcloseTag") ? pass() : cont();
188
263
  }
189
264
  function attvalue(type) {
190
- if (type == "word" && Kludges.allowUnquoted) {setStyle = "string"; return cont();}
191
265
  if (type == "string") return cont(attvaluemaybe);
192
- return pass();
266
+ if (type == "word" && Kludges.allowUnquoted) {setStyle = "string"; return cont();}
267
+ setStyle = "error";
268
+ return (type == "endTag" || type == "selfCloseTag") ? pass() : cont();
193
269
  }
194
270
  function attvaluemaybe(type) {
195
271
  if (type == "string") return cont(attvaluemaybe);
@@ -236,17 +312,13 @@ CodeMirror.defineMode("xml", function(config, parserConfig) {
236
312
  else return 0;
237
313
  },
238
314
 
239
- compareStates: function(a, b) {
240
- if (a.indented != b.indented || a.tokenize != b.tokenize) return false;
241
- for (var ca = a.context, cb = b.context; ; ca = ca.prev, cb = cb.prev) {
242
- if (!ca || !cb) return ca == cb;
243
- if (ca.tagName != cb.tagName) return false;
244
- }
245
- },
315
+ electricChars: "/",
246
316
 
247
- electricChars: "/"
317
+ configuration: parserConfig.htmlMode ? "html" : "xml"
248
318
  };
249
319
  });
250
320
 
321
+ CodeMirror.defineMIME("text/xml", "xml");
251
322
  CodeMirror.defineMIME("application/xml", "xml");
252
- CodeMirror.defineMIME("text/html", {name: "xml", htmlMode: true});
323
+ if (!CodeMirror.mimeModes.hasOwnProperty("text/html"))
324
+ CodeMirror.defineMIME("text/html", {name: "xml", htmlMode: true});