liquid_cms 0.3.1.0 → 0.3.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (136) hide show
  1. data/CHANGELOG.rdoc +10 -0
  2. data/Gemfile +0 -3
  3. data/README.rdoc +16 -2
  4. data/TODO.rdoc +0 -2
  5. data/app/controllers/cms/assets_controller.rb +20 -6
  6. data/app/controllers/cms/components_controller.rb +11 -3
  7. data/app/controllers/cms/pages_controller.rb +15 -4
  8. data/app/helpers/cms/common_helper.rb +31 -32
  9. data/app/liquid/cms_paperclip_extension.rb +75 -3
  10. data/app/liquid/tags/{data_tag.rb → cms/data_tag.rb} +0 -0
  11. data/app/models/cms/asset.rb +1 -1
  12. data/app/models/cms/component.rb +3 -3
  13. data/app/views/cms/assets/_form.html.erb +1 -2
  14. data/app/views/cms/assets/update.js.rjs +1 -0
  15. data/app/views/cms/components/update.js.rjs +1 -0
  16. data/app/views/cms/pages/_form.html.erb +3 -3
  17. data/app/views/cms/pages/update.js.rjs +1 -0
  18. data/app/views/layouts/cms.html.erb +4 -3
  19. data/config/initializers/cms/simple_form.rb +70 -12
  20. data/config/initializers/cms/simple_form_updates.rb +9 -3
  21. data/config/locales/cms/en.yml +6 -0
  22. data/lib/generators/liquid_cms/install_generator.rb +5 -1
  23. data/lib/generators/liquid_cms/templates/migration_rev2.rb +13 -0
  24. data/lib/generators/liquid_cms/templates/public/cms/codemirror/LICENSE +16 -20
  25. data/lib/generators/liquid_cms/templates/public/cms/codemirror/lib/codemirror.css +68 -0
  26. data/lib/generators/liquid_cms/templates/public/cms/codemirror/lib/codemirror.js +2197 -0
  27. data/lib/generators/liquid_cms/templates/public/cms/codemirror/lib/overlay.js +51 -0
  28. data/lib/generators/liquid_cms/templates/public/cms/codemirror/lib/runmode.js +27 -0
  29. data/lib/generators/liquid_cms/templates/public/cms/codemirror/mode/clike/clike.js +247 -0
  30. data/lib/generators/liquid_cms/templates/public/cms/codemirror/mode/clike/index.html +102 -0
  31. data/lib/generators/liquid_cms/templates/public/cms/codemirror/mode/clojure/clojure.js +207 -0
  32. data/lib/generators/liquid_cms/templates/public/cms/codemirror/mode/clojure/index.html +85 -0
  33. data/lib/generators/liquid_cms/templates/public/cms/codemirror/mode/coffeescript/LICENSE +22 -0
  34. data/lib/generators/liquid_cms/templates/public/cms/codemirror/mode/coffeescript/coffeescript.js +325 -0
  35. data/lib/generators/liquid_cms/templates/public/cms/codemirror/mode/coffeescript/index.html +722 -0
  36. data/lib/generators/liquid_cms/templates/public/cms/codemirror/mode/css/css.js +124 -0
  37. data/lib/generators/liquid_cms/templates/public/cms/codemirror/mode/css/index.html +56 -0
  38. data/lib/generators/liquid_cms/templates/public/cms/codemirror/mode/diff/diff.css +3 -0
  39. data/lib/generators/liquid_cms/templates/public/cms/codemirror/mode/diff/diff.js +13 -0
  40. data/lib/generators/liquid_cms/templates/public/cms/codemirror/mode/diff/index.html +99 -0
  41. data/lib/generators/liquid_cms/templates/public/cms/codemirror/mode/haskell/haskell.js +242 -0
  42. data/lib/generators/liquid_cms/templates/public/cms/codemirror/mode/haskell/index.html +60 -0
  43. data/lib/generators/liquid_cms/templates/public/cms/codemirror/mode/htmlmixed/htmlmixed.js +79 -0
  44. data/lib/generators/liquid_cms/templates/public/cms/codemirror/mode/htmlmixed/index.html +52 -0
  45. data/lib/generators/liquid_cms/templates/public/cms/codemirror/mode/javascript/index.html +78 -0
  46. data/lib/generators/liquid_cms/templates/public/cms/codemirror/mode/javascript/javascript.js +352 -0
  47. data/lib/generators/liquid_cms/templates/public/cms/codemirror/mode/jinja2/index.html +38 -0
  48. data/lib/generators/liquid_cms/templates/public/cms/codemirror/mode/jinja2/jinja2.js +42 -0
  49. data/lib/generators/liquid_cms/templates/public/cms/codemirror/mode/lua/index.html +72 -0
  50. data/lib/generators/liquid_cms/templates/public/cms/codemirror/mode/lua/lua.js +140 -0
  51. data/lib/generators/liquid_cms/templates/public/cms/codemirror/mode/markdown/index.html +340 -0
  52. data/lib/generators/liquid_cms/templates/public/cms/codemirror/mode/markdown/markdown.css +10 -0
  53. data/lib/generators/liquid_cms/templates/public/cms/codemirror/mode/markdown/markdown.js +230 -0
  54. data/lib/generators/liquid_cms/templates/public/cms/codemirror/mode/ntriples/index.html +33 -0
  55. data/lib/generators/liquid_cms/templates/public/cms/codemirror/mode/ntriples/ntriples.js +172 -0
  56. data/lib/generators/liquid_cms/templates/public/cms/codemirror/mode/pascal/LICENSE +7 -0
  57. data/lib/generators/liquid_cms/templates/public/cms/codemirror/mode/pascal/index.html +49 -0
  58. data/lib/generators/liquid_cms/templates/public/cms/codemirror/mode/pascal/pascal.js +138 -0
  59. data/lib/generators/liquid_cms/templates/public/cms/codemirror/mode/php/index.html +49 -0
  60. data/lib/generators/liquid_cms/templates/public/cms/codemirror/mode/php/php.js +116 -0
  61. data/lib/generators/liquid_cms/templates/public/cms/codemirror/mode/plsql/index.html +63 -0
  62. data/lib/generators/liquid_cms/templates/public/cms/codemirror/mode/plsql/plsql.js +217 -0
  63. data/lib/generators/liquid_cms/templates/public/cms/codemirror/mode/python/LICENSE.txt +21 -0
  64. data/lib/generators/liquid_cms/templates/public/cms/codemirror/mode/python/index.html +123 -0
  65. data/lib/generators/liquid_cms/templates/public/cms/codemirror/mode/python/python.js +320 -0
  66. data/lib/generators/liquid_cms/templates/public/cms/codemirror/mode/r/LICENSE +24 -0
  67. data/lib/generators/liquid_cms/templates/public/cms/codemirror/mode/r/index.html +74 -0
  68. data/lib/generators/liquid_cms/templates/public/cms/codemirror/mode/r/r.js +141 -0
  69. data/lib/generators/liquid_cms/templates/public/cms/codemirror/mode/rst/index.html +526 -0
  70. data/lib/generators/liquid_cms/templates/public/cms/codemirror/mode/rst/rst.css +75 -0
  71. data/lib/generators/liquid_cms/templates/public/cms/codemirror/mode/rst/rst.js +333 -0
  72. data/lib/generators/liquid_cms/templates/public/cms/codemirror/mode/ruby/LICENSE +24 -0
  73. data/lib/generators/liquid_cms/templates/public/cms/codemirror/mode/ruby/index.html +172 -0
  74. data/lib/generators/liquid_cms/templates/public/cms/codemirror/mode/ruby/ruby.js +195 -0
  75. data/lib/generators/liquid_cms/templates/public/cms/codemirror/mode/scheme/index.html +65 -0
  76. data/lib/generators/liquid_cms/templates/public/cms/codemirror/mode/scheme/scheme.js +202 -0
  77. data/lib/generators/liquid_cms/templates/public/cms/codemirror/mode/smalltalk/index.html +56 -0
  78. data/lib/generators/liquid_cms/templates/public/cms/codemirror/mode/smalltalk/smalltalk.js +122 -0
  79. data/lib/generators/liquid_cms/templates/public/cms/codemirror/mode/sparql/index.html +41 -0
  80. data/lib/generators/liquid_cms/templates/public/cms/codemirror/mode/sparql/sparql.js +143 -0
  81. data/lib/generators/liquid_cms/templates/public/cms/codemirror/mode/stex/index.html +96 -0
  82. data/lib/generators/liquid_cms/templates/public/cms/codemirror/mode/stex/stex.js +167 -0
  83. data/lib/generators/liquid_cms/templates/public/cms/codemirror/mode/velocity/index.html +103 -0
  84. data/lib/generators/liquid_cms/templates/public/cms/codemirror/mode/velocity/velocity.js +146 -0
  85. data/lib/generators/liquid_cms/templates/public/cms/codemirror/mode/xml/index.html +42 -0
  86. data/lib/generators/liquid_cms/templates/public/cms/codemirror/mode/xml/xml.js +231 -0
  87. data/lib/generators/liquid_cms/templates/public/cms/codemirror/mode/xmlpure/index.html +60 -0
  88. data/lib/generators/liquid_cms/templates/public/cms/codemirror/mode/xmlpure/xmlpure.js +481 -0
  89. data/lib/generators/liquid_cms/templates/public/cms/codemirror/mode/yaml/index.html +68 -0
  90. data/lib/generators/liquid_cms/templates/public/cms/codemirror/mode/yaml/yaml.js +95 -0
  91. data/lib/generators/liquid_cms/templates/public/cms/codemirror/theme/cobalt.css +17 -0
  92. data/lib/generators/liquid_cms/templates/public/cms/codemirror/theme/default.css +19 -0
  93. data/lib/generators/liquid_cms/templates/public/cms/codemirror/theme/eclipse.css +24 -0
  94. data/lib/generators/liquid_cms/templates/public/cms/codemirror/theme/elegant.css +9 -0
  95. data/lib/generators/liquid_cms/templates/public/cms/codemirror/theme/neat.css +8 -0
  96. data/lib/generators/liquid_cms/templates/public/cms/codemirror/theme/night.css +20 -0
  97. data/lib/generators/liquid_cms/templates/public/cms/javascripts/cms.js +1 -1
  98. data/lib/generators/liquid_cms/templates/public/cms/javascripts/codemirror_custom.js +96 -0
  99. data/lib/generators/liquid_cms/templates/public/cms/stylesheets/codemirror_changes.css +26 -0
  100. data/lib/generators/liquid_cms/templates/public/cms/stylesheets/liquid.css +7 -0
  101. data/lib/generators/liquid_cms/templates/public/cms/stylesheets/simple_form.css +0 -8
  102. data/lib/liquid_cms/version.rb +1 -1
  103. data/liquid_cms.gemspec +1 -1
  104. data/test/functional/assets_controller_test.rb +35 -20
  105. data/test/functional/components_controller_test.rb +15 -5
  106. data/test/functional/pages_controller_test.rb +19 -6
  107. data/test/rails_app/Gemfile +1 -2
  108. data/test/rails_app/config/locales/cms/en.yml +26 -4
  109. data/test/rails_app/db/migrate/20110511161859_create_liquid_cms_upgrade_rev2.rb +13 -0
  110. data/test/unit/asset_test.rb +1 -1
  111. data/test/unit/component_test.rb +1 -1
  112. metadata +89 -32
  113. data/generators/liquid_cms/templates/migration_rev1.rb +0 -38
  114. data/lib/generators/liquid_cms/templates/public/cms/codemirror/css/csscolors.css +0 -55
  115. data/lib/generators/liquid_cms/templates/public/cms/codemirror/css/docs.css +0 -158
  116. data/lib/generators/liquid_cms/templates/public/cms/codemirror/css/font.js +0 -15
  117. data/lib/generators/liquid_cms/templates/public/cms/codemirror/css/jscolors.css +0 -59
  118. data/lib/generators/liquid_cms/templates/public/cms/codemirror/css/sparqlcolors.css +0 -43
  119. data/lib/generators/liquid_cms/templates/public/cms/codemirror/css/xmlcolors.css +0 -55
  120. data/lib/generators/liquid_cms/templates/public/cms/codemirror/js/codemirror.js +0 -582
  121. data/lib/generators/liquid_cms/templates/public/cms/codemirror/js/editor.js +0 -1671
  122. data/lib/generators/liquid_cms/templates/public/cms/codemirror/js/highlight.js +0 -68
  123. data/lib/generators/liquid_cms/templates/public/cms/codemirror/js/mirrorframe.js +0 -81
  124. data/lib/generators/liquid_cms/templates/public/cms/codemirror/js/parsecss.js +0 -161
  125. data/lib/generators/liquid_cms/templates/public/cms/codemirror/js/parsedummy.js +0 -32
  126. data/lib/generators/liquid_cms/templates/public/cms/codemirror/js/parsehtmlmixed.js +0 -93
  127. data/lib/generators/liquid_cms/templates/public/cms/codemirror/js/parsejavascript.js +0 -359
  128. data/lib/generators/liquid_cms/templates/public/cms/codemirror/js/parsesparql.js +0 -162
  129. data/lib/generators/liquid_cms/templates/public/cms/codemirror/js/parsexml.js +0 -291
  130. data/lib/generators/liquid_cms/templates/public/cms/codemirror/js/select.js +0 -699
  131. data/lib/generators/liquid_cms/templates/public/cms/codemirror/js/stringstream.js +0 -159
  132. data/lib/generators/liquid_cms/templates/public/cms/codemirror/js/tokenize.js +0 -57
  133. data/lib/generators/liquid_cms/templates/public/cms/codemirror/js/tokenizejavascript.js +0 -174
  134. data/lib/generators/liquid_cms/templates/public/cms/codemirror/js/undo.js +0 -413
  135. data/lib/generators/liquid_cms/templates/public/cms/codemirror/js/unittests.js +0 -44
  136. data/lib/generators/liquid_cms/templates/public/cms/codemirror/js/util.js +0 -133
@@ -1,68 +0,0 @@
1
- // Minimal framing needed to use CodeMirror-style parsers to highlight
2
- // code. Load this along with tokenize.js, stringstream.js, and your
3
- // parser. Then call highlightText, passing a string as the first
4
- // argument, and as the second argument either a callback function
5
- // that will be called with an array of SPAN nodes for every line in
6
- // the code, or a DOM node to which to append these spans, and
7
- // optionally (not needed if you only loaded one parser) a parser
8
- // object.
9
-
10
- // Stuff from util.js that the parsers are using.
11
- var StopIteration = {toString: function() {return "StopIteration"}};
12
-
13
- var Editor = {};
14
- var indentUnit = 2;
15
-
16
- (function(){
17
- function normaliseString(string) {
18
- var tab = "";
19
- for (var i = 0; i < indentUnit; i++) tab += " ";
20
-
21
- string = string.replace(/\t/g, tab).replace(/\u00a0/g, " ").replace(/\r\n?/g, "\n");
22
- var pos = 0, parts = [], lines = string.split("\n");
23
- for (var line = 0; line < lines.length; line++) {
24
- if (line != 0) parts.push("\n");
25
- parts.push(lines[line]);
26
- }
27
-
28
- return {
29
- next: function() {
30
- if (pos < parts.length) return parts[pos++];
31
- else throw StopIteration;
32
- }
33
- };
34
- }
35
-
36
- window.highlightText = function(string, callback, parser) {
37
- parser = (parser || Editor.Parser).make(stringStream(normaliseString(string)));
38
- var line = [];
39
- if (callback.nodeType == 1) {
40
- var node = callback;
41
- callback = function(line) {
42
- for (var i = 0; i < line.length; i++)
43
- node.appendChild(line[i]);
44
- node.appendChild(document.createElement("br"));
45
- };
46
- }
47
-
48
- try {
49
- while (true) {
50
- var token = parser.next();
51
- if (token.value == "\n") {
52
- callback(line);
53
- line = [];
54
- }
55
- else {
56
- var span = document.createElement("span");
57
- span.className = token.style;
58
- span.appendChild(document.createTextNode(token.value));
59
- line.push(span);
60
- }
61
- }
62
- }
63
- catch (e) {
64
- if (e != StopIteration) throw e;
65
- }
66
- if (line.length) callback(line);
67
- }
68
- })();
@@ -1,81 +0,0 @@
1
- /* Demonstration of embedding CodeMirror in a bigger application. The
2
- * interface defined here is a mess of prompts and confirms, and
3
- * should probably not be used in a real project.
4
- */
5
-
6
- function MirrorFrame(place, options) {
7
- this.home = document.createElement("div");
8
- if (place.appendChild)
9
- place.appendChild(this.home);
10
- else
11
- place(this.home);
12
-
13
- var self = this;
14
- function makeButton(name, action) {
15
- var button = document.createElement("input");
16
- button.type = "button";
17
- button.value = name;
18
- self.home.appendChild(button);
19
- button.onclick = function(){self[action].call(self);};
20
- }
21
-
22
- makeButton("Search", "search");
23
- makeButton("Replace", "replace");
24
- makeButton("Current line", "line");
25
- makeButton("Jump to line", "jump");
26
- makeButton("Insert constructor", "macro");
27
- makeButton("Indent all", "reindent");
28
-
29
- this.mirror = new CodeMirror(this.home, options);
30
- }
31
-
32
- MirrorFrame.prototype = {
33
- search: function() {
34
- var text = prompt("Enter search term:", "");
35
- if (!text) return;
36
-
37
- var first = true;
38
- do {
39
- var cursor = this.mirror.getSearchCursor(text, first);
40
- first = false;
41
- while (cursor.findNext()) {
42
- cursor.select();
43
- if (!confirm("Search again?"))
44
- return;
45
- }
46
- } while (confirm("End of document reached. Start over?"));
47
- },
48
-
49
- replace: function() {
50
- // This is a replace-all, but it is possible to implement a
51
- // prompting replace.
52
- var from = prompt("Enter search string:", ""), to;
53
- if (from) to = prompt("What should it be replaced with?", "");
54
- if (to == null) return;
55
-
56
- var cursor = this.mirror.getSearchCursor(from, false);
57
- while (cursor.findNext())
58
- cursor.replace(to);
59
- },
60
-
61
- jump: function() {
62
- var line = prompt("Jump to line:", "");
63
- if (line && !isNaN(Number(line)))
64
- this.mirror.jumpToLine(Number(line));
65
- },
66
-
67
- line: function() {
68
- alert("The cursor is currently at line " + this.mirror.currentLine());
69
- this.mirror.focus();
70
- },
71
-
72
- macro: function() {
73
- var name = prompt("Name your constructor:", "");
74
- if (name)
75
- this.mirror.replaceSelection("function " + name + "() {\n \n}\n\n" + name + ".prototype = {\n \n};\n");
76
- },
77
-
78
- reindent: function() {
79
- this.mirror.reindent();
80
- }
81
- };
@@ -1,161 +0,0 @@
1
- /* Simple parser for CSS */
2
-
3
- var CSSParser = Editor.Parser = (function() {
4
- var tokenizeCSS = (function() {
5
- function normal(source, setState) {
6
- var ch = source.next();
7
- if (ch == "@") {
8
- source.nextWhileMatches(/\w/);
9
- return "css-at";
10
- }
11
- else if (ch == "/" && source.equals("*")) {
12
- setState(inCComment);
13
- return null;
14
- }
15
- else if (ch == "<" && source.equals("!")) {
16
- setState(inSGMLComment);
17
- return null;
18
- }
19
- else if (ch == "=") {
20
- return "css-compare";
21
- }
22
- else if (source.equals("=") && (ch == "~" || ch == "|")) {
23
- source.next();
24
- return "css-compare";
25
- }
26
- else if (ch == "\"" || ch == "'") {
27
- setState(inString(ch));
28
- return null;
29
- }
30
- else if (ch == "#") {
31
- source.nextWhileMatches(/\w/);
32
- return "css-hash";
33
- }
34
- else if (ch == "!") {
35
- source.nextWhileMatches(/[ \t]/);
36
- source.nextWhileMatches(/\w/);
37
- return "css-important";
38
- }
39
- else if (/\d/.test(ch)) {
40
- source.nextWhileMatches(/[\w.%]/);
41
- return "css-unit";
42
- }
43
- else if (/[,.+>*\/]/.test(ch)) {
44
- return "css-select-op";
45
- }
46
- else if (/[;{}:\[\]]/.test(ch)) {
47
- return "css-punctuation";
48
- }
49
- else {
50
- source.nextWhileMatches(/[\w\\\-_]/);
51
- return "css-identifier";
52
- }
53
- }
54
-
55
- function inCComment(source, setState) {
56
- var maybeEnd = false;
57
- while (!source.endOfLine()) {
58
- var ch = source.next();
59
- if (maybeEnd && ch == "/") {
60
- setState(normal);
61
- break;
62
- }
63
- maybeEnd = (ch == "*");
64
- }
65
- return "css-comment";
66
- }
67
-
68
- function inSGMLComment(source, setState) {
69
- var dashes = 0;
70
- while (!source.endOfLine()) {
71
- var ch = source.next();
72
- if (dashes >= 2 && ch == ">") {
73
- setState(normal);
74
- break;
75
- }
76
- dashes = (ch == "-") ? dashes + 1 : 0;
77
- }
78
- return "css-comment";
79
- }
80
-
81
- function inString(quote) {
82
- return function(source, setState) {
83
- var escaped = false;
84
- while (!source.endOfLine()) {
85
- var ch = source.next();
86
- if (ch == quote && !escaped)
87
- break;
88
- escaped = !escaped && ch == "\\";
89
- }
90
- if (!escaped)
91
- setState(normal);
92
- return "css-string";
93
- };
94
- }
95
-
96
- return function(source, startState) {
97
- return tokenizer(source, startState || normal);
98
- };
99
- })();
100
-
101
- function indentCSS(inBraces, inRule, base) {
102
- return function(nextChars) {
103
- if (!inBraces || /^\}/.test(nextChars)) return base;
104
- else if (inRule) return base + indentUnit * 2;
105
- else return base + indentUnit;
106
- };
107
- }
108
-
109
- // This is a very simplistic parser -- since CSS does not really
110
- // nest, it works acceptably well, but some nicer colouroing could
111
- // be provided with a more complicated parser.
112
- function parseCSS(source, basecolumn) {
113
- basecolumn = basecolumn || 0;
114
- var tokens = tokenizeCSS(source);
115
- var inBraces = false, inRule = false, inDecl = false;;
116
-
117
- var iter = {
118
- next: function() {
119
- var token = tokens.next(), style = token.style, content = token.content;
120
-
121
- if (style == "css-hash")
122
- style = token.style = inRule ? "css-colorcode" : "css-identifier";
123
- if (style == "css-identifier") {
124
- if (inRule) token.style = "css-value";
125
- else if (!inBraces && !inDecl) token.style = "css-selector";
126
- }
127
-
128
- if (content == "\n")
129
- token.indentation = indentCSS(inBraces, inRule, basecolumn);
130
-
131
- if (content == "{" && inDecl == "@media")
132
- inDecl = false;
133
- else if (content == "{")
134
- inBraces = true;
135
- else if (content == "}")
136
- inBraces = inRule = inDecl = false;
137
- else if (content == ";")
138
- inRule = inDecl = false;
139
- else if (inBraces && style != "css-comment" && style != "whitespace")
140
- inRule = true;
141
- else if (!inBraces && style == "css-at")
142
- inDecl = content;
143
-
144
- return token;
145
- },
146
-
147
- copy: function() {
148
- var _inBraces = inBraces, _inRule = inRule, _tokenState = tokens.state;
149
- return function(source) {
150
- tokens = tokenizeCSS(source, _tokenState);
151
- inBraces = _inBraces;
152
- inRule = _inRule;
153
- return iter;
154
- };
155
- }
156
- };
157
- return iter;
158
- }
159
-
160
- return {make: parseCSS, electricChars: "}"};
161
- })();
@@ -1,32 +0,0 @@
1
- var DummyParser = Editor.Parser = (function() {
2
- function tokenizeDummy(source) {
3
- while (!source.endOfLine()) source.next();
4
- return "text";
5
- }
6
- function parseDummy(source) {
7
- function indentTo(n) {return function() {return n;}}
8
- source = tokenizer(source, tokenizeDummy);
9
- var space = 0;
10
-
11
- var iter = {
12
- next: function() {
13
- var tok = source.next();
14
- if (tok.type == "whitespace") {
15
- if (tok.value == "\n") tok.indentation = indentTo(space);
16
- else space = tok.value.length;
17
- }
18
- return tok;
19
- },
20
- copy: function() {
21
- var _space = space;
22
- return function(_source) {
23
- space = _space;
24
- source = tokenizer(_source, tokenizeDummy);
25
- return iter;
26
- };
27
- }
28
- };
29
- return iter;
30
- }
31
- return {make: parseDummy};
32
- })();
@@ -1,93 +0,0 @@
1
- var HTMLMixedParser = Editor.Parser = (function() {
2
-
3
- // tags that trigger seperate parsers
4
- var triggers = {
5
- "script": "JSParser",
6
- "style": "CSSParser"
7
- };
8
-
9
- function checkDependencies() {
10
- var parsers = ['XMLParser'];
11
- for (var p in triggers) parsers.push(triggers[p]);
12
- for (var i in parsers) {
13
- if (!window[parsers[i]]) throw new Error(parsers[i] + " parser must be loaded for HTML mixed mode to work.");
14
- }
15
- XMLParser.configure({useHTMLKludges: true});
16
- }
17
-
18
- function parseMixed(stream) {
19
- checkDependencies();
20
- var htmlParser = XMLParser.make(stream), localParser = null, inTag = false;
21
- var iter = {next: top, copy: copy};
22
-
23
- function top() {
24
- var token = htmlParser.next();
25
- if (token.content == "<")
26
- inTag = true;
27
- else if (token.style == "xml-tagname" && inTag === true)
28
- inTag = token.content.toLowerCase();
29
- else if (token.content == ">") {
30
- if (triggers[inTag]) {
31
- var parser = window[triggers[inTag]];
32
- iter.next = local(parser, "</" + inTag);
33
- }
34
- inTag = false;
35
- }
36
- return token;
37
- }
38
- function local(parser, tag) {
39
- var baseIndent = htmlParser.indentation();
40
- localParser = parser.make(stream, baseIndent + indentUnit);
41
- return function() {
42
- if (stream.lookAhead(tag, false, false, true)) {
43
- localParser = null;
44
- iter.next = top;
45
- return top();
46
- }
47
-
48
- var token = localParser.next();
49
- var lt = token.value.lastIndexOf("<"), sz = Math.min(token.value.length - lt, tag.length);
50
- if (lt != -1 && token.value.slice(lt, lt + sz).toLowerCase() == tag.slice(0, sz) &&
51
- stream.lookAhead(tag.slice(sz), false, false, true)) {
52
- stream.push(token.value.slice(lt));
53
- token.value = token.value.slice(0, lt);
54
- }
55
-
56
- if (token.indentation) {
57
- var oldIndent = token.indentation;
58
- token.indentation = function(chars) {
59
- if (chars == "</")
60
- return baseIndent;
61
- else
62
- return oldIndent(chars);
63
- };
64
- }
65
-
66
- return token;
67
- };
68
- }
69
-
70
- function copy() {
71
- var _html = htmlParser.copy(), _local = localParser && localParser.copy(),
72
- _next = iter.next, _inTag = inTag;
73
- return function(_stream) {
74
- stream = _stream;
75
- htmlParser = _html(_stream);
76
- localParser = _local && _local(_stream);
77
- iter.next = _next;
78
- inTag = _inTag;
79
- return iter;
80
- };
81
- }
82
- return iter;
83
- }
84
-
85
- return {
86
- make: parseMixed,
87
- electricChars: "{}/:",
88
- configure: function(obj) {
89
- if (obj.triggers) triggers = obj.triggers;
90
- }
91
- };
92
-
93
- })();
@@ -1,359 +0,0 @@
1
- /* Parse function for JavaScript. Makes use of the tokenizer from
2
- * tokenizejavascript.js. Note that your parsers do not have to be
3
- * this complicated -- if you don't want to recognize local variables,
4
- * in many languages it is enough to just look for braces, semicolons,
5
- * parentheses, etc, and know when you are inside a string or comment.
6
- *
7
- * See manual.html for more info about the parser interface.
8
- */
9
-
10
- var JSParser = Editor.Parser = (function() {
11
- // Token types that can be considered to be atoms.
12
- var atomicTypes = {"atom": true, "number": true, "variable": true, "string": true, "regexp": true};
13
- // Setting that can be used to have JSON data indent properly.
14
- var json = false;
15
- // Constructor for the lexical context objects.
16
- function JSLexical(indented, column, type, align, prev, info) {
17
- // indentation at start of this line
18
- this.indented = indented;
19
- // column at which this scope was opened
20
- this.column = column;
21
- // type of scope ('vardef', 'stat' (statement), 'form' (special form), '[', '{', or '(')
22
- this.type = type;
23
- // '[', '{', or '(' blocks that have any text after their opening
24
- // character are said to be 'aligned' -- any lines below are
25
- // indented all the way to the opening character.
26
- if (align != null)
27
- this.align = align;
28
- // Parent scope, if any.
29
- this.prev = prev;
30
- this.info = info;
31
- }
32
-
33
- // My favourite JavaScript indentation rules.
34
- function indentJS(lexical) {
35
- return function(firstChars) {
36
- var firstChar = firstChars && firstChars.charAt(0), type = lexical.type;
37
- var closing = firstChar == type;
38
- if (type == "vardef")
39
- return lexical.indented + 4;
40
- else if (type == "form" && firstChar == "{")
41
- return lexical.indented;
42
- else if (type == "stat" || type == "form")
43
- return lexical.indented + indentUnit;
44
- else if (lexical.info == "switch" && !closing)
45
- return lexical.indented + (/^(?:case|default)\b/.test(firstChars) ? indentUnit : 2 * indentUnit);
46
- else if (lexical.align)
47
- return lexical.column - (closing ? 1 : 0);
48
- else
49
- return lexical.indented + (closing ? 0 : indentUnit);
50
- };
51
- }
52
-
53
- // The parser-iterator-producing function itself.
54
- function parseJS(input, basecolumn) {
55
- // Wrap the input in a token stream
56
- var tokens = tokenizeJavaScript(input);
57
- // The parser state. cc is a stack of actions that have to be
58
- // performed to finish the current statement. For example we might
59
- // know that we still need to find a closing parenthesis and a
60
- // semicolon. Actions at the end of the stack go first. It is
61
- // initialized with an infinitely looping action that consumes
62
- // whole statements.
63
- var cc = [json ? expressions : statements];
64
- // Context contains information about the current local scope, the
65
- // variables defined in that, and the scopes above it.
66
- var context = null;
67
- // The lexical scope, used mostly for indentation.
68
- var lexical = new JSLexical((basecolumn || 0) - indentUnit, 0, "block", false);
69
- // Current column, and the indentation at the start of the current
70
- // line. Used to create lexical scope objects.
71
- var column = 0;
72
- var indented = 0;
73
- // Variables which are used by the mark, cont, and pass functions
74
- // below to communicate with the driver loop in the 'next'
75
- // function.
76
- var consume, marked;
77
-
78
- // The iterator object.
79
- var parser = {next: next, copy: copy};
80
-
81
- function next(){
82
- // Start by performing any 'lexical' actions (adjusting the
83
- // lexical variable), or the operations below will be working
84
- // with the wrong lexical state.
85
- while(cc[cc.length - 1].lex)
86
- cc.pop()();
87
-
88
- // Fetch a token.
89
- var token = tokens.next();
90
-
91
- // Adjust column and indented.
92
- if (token.type == "whitespace" && column == 0)
93
- indented = token.value.length;
94
- column += token.value.length;
95
- if (token.content == "\n"){
96
- indented = column = 0;
97
- // If the lexical scope's align property is still undefined at
98
- // the end of the line, it is an un-aligned scope.
99
- if (!("align" in lexical))
100
- lexical.align = false;
101
- // Newline tokens get an indentation function associated with
102
- // them.
103
- token.indentation = indentJS(lexical);
104
- }
105
- // No more processing for meaningless tokens.
106
- if (token.type == "whitespace" || token.type == "comment")
107
- return token;
108
- // When a meaningful token is found and the lexical scope's
109
- // align is undefined, it is an aligned scope.
110
- if (!("align" in lexical))
111
- lexical.align = true;
112
-
113
- // Execute actions until one 'consumes' the token and we can
114
- // return it.
115
- while(true) {
116
- consume = marked = false;
117
- // Take and execute the topmost action.
118
- cc.pop()(token.type, token.content);
119
- if (consume){
120
- // Marked is used to change the style of the current token.
121
- if (marked)
122
- token.style = marked;
123
- // Here we differentiate between local and global variables.
124
- else if (token.type == "variable" && inScope(token.content))
125
- token.style = "js-localvariable";
126
- return token;
127
- }
128
- }
129
- }
130
-
131
- // This makes a copy of the parser state. It stores all the
132
- // stateful variables in a closure, and returns a function that
133
- // will restore them when called with a new input stream. Note
134
- // that the cc array has to be copied, because it is contantly
135
- // being modified. Lexical objects are not mutated, and context
136
- // objects are not mutated in a harmful way, so they can be shared
137
- // between runs of the parser.
138
- function copy(){
139
- var _context = context, _lexical = lexical, _cc = cc.concat([]), _tokenState = tokens.state;
140
-
141
- return function copyParser(input){
142
- context = _context;
143
- lexical = _lexical;
144
- cc = _cc.concat([]); // copies the array
145
- column = indented = 0;
146
- tokens = tokenizeJavaScript(input, _tokenState);
147
- return parser;
148
- };
149
- }
150
-
151
- // Helper function for pushing a number of actions onto the cc
152
- // stack in reverse order.
153
- function push(fs){
154
- for (var i = fs.length - 1; i >= 0; i--)
155
- cc.push(fs[i]);
156
- }
157
- // cont and pass are used by the action functions to add other
158
- // actions to the stack. cont will cause the current token to be
159
- // consumed, pass will leave it for the next action.
160
- function cont(){
161
- push(arguments);
162
- consume = true;
163
- }
164
- function pass(){
165
- push(arguments);
166
- consume = false;
167
- }
168
- // Used to change the style of the current token.
169
- function mark(style){
170
- marked = style;
171
- }
172
-
173
- // Push a new scope. Will automatically link the current scope.
174
- function pushcontext(){
175
- context = {prev: context, vars: {"this": true, "arguments": true}};
176
- }
177
- // Pop off the current scope.
178
- function popcontext(){
179
- context = context.prev;
180
- }
181
- // Register a variable in the current scope.
182
- function register(varname){
183
- if (context){
184
- mark("js-variabledef");
185
- context.vars[varname] = true;
186
- }
187
- }
188
- // Check whether a variable is defined in the current scope.
189
- function inScope(varname){
190
- var cursor = context;
191
- while (cursor) {
192
- if (cursor.vars[varname])
193
- return true;
194
- cursor = cursor.prev;
195
- }
196
- return false;
197
- }
198
-
199
- // Push a new lexical context of the given type.
200
- function pushlex(type, info) {
201
- var result = function(){
202
- lexical = new JSLexical(indented, column, type, null, lexical, info)
203
- };
204
- result.lex = true;
205
- return result;
206
- }
207
- // Pop off the current lexical context.
208
- function poplex(){
209
- if (lexical.type == ")")
210
- indented = lexical.indented;
211
- lexical = lexical.prev;
212
- }
213
- poplex.lex = true;
214
- // The 'lex' flag on these actions is used by the 'next' function
215
- // to know they can (and have to) be ran before moving on to the
216
- // next token.
217
-
218
- // Creates an action that discards tokens until it finds one of
219
- // the given type.
220
- function expect(wanted){
221
- return function expecting(type){
222
- if (type == wanted) cont();
223
- else if (wanted == ";") pass();
224
- else cont(arguments.callee);
225
- };
226
- }
227
-
228
- // Looks for a statement, and then calls itself.
229
- function statements(type){
230
- return pass(statement, statements);
231
- }
232
- function expressions(type){
233
- return pass(expression, expressions);
234
- }
235
- // Dispatches various types of statements based on the type of the
236
- // current token.
237
- function statement(type){
238
- if (type == "var") cont(pushlex("vardef"), vardef1, expect(";"), poplex);
239
- else if (type == "keyword a") cont(pushlex("form"), expression, statement, poplex);
240
- else if (type == "keyword b") cont(pushlex("form"), statement, poplex);
241
- else if (type == "{") cont(pushlex("}"), block, poplex);
242
- else if (type == ";") cont();
243
- else if (type == "function") cont(functiondef);
244
- else if (type == "for") cont(pushlex("form"), expect("("), pushlex(")"), forspec1, expect(")"), poplex, statement, poplex);
245
- else if (type == "variable") cont(pushlex("stat"), maybelabel);
246
- else if (type == "switch") cont(pushlex("form"), expression, pushlex("}", "switch"), expect("{"), block, poplex, poplex);
247
- else if (type == "case") cont(expression, expect(":"));
248
- else if (type == "default") cont(expect(":"));
249
- else if (type == "catch") cont(pushlex("form"), pushcontext, expect("("), funarg, expect(")"), statement, poplex, popcontext);
250
- else pass(pushlex("stat"), expression, expect(";"), poplex);
251
- }
252
- // Dispatch expression types.
253
- function expression(type){
254
- if (atomicTypes.hasOwnProperty(type)) cont(maybeoperator);
255
- else if (type == "function") cont(functiondef);
256
- else if (type == "keyword c") cont(expression);
257
- else if (type == "(") cont(pushlex(")"), expression, expect(")"), poplex, maybeoperator);
258
- else if (type == "operator") cont(expression);
259
- else if (type == "[") cont(pushlex("]"), commasep(expression, "]"), poplex, maybeoperator);
260
- else if (type == "{") cont(pushlex("}"), commasep(objprop, "}"), poplex, maybeoperator);
261
- else cont();
262
- }
263
- // Called for places where operators, function calls, or
264
- // subscripts are valid. Will skip on to the next action if none
265
- // is found.
266
- function maybeoperator(type, value){
267
- if (type == "operator" && /\+\+|--/.test(value)) cont(maybeoperator);
268
- else if (type == "operator") cont(expression);
269
- else if (type == ";") pass();
270
- else if (type == "(") cont(pushlex(")"), commasep(expression, ")"), poplex, maybeoperator);
271
- else if (type == ".") cont(property, maybeoperator);
272
- else if (type == "[") cont(pushlex("]"), expression, expect("]"), poplex, maybeoperator);
273
- }
274
- // When a statement starts with a variable name, it might be a
275
- // label. If no colon follows, it's a regular statement.
276
- function maybelabel(type){
277
- if (type == ":") cont(poplex, statement);
278
- else pass(maybeoperator, expect(";"), poplex);
279
- }
280
- // Property names need to have their style adjusted -- the
281
- // tokenizer thinks they are variables.
282
- function property(type){
283
- if (type == "variable") {mark("js-property"); cont();}
284
- }
285
- // This parses a property and its value in an object literal.
286
- function objprop(type){
287
- if (type == "variable") mark("js-property");
288
- if (atomicTypes.hasOwnProperty(type)) cont(expect(":"), expression);
289
- }
290
- // Parses a comma-separated list of the things that are recognized
291
- // by the 'what' argument.
292
- function commasep(what, end){
293
- function proceed(type) {
294
- if (type == ",") cont(what, proceed);
295
- else if (type == end) cont();
296
- else cont(expect(end));
297
- }
298
- return function commaSeparated(type) {
299
- if (type == end) cont();
300
- else pass(what, proceed);
301
- };
302
- }
303
- // Look for statements until a closing brace is found.
304
- function block(type){
305
- if (type == "}") cont();
306
- else pass(statement, block);
307
- }
308
- // Variable definitions are split into two actions -- 1 looks for
309
- // a name or the end of the definition, 2 looks for an '=' sign or
310
- // a comma.
311
- function vardef1(type, value){
312
- if (type == "variable"){register(value); cont(vardef2);}
313
- else cont();
314
- }
315
- function vardef2(type, value){
316
- if (value == "=") cont(expression, vardef2);
317
- else if (type == ",") cont(vardef1);
318
- }
319
- // For loops.
320
- function forspec1(type){
321
- if (type == "var") cont(vardef1, forspec2);
322
- else if (type == ";") pass(forspec2);
323
- else if (type == "variable") cont(formaybein);
324
- else pass(forspec2);
325
- }
326
- function formaybein(type, value){
327
- if (value == "in") cont(expression);
328
- else cont(maybeoperator, forspec2);
329
- }
330
- function forspec2(type, value){
331
- if (type == ";") cont(forspec3);
332
- else if (value == "in") cont(expression);
333
- else cont(expression, expect(";"), forspec3);
334
- }
335
- function forspec3(type) {
336
- if (type == ")") pass();
337
- else cont(expression);
338
- }
339
- // A function definition creates a new context, and the variables
340
- // in its argument list have to be added to this context.
341
- function functiondef(type, value){
342
- if (type == "variable"){register(value); cont(functiondef);}
343
- else if (type == "(") cont(pushcontext, commasep(funarg, ")"), statement, popcontext);
344
- }
345
- function funarg(type, value){
346
- if (type == "variable"){register(value); cont();}
347
- }
348
-
349
- return parser;
350
- }
351
-
352
- return {
353
- make: parseJS,
354
- electricChars: "{}:",
355
- configure: function(obj) {
356
- if (obj.json != null) json = obj.json;
357
- }
358
- };
359
- })();