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
@@ -0,0 +1,95 @@
1
+ CodeMirror.defineMode("yaml", function() {
2
+
3
+ var cons = ['true', 'false', 'on', 'off', 'yes', 'no'];
4
+ var keywordRegex = new RegExp("\\b(("+cons.join(")|(")+"))$", 'i');
5
+
6
+ return {
7
+ token: function(stream, state) {
8
+ var ch = stream.peek();
9
+ var esc = state.escaped;
10
+ state.escaped = false;
11
+ /* comments */
12
+ if (ch == "#") { stream.skipToEnd(); return "comment"; }
13
+ if (state.literal && stream.indentation() > state.keyCol) {
14
+ stream.skipToEnd(); return "string";
15
+ } else if (state.literal) { state.literal = false; }
16
+ if (stream.sol()) {
17
+ state.keyCol = 0;
18
+ state.pair = false;
19
+ state.pairStart = false;
20
+ /* document start */
21
+ if(stream.match(/---/)) { return "def"; }
22
+ /* document end */
23
+ if (stream.match(/\.\.\./)) { return "def"; }
24
+ /* array list item */
25
+ if (stream.match(/\s*-\s+/)) { return 'meta'; }
26
+ }
27
+ /* pairs (associative arrays) -> key */
28
+ if (!state.pair && stream.match(/^\s*([a-z0-9\._-])+(?=\s*:)/i)) {
29
+ state.pair = true;
30
+ state.keyCol = stream.indentation();
31
+ return "atom";
32
+ }
33
+ if (state.pair && stream.match(/^:\s*/)) { state.pairStart = true; return 'meta'; }
34
+
35
+ /* inline pairs/lists */
36
+ if (stream.match(/^(\{|\}|\[|\])/)) {
37
+ if (ch == '{')
38
+ state.inlinePairs++;
39
+ else if (ch == '}')
40
+ state.inlinePairs--;
41
+ else if (ch == '[')
42
+ state.inlineList++;
43
+ else
44
+ state.inlineList--;
45
+ return 'meta';
46
+ }
47
+
48
+ /* list seperator */
49
+ if (state.inlineList > 0 && !esc && ch == ',') {
50
+ stream.next();
51
+ return 'meta';
52
+ }
53
+ /* pairs seperator */
54
+ if (state.inlinePairs > 0 && !esc && ch == ',') {
55
+ state.keyCol = 0;
56
+ state.pair = false;
57
+ state.pairStart = false;
58
+ stream.next();
59
+ return 'meta';
60
+ }
61
+
62
+ /* start of value of a pair */
63
+ if (state.pairStart) {
64
+ /* block literals */
65
+ if (stream.match(/^\s*(\||\>)\s*/)) { state.literal = true; return 'meta'; };
66
+ /* references */
67
+ if (stream.match(/^\s*(\&|\*)[a-z0-9\._-]+\b/i)) { return 'variable-2'; }
68
+ /* numbers */
69
+ if (state.inlinePairs == 0 && stream.match(/^\s*-?[0-9\.\,]+\s?$/)) { return 'number'; }
70
+ if (state.inlinePairs > 0 && stream.match(/^\s*-?[0-9\.\,]+\s?(?=(,|}))/)) { return 'number'; }
71
+ /* keywords */
72
+ if (stream.match(keywordRegex)) { return 'keyword'; }
73
+ }
74
+
75
+ /* nothing found, continue */
76
+ state.pairStart = false;
77
+ state.escaped = (ch == '\\');
78
+ stream.next();
79
+ return null;
80
+ },
81
+ startState: function() {
82
+ return {
83
+ pair: false,
84
+ pairStart: false,
85
+ keyCol: 0,
86
+ inlinePairs: 0,
87
+ inlineList: 0,
88
+ literal: false,
89
+ escaped: false
90
+ };
91
+ }
92
+ };
93
+ });
94
+
95
+ CodeMirror.defineMIME("text/x-yaml", "yaml");
@@ -1,15 +1,31 @@
1
- CodeMirror.defineMode("liquid", function(config, parserConfig) {
2
- var liquidOverlay = {
3
- token: function(stream, state) {
4
- if (stream.match("{{") || stream.match("{%")) {
5
- while ((ch = stream.next()) != null)
6
- if ((ch == "}" || ch == "%") && stream.next() == "}") break;
7
- return "liquid";
8
- }
9
- while (stream.next() != null && !(stream.match("{{", false) || !stream.match("{%", false))) {}
10
- return null;
1
+ CodeMirror.defineMode("text/x-liquid-html", function(config) {
2
+ return CodeMirror.multiplexingMode(
3
+ CodeMirror.getMode(config, "text/html"),
4
+ {
5
+ open: "{{", close: "}}",
6
+ mode: CodeMirror.getMode(config, "text/x-liquid-variable"),
7
+ delimStyle: "tag"
8
+ },
9
+ {
10
+ open: "{%", close: "%}",
11
+ mode: CodeMirror.getMode(config, "text/x-liquid-tag"),
12
+ delimStyle: "tag"
11
13
  }
12
- };
14
+ );
15
+ });
13
16
 
14
- return CodeMirror.overlayParser(CodeMirror.getMode(config, parserConfig.backdrop || "text/html"), liquidOverlay);
17
+ CodeMirror.defineMode("text/x-liquid-yaml", function(config) {
18
+ return CodeMirror.multiplexingMode(
19
+ CodeMirror.getMode(config, "text/x-yaml"),
20
+ {
21
+ open: "{{", close: "}}",
22
+ mode: CodeMirror.getMode(config, "text/x-liquid-variable"),
23
+ delimStyle: "tag"
24
+ },
25
+ {
26
+ open: "{%", close: "%}",
27
+ mode: CodeMirror.getMode(config, "text/x-liquid-tag"),
28
+ delimStyle: "tag"
29
+ }
30
+ );
15
31
  });
@@ -0,0 +1,63 @@
1
+ (function() {
2
+ var matching = {"(": ")>", ")": "(<", "[": "]>", "]": "[<", "{": "}>", "}": "{<"};
3
+ function findMatchingBracket(cm) {
4
+ var cur = cm.getCursor(), line = cm.getLineHandle(cur.line), pos = cur.ch - 1;
5
+ var match = (pos >= 0 && matching[line.text.charAt(pos)]) || matching[line.text.charAt(++pos)];
6
+ if (!match) return null;
7
+ var forward = match.charAt(1) == ">", d = forward ? 1 : -1;
8
+ var style = cm.getTokenAt({line: cur.line, ch: pos + 1}).type;
9
+
10
+ var stack = [line.text.charAt(pos)], re = /[(){}[\]]/;
11
+ function scan(line, lineNo, start) {
12
+ if (!line.text) return;
13
+ var pos = forward ? 0 : line.text.length - 1, end = forward ? line.text.length : -1;
14
+ if (start != null) pos = start + d;
15
+ for (; pos != end; pos += d) {
16
+ var ch = line.text.charAt(pos);
17
+ if (re.test(ch) && cm.getTokenAt({line: lineNo, ch: pos + 1}).type == style) {
18
+ var match = matching[ch];
19
+ if (match.charAt(1) == ">" == forward) stack.push(ch);
20
+ else if (stack.pop() != match.charAt(0)) return {pos: pos, match: false};
21
+ else if (!stack.length) return {pos: pos, match: true};
22
+ }
23
+ }
24
+ }
25
+ for (var i = cur.line, found, e = forward ? Math.min(i + 100, cm.lineCount()) : Math.max(-1, i - 100); i != e; i+=d) {
26
+ if (i == cur.line) found = scan(line, i, pos);
27
+ else found = scan(cm.getLineHandle(i), i);
28
+ if (found) break;
29
+ }
30
+ return {from: {line: cur.line, ch: pos}, to: found && {line: i, ch: found.pos}, match: found && found.match};
31
+ }
32
+
33
+ function matchBrackets(cm, autoclear) {
34
+ var found = findMatchingBracket(cm);
35
+ if (!found) return;
36
+ var style = found.match ? "CodeMirror-matchingbracket" : "CodeMirror-nonmatchingbracket";
37
+ var one = cm.markText(found.from, {line: found.from.line, ch: found.from.ch + 1},
38
+ {className: style});
39
+ var two = found.to && cm.markText(found.to, {line: found.to.line, ch: found.to.ch + 1},
40
+ {className: style});
41
+ var clear = function() {
42
+ cm.operation(function() { one.clear(); two && two.clear(); });
43
+ };
44
+ if (autoclear) setTimeout(clear, 800);
45
+ else return clear;
46
+ }
47
+
48
+ var currentlyHighlighted = null;
49
+ function doMatchBrackets(cm) {
50
+ cm.operation(function() {
51
+ if (currentlyHighlighted) {currentlyHighlighted(); currentlyHighlighted = null;}
52
+ if (!cm.somethingSelected()) currentlyHighlighted = matchBrackets(cm, false);
53
+ });
54
+ }
55
+
56
+ CodeMirror.defineOption("matchBrackets", false, function(cm, val) {
57
+ if (val) cm.on("cursorActivity", doMatchBrackets);
58
+ else cm.off("cursorActivity", doMatchBrackets);
59
+ });
60
+
61
+ CodeMirror.defineExtension("matchBrackets", function() {matchBrackets(this, true);});
62
+ CodeMirror.defineExtension("findMatchingBracket", function(){return findMatchingBracket(this);});
63
+ })();
@@ -0,0 +1,95 @@
1
+ CodeMirror.multiplexingMode = function(outer /*, others */) {
2
+ // Others should be {open, close, mode [, delimStyle]} objects
3
+ var others = Array.prototype.slice.call(arguments, 1);
4
+ var n_others = others.length;
5
+
6
+ function indexOf(string, pattern, from) {
7
+ if (typeof pattern == "string") return string.indexOf(pattern, from);
8
+ var m = pattern.exec(from ? string.slice(from) : string);
9
+ return m ? m.index + from : -1;
10
+ }
11
+
12
+ return {
13
+ startState: function() {
14
+ return {
15
+ outer: CodeMirror.startState(outer),
16
+ innerActive: null,
17
+ inner: null
18
+ };
19
+ },
20
+
21
+ copyState: function(state) {
22
+ return {
23
+ outer: CodeMirror.copyState(outer, state.outer),
24
+ innerActive: state.innerActive,
25
+ inner: state.innerActive && CodeMirror.copyState(state.innerActive.mode, state.inner)
26
+ };
27
+ },
28
+
29
+ token: function(stream, state) {
30
+ if (!state.innerActive) {
31
+ var cutOff = Infinity, oldContent = stream.string;
32
+ for (var i = 0; i < n_others; ++i) {
33
+ var other = others[i];
34
+ var found = indexOf(oldContent, other.open, stream.pos);
35
+ if (found == stream.pos) {
36
+ stream.match(other.open);
37
+ state.innerActive = other;
38
+ state.inner = CodeMirror.startState(other.mode, outer.indent ? outer.indent(state.outer, "") : 0);
39
+ return other.delimStyle;
40
+ } else if (found != -1 && found < cutOff) {
41
+ cutOff = found;
42
+ }
43
+ }
44
+ if (cutOff != Infinity) stream.string = oldContent.slice(0, cutOff);
45
+ var outerToken = outer.token(stream, state.outer);
46
+ if (cutOff != Infinity) stream.string = oldContent;
47
+ return outerToken;
48
+ } else {
49
+ var curInner = state.innerActive, oldContent = stream.string;
50
+ var found = indexOf(oldContent, curInner.close, stream.pos);
51
+ if (found == stream.pos) {
52
+ stream.match(curInner.close);
53
+ state.innerActive = state.inner = null;
54
+ return curInner.delimStyle;
55
+ }
56
+ if (found > -1) stream.string = oldContent.slice(0, found);
57
+ var innerToken = curInner.mode.token(stream, state.inner);
58
+ if (found > -1) stream.string = oldContent;
59
+ var cur = stream.current(), found = cur.indexOf(curInner.close);
60
+ if (found > -1) stream.backUp(cur.length - found);
61
+ return innerToken;
62
+ }
63
+ },
64
+
65
+ indent: function(state, textAfter) {
66
+ var mode = state.innerActive ? state.innerActive.mode : outer;
67
+ if (!mode.indent) return CodeMirror.Pass;
68
+ return mode.indent(state.innerActive ? state.inner : state.outer, textAfter);
69
+ },
70
+
71
+ blankLine: function(state) {
72
+ var mode = state.innerActive ? state.innerActive.mode : outer;
73
+ if (mode.blankLine) {
74
+ mode.blankLine(state.innerActive ? state.inner : state.outer);
75
+ }
76
+ if (!state.innerActive) {
77
+ for (var i = 0; i < n_others; ++i) {
78
+ var other = others[i];
79
+ if (other.open === "\n") {
80
+ state.innerActive = other;
81
+ state.inner = CodeMirror.startState(other.mode, mode.indent ? mode.indent(state.outer, "") : 0);
82
+ }
83
+ }
84
+ } else if (mode.close === "\n") {
85
+ state.innerActive = state.inner = null;
86
+ }
87
+ },
88
+
89
+ electricChars: outer.electricChars,
90
+
91
+ innerMode: function(state) {
92
+ return state.inner ? {state: state.inner, mode: state.innerActive.mode} : {state: state.outer, mode: outer};
93
+ }
94
+ };
95
+ };
@@ -1,15 +1,15 @@
1
1
  //= require puffer/right-tabs-src
2
2
  //= require puffer/codemirror
3
- //= require puffer/overlay
3
+ //= require puffer/multiplex
4
+ //= require puffer/matchbrackets
4
5
  //= require puffer/codemirror/xml
5
6
  //= require puffer/codemirror/javascript
6
7
  //= require puffer/codemirror/css
7
8
  //= require_tree ./codemirror
8
- //= require puffer/liquid
9
9
 
10
10
  Tabs.include({
11
- initialize: function(options) {
12
- this.$super(options);
11
+ initialize: function(element, options) {
12
+ this.$super(element, options);
13
13
  this.buildAddButton();
14
14
  },
15
15
 
@@ -17,89 +17,185 @@ Tabs.include({
17
17
  if (isFunction(this.options.addButton)) {
18
18
  this.addButton = $E('a', {'class': 'rui-tabs-tab rui-tabs-add', 'html': '<a href="#">+</a>'}).insertTo(this.tabsList);
19
19
  this.addButton.onClick(this.options.addButton.bind(this));
20
+ this.onAdd(function(event) {
21
+ this.addButton.insertTo(this.tabsList);
22
+ });
23
+ }
24
+ },
25
+
26
+ scrollTo: function(scroll) {
27
+ // checking the constraints
28
+ var available_width = this.scroller.size().x;
29
+ if (this.addButton) {
30
+ var addButtonWidth = this.addButton.dimensions().width;
31
+ } else {
32
+ var addButtonWidth = 0;
33
+ }
34
+ var overall_width = this.tabs.map('width').sum() + addButtonWidth;
35
+
36
+ if (scroll < (available_width - overall_width)) {
37
+ scroll = available_width - overall_width;
38
+ }
39
+ if (scroll > 0) { scroll = 0; }
40
+
41
+ // applying the scroll
42
+ this.tabsList.morph({left: scroll+'px'}, {duration: this.options.scrollDuration});
43
+
44
+ this.checkScrollButtons(overall_width, available_width, scroll);
45
+ }
46
+ });
47
+
48
+ Tabs.Tab.include({
49
+ initialize: function(element, main) {
50
+ this.$super(element, main);
51
+ if (main.options.disablable) {
52
+ this.link.insert($E('div', {
53
+ 'class': 'rui-tabs-tab-close-icon', 'html': '&times;'
54
+ }).onClick(function(event) {
55
+ if (this.main.enabled().length > 1) {
56
+ if (this.current()) {
57
+ var enabled = this.main.enabled();
58
+ var sibling = enabled[enabled.indexOf(this) + 1] || enabled[enabled.indexOf(this)-1];
59
+
60
+ if (sibling) {
61
+ sibling.select();
62
+ }
63
+ }
64
+ this.disable();
65
+ }
66
+ event.stop();
67
+ }.bind(this)));
20
68
  }
21
69
  }
22
70
  });
23
71
 
24
72
  var page_part_tab_select = function(event) {
73
+ var inner_tabs = event.target.panel.find('.rui-tabs,*[data-tabs]').first();
74
+ if (inner_tabs instanceof Tabs)
75
+ inner_tabs.current().select();
76
+
25
77
  var textarea = event.target.panel.first('textarea[data-codemirror]');
26
- if (textarea.codemirror) {
78
+ if (textarea && textarea.codemirror) {
27
79
  textarea.codemirror.refresh();
28
80
  }
29
81
  }
30
82
 
31
- var page_part_tab_remove = function(event) {
32
- var destroy_mark = event.target.panel.first('.destroy_mark');
33
- var page_part_param = destroy_mark.next();
34
- $('page_parts_marked_for_destroy').append(destroy_mark.value('1'))
35
- if (page_part_param) {
36
- $('page_parts_marked_for_destroy').append(page_part_param);
37
- }
38
- }
39
-
40
83
  var page_part_tab_add = function(event) {
41
- event.stop();
42
- var new_id = new Date().getTime();
43
84
  var _this = this;
85
+
44
86
  new Dialog.Prompt({label: 'Enter new page part name'}).onOk(function() {
45
87
  var value = this.input.value();
46
88
  if (!value.blank()) {
47
- _this.add(value, new_page_part_tab_panel.replace(/new_page_part_tab_panel_index/g, new_id), {id: new_id});
48
- _this.tabs.last().panel.first('input[type=hidden]').value(value);
49
- _this.tabs.last().select();
50
- _this.addButton.insertTo(_this.tabsList);
51
- $$('textarea[data-codemirror]').each(init_codemirror);
89
+ _this.add(value);
90
+ var tab = _this.tabs.last();
91
+ tab.panel.data('name', value);
92
+ fill_new_tab(tab);
93
+ tab.select();
94
+
95
+ Tabs.rescan();
96
+ init_codemirrors();
52
97
  this.hide();
53
98
  }
54
99
  }).show();
100
+ event.stop();
101
+ }
102
+
103
+ var page_part_tab_remove = function(event) {
104
+ save_destroy_marks(event.target.panel);
105
+ }
106
+
107
+
108
+ var fill_new_tab = function(tab) {
109
+ var new_id = new Date().getTime();
110
+ if (tab.main.data('new-panel'))
111
+ tab.panel.update(tab.main.data('new-panel').replace(new RegExp(tab.main.data('new-panel-variable'), 'g'), new_id));
112
+
113
+ var name_input = tab.panel.first('[data-acts="name"]');
114
+ var name_panel = tab.panel.first().parent('[data-name]');
115
+ if (name_input && name_panel) {
116
+ name_input.value(name_panel.data('name'));
117
+ }
118
+
119
+ init_codemirrors();
120
+ }
121
+
122
+ var save_destroy_marks = function(scope) {
123
+ var form = scope.tab.main.parent('form');
124
+ scope.find('[data-acts="destroy"]').each(function(destroy_mark) {
125
+ var page_part_param = destroy_mark.siblings('[data-acts="id"]').first();
126
+ if (page_part_param) {
127
+ form.insert(destroy_mark.value('true'), 'top');
128
+ form.insert(page_part_param, 'top');
129
+ }
130
+ });
55
131
  }
56
132
 
57
133
  var init_codemirror = function(textarea) {
58
134
  if (!textarea.codemirror) {
59
135
  var codemirror = CodeMirror.fromTextArea(textarea._, {
60
- mode: 'liquid',
136
+ mode: textarea.data('codemirror').mode || 'text/html',
61
137
  lineNumbers: true,
62
138
  lineWrapping: true,
63
- onCursorActivity: function(editor) {
64
- if (editor.last_active_line != undefined) {
65
- editor.setLineClass(editor.last_active_line, null);
66
- }
67
- editor.last_active_line = editor.getCursor().line;
68
- editor.setLineClass(editor.last_active_line, "active_line");
69
- },
139
+ tabSize: 2,
70
140
  extraKeys: {
71
- "Esc": codemirror_fullscreen
141
+ "Tab": "indentMore",
142
+ "Shift-Tab": "indentLess",
143
+ "Esc": codemirror_fullscreen,
144
+ "Alt-Enter": codemirror_fullscreen
72
145
  }
73
146
  });
74
147
 
75
148
  textarea.codemirror = codemirror;
76
- codemirror.buttons = textarea.prev('.codemirror_buttons');
77
149
  }
78
150
  }
79
151
 
80
- $(document).onReady(function() {
152
+ var init_codemirrors = function() {
81
153
  $$('textarea[data-codemirror]').each(init_codemirror);
154
+ }
155
+
156
+ var set_codemirror_mode = function(select) {
157
+ var editors = select.parent('.rui-tabs-panel').find('textarea[data-codemirror]');
158
+ var selected = $(select._.selectedOptions[0]);
159
+ var mode = selected.data('codemirror-mode');
160
+ if (!mode.blank()) {
161
+ editors.each(function(editor) {
162
+ editor.codemirror.setOption("mode", mode);
163
+ });
164
+ }
165
+ }
166
+
167
+ var set_codemirrors_modes = function() {
168
+ $$("select[data-codemirror-mode-select]").each(set_codemirror_mode);
169
+ }
170
+
171
+ "select[data-codemirror-mode-select]".on('change', function() { set_codemirror_mode(this) });
172
+
173
+ $(document).onReady(function() {
174
+ init_codemirrors();
175
+ set_codemirrors_modes();
176
+ });
177
+
178
+ $(document).on('data:sending', function() {
179
+ $$('textarea[data-codemirror]').each(function(element) {
180
+ element.codemirror.save();
181
+ });
82
182
  });
83
183
 
84
- "*[data-codemirror-button]".onClick(function(event) {
85
- if (event.which != 1) return;
86
- window['codemirror_' + this.data('codemirror-button')](this.parent('ul').next('textarea').codemirror);
184
+ $(document).on('ajax:complete', function() {
185
+ Tabs.rescan();
186
+ init_codemirrors();
187
+ set_codemirrors_modes();
87
188
  });
88
189
 
89
- ".codemirror_buttons_fulscreen".onMouseenter('morph', {'top': '0px'});
90
- ".codemirror_buttons_fulscreen".onMouseleave('morph', {'top': '-20px'});
91
-
92
190
  var codemirror_fullscreen = function(editor) {
93
- var scroll = $(editor.getWrapperElement()).children('.CodeMirror-scroll').first();
191
+ var scroll = $(editor.getTextArea()).parents('*[data-fullscreen]').last();
94
192
  var body = $$('body').first();
95
193
 
96
- if (scroll.hasClass('fullscreen')) {
97
- scroll.removeClass('fullscreen');
98
- editor.buttons.removeClass('codemirror_buttons_fulscreen');
194
+ if (scroll.data('fullscreen')) {
195
+ scroll.data('fullscreen', false)
99
196
  body.setStyle('overflow', 'auto');
100
197
  } else {
101
- scroll.addClass('fullscreen');
102
- editor.buttons.addClass('codemirror_buttons_fulscreen');
198
+ scroll.data('fullscreen', true)
103
199
  body.setStyle('overflow', 'hidden');
104
200
  }
105
201