ledger_web 1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (128) hide show
  1. data/.gitignore +10 -0
  2. data/LICENSE +7 -0
  3. data/README.md +140 -0
  4. data/Rakefile +11 -0
  5. data/bin/ledger_web +14 -0
  6. data/ledger_web.gemspec +26 -0
  7. data/lib/ledger_web/app.rb +69 -0
  8. data/lib/ledger_web/config.rb +87 -0
  9. data/lib/ledger_web/db/migrate/20111226180900_initial_schema.rb +38 -0
  10. data/lib/ledger_web/db/migrate/20111231132900_add_views.rb +37 -0
  11. data/lib/ledger_web/db.rb +54 -0
  12. data/lib/ledger_web/helpers.rb +62 -0
  13. data/lib/ledger_web/public/bootstrap-dropdown.js +55 -0
  14. data/lib/ledger_web/public/bootstrap.min.css +356 -0
  15. data/lib/ledger_web/public/codemirror/keymap/emacs.js +29 -0
  16. data/lib/ledger_web/public/codemirror/keymap/vim.js +76 -0
  17. data/lib/ledger_web/public/codemirror/lib/codemirror.css +104 -0
  18. data/lib/ledger_web/public/codemirror/lib/codemirror.js +2761 -0
  19. data/lib/ledger_web/public/codemirror/lib/util/dialog.css +23 -0
  20. data/lib/ledger_web/public/codemirror/lib/util/dialog.js +63 -0
  21. data/lib/ledger_web/public/codemirror/lib/util/foldcode.js +66 -0
  22. data/lib/ledger_web/public/codemirror/lib/util/formatting.js +291 -0
  23. data/lib/ledger_web/public/codemirror/lib/util/javascript-hint.js +83 -0
  24. data/lib/ledger_web/public/codemirror/lib/util/overlay.js +51 -0
  25. data/lib/ledger_web/public/codemirror/lib/util/runmode.js +27 -0
  26. data/lib/ledger_web/public/codemirror/lib/util/search.js +114 -0
  27. data/lib/ledger_web/public/codemirror/lib/util/searchcursor.js +117 -0
  28. data/lib/ledger_web/public/codemirror/lib/util/simple-hint.css +16 -0
  29. data/lib/ledger_web/public/codemirror/lib/util/simple-hint.js +66 -0
  30. data/lib/ledger_web/public/codemirror/mode/clike/clike.js +249 -0
  31. data/lib/ledger_web/public/codemirror/mode/clike/index.html +101 -0
  32. data/lib/ledger_web/public/codemirror/mode/clojure/clojure.js +207 -0
  33. data/lib/ledger_web/public/codemirror/mode/clojure/index.html +66 -0
  34. data/lib/ledger_web/public/codemirror/mode/coffeescript/LICENSE +22 -0
  35. data/lib/ledger_web/public/codemirror/mode/coffeescript/coffeescript.js +325 -0
  36. data/lib/ledger_web/public/codemirror/mode/coffeescript/index.html +721 -0
  37. data/lib/ledger_web/public/codemirror/mode/css/css.js +124 -0
  38. data/lib/ledger_web/public/codemirror/mode/css/index.html +55 -0
  39. data/lib/ledger_web/public/codemirror/mode/diff/diff.css +3 -0
  40. data/lib/ledger_web/public/codemirror/mode/diff/diff.js +13 -0
  41. data/lib/ledger_web/public/codemirror/mode/diff/index.html +99 -0
  42. data/lib/ledger_web/public/codemirror/mode/gfm/gfm.js +108 -0
  43. data/lib/ledger_web/public/codemirror/mode/gfm/index.html +47 -0
  44. data/lib/ledger_web/public/codemirror/mode/groovy/groovy.js +210 -0
  45. data/lib/ledger_web/public/codemirror/mode/groovy/index.html +71 -0
  46. data/lib/ledger_web/public/codemirror/mode/haskell/haskell.js +242 -0
  47. data/lib/ledger_web/public/codemirror/mode/haskell/index.html +60 -0
  48. data/lib/ledger_web/public/codemirror/mode/htmlembedded/htmlembedded.js +68 -0
  49. data/lib/ledger_web/public/codemirror/mode/htmlembedded/index.html +49 -0
  50. data/lib/ledger_web/public/codemirror/mode/htmlmixed/htmlmixed.js +83 -0
  51. data/lib/ledger_web/public/codemirror/mode/htmlmixed/index.html +51 -0
  52. data/lib/ledger_web/public/codemirror/mode/javascript/index.html +77 -0
  53. data/lib/ledger_web/public/codemirror/mode/javascript/javascript.js +360 -0
  54. data/lib/ledger_web/public/codemirror/mode/jinja2/index.html +37 -0
  55. data/lib/ledger_web/public/codemirror/mode/jinja2/jinja2.js +42 -0
  56. data/lib/ledger_web/public/codemirror/mode/lua/index.html +72 -0
  57. data/lib/ledger_web/public/codemirror/mode/lua/lua.js +140 -0
  58. data/lib/ledger_web/public/codemirror/mode/markdown/index.html +339 -0
  59. data/lib/ledger_web/public/codemirror/mode/markdown/markdown.js +242 -0
  60. data/lib/ledger_web/public/codemirror/mode/ntriples/index.html +32 -0
  61. data/lib/ledger_web/public/codemirror/mode/ntriples/ntriples.js +172 -0
  62. data/lib/ledger_web/public/codemirror/mode/pascal/LICENSE +7 -0
  63. data/lib/ledger_web/public/codemirror/mode/pascal/index.html +48 -0
  64. data/lib/ledger_web/public/codemirror/mode/pascal/pascal.js +138 -0
  65. data/lib/ledger_web/public/codemirror/mode/perl/LICENSE +19 -0
  66. data/lib/ledger_web/public/codemirror/mode/perl/index.html +62 -0
  67. data/lib/ledger_web/public/codemirror/mode/perl/perl.js +816 -0
  68. data/lib/ledger_web/public/codemirror/mode/php/index.html +48 -0
  69. data/lib/ledger_web/public/codemirror/mode/php/php.js +120 -0
  70. data/lib/ledger_web/public/codemirror/mode/plsql/index.html +62 -0
  71. data/lib/ledger_web/public/codemirror/mode/plsql/plsql.js +217 -0
  72. data/lib/ledger_web/public/codemirror/mode/python/LICENSE.txt +21 -0
  73. data/lib/ledger_web/public/codemirror/mode/python/index.html +122 -0
  74. data/lib/ledger_web/public/codemirror/mode/python/python.js +333 -0
  75. data/lib/ledger_web/public/codemirror/mode/r/LICENSE +24 -0
  76. data/lib/ledger_web/public/codemirror/mode/r/index.html +73 -0
  77. data/lib/ledger_web/public/codemirror/mode/r/r.js +141 -0
  78. data/lib/ledger_web/public/codemirror/mode/rpm/changes/changes.js +19 -0
  79. data/lib/ledger_web/public/codemirror/mode/rpm/changes/index.html +53 -0
  80. data/lib/ledger_web/public/codemirror/mode/rpm/spec/index.html +99 -0
  81. data/lib/ledger_web/public/codemirror/mode/rpm/spec/spec.css +5 -0
  82. data/lib/ledger_web/public/codemirror/mode/rpm/spec/spec.js +66 -0
  83. data/lib/ledger_web/public/codemirror/mode/rst/index.html +525 -0
  84. data/lib/ledger_web/public/codemirror/mode/rst/rst.js +326 -0
  85. data/lib/ledger_web/public/codemirror/mode/ruby/LICENSE +24 -0
  86. data/lib/ledger_web/public/codemirror/mode/ruby/index.html +171 -0
  87. data/lib/ledger_web/public/codemirror/mode/ruby/ruby.js +195 -0
  88. data/lib/ledger_web/public/codemirror/mode/rust/index.html +48 -0
  89. data/lib/ledger_web/public/codemirror/mode/rust/rust.js +411 -0
  90. data/lib/ledger_web/public/codemirror/mode/scheme/index.html +64 -0
  91. data/lib/ledger_web/public/codemirror/mode/scheme/scheme.js +202 -0
  92. data/lib/ledger_web/public/codemirror/mode/smalltalk/index.html +55 -0
  93. data/lib/ledger_web/public/codemirror/mode/smalltalk/smalltalk.js +139 -0
  94. data/lib/ledger_web/public/codemirror/mode/sparql/index.html +40 -0
  95. data/lib/ledger_web/public/codemirror/mode/sparql/sparql.js +143 -0
  96. data/lib/ledger_web/public/codemirror/mode/stex/index.html +95 -0
  97. data/lib/ledger_web/public/codemirror/mode/stex/stex.js +167 -0
  98. data/lib/ledger_web/public/codemirror/mode/tiddlywiki/index.html +183 -0
  99. data/lib/ledger_web/public/codemirror/mode/tiddlywiki/tiddlywiki.css +21 -0
  100. data/lib/ledger_web/public/codemirror/mode/tiddlywiki/tiddlywiki.js +374 -0
  101. data/lib/ledger_web/public/codemirror/mode/velocity/index.html +103 -0
  102. data/lib/ledger_web/public/codemirror/mode/velocity/velocity.js +146 -0
  103. data/lib/ledger_web/public/codemirror/mode/xml/index.html +44 -0
  104. data/lib/ledger_web/public/codemirror/mode/xml/xml.js +252 -0
  105. data/lib/ledger_web/public/codemirror/mode/xmlpure/index.html +59 -0
  106. data/lib/ledger_web/public/codemirror/mode/xmlpure/xmlpure.js +485 -0
  107. data/lib/ledger_web/public/codemirror/mode/yaml/index.html +67 -0
  108. data/lib/ledger_web/public/codemirror/mode/yaml/yaml.js +95 -0
  109. data/lib/ledger_web/public/codemirror/theme/cobalt.css +18 -0
  110. data/lib/ledger_web/public/codemirror/theme/eclipse.css +25 -0
  111. data/lib/ledger_web/public/codemirror/theme/elegant.css +10 -0
  112. data/lib/ledger_web/public/codemirror/theme/monokai.css +28 -0
  113. data/lib/ledger_web/public/codemirror/theme/neat.css +9 -0
  114. data/lib/ledger_web/public/codemirror/theme/night.css +21 -0
  115. data/lib/ledger_web/public/codemirror/theme/rubyblue.css +21 -0
  116. data/lib/ledger_web/public/jquery-1.7.1.min.js +4 -0
  117. data/lib/ledger_web/public/jquery.tablesorter.min.js +4 -0
  118. data/lib/ledger_web/public/ledger.css +14 -0
  119. data/lib/ledger_web/report.rb +187 -0
  120. data/lib/ledger_web/reports/savings_rate.erb +49 -0
  121. data/lib/ledger_web/version.rb +3 -0
  122. data/lib/ledger_web/views/error.erb +5 -0
  123. data/lib/ledger_web/views/help.erb +6 -0
  124. data/lib/ledger_web/views/layout.erb +44 -0
  125. data/lib/ledger_web/views/table.erb +31 -0
  126. data/lib/ledger_web/watcher.rb +37 -0
  127. data/lib/ledger_web.rb +20 -0
  128. metadata +229 -0
@@ -0,0 +1,23 @@
1
+ .CodeMirror-dialog {
2
+ position: relative;
3
+ }
4
+
5
+ .CodeMirror-dialog > div {
6
+ position: absolute;
7
+ top: 0; left: 0; right: 0;
8
+ background: white;
9
+ border-bottom: 1px solid #eee;
10
+ z-index: 15;
11
+ padding: .1em .8em;
12
+ overflow: hidden;
13
+ color: #333;
14
+ }
15
+
16
+ .CodeMirror-dialog input {
17
+ border: none;
18
+ outline: none;
19
+ background: transparent;
20
+ width: 20em;
21
+ color: inherit;
22
+ font-family: monospace;
23
+ }
@@ -0,0 +1,63 @@
1
+ // Open simple dialogs on top of an editor. Relies on dialog.css.
2
+
3
+ (function() {
4
+ function dialogDiv(cm, template) {
5
+ var wrap = cm.getWrapperElement();
6
+ var dialog = wrap.insertBefore(document.createElement("div"), wrap.firstChild);
7
+ dialog.className = "CodeMirror-dialog";
8
+ dialog.innerHTML = '<div>' + template + '</div>';
9
+ return dialog;
10
+ }
11
+
12
+ CodeMirror.defineExtension("openDialog", function(template, callback) {
13
+ var dialog = dialogDiv(this, template);
14
+ var closed = false, me = this;
15
+ function close() {
16
+ if (closed) return;
17
+ closed = true;
18
+ dialog.parentNode.removeChild(dialog);
19
+ }
20
+ var inp = dialog.getElementsByTagName("input")[0];
21
+ if (inp) {
22
+ CodeMirror.connect(inp, "keydown", function(e) {
23
+ if (e.keyCode == 13 || e.keyCode == 27) {
24
+ CodeMirror.e_stop(e);
25
+ close();
26
+ me.focus();
27
+ if (e.keyCode == 13) callback(inp.value);
28
+ }
29
+ });
30
+ inp.focus();
31
+ CodeMirror.connect(inp, "blur", close);
32
+ }
33
+ return close;
34
+ });
35
+
36
+ CodeMirror.defineExtension("openConfirm", function(template, callbacks) {
37
+ var dialog = dialogDiv(this, template);
38
+ var buttons = dialog.getElementsByTagName("button");
39
+ var closed = false, me = this, blurring = 1;
40
+ function close() {
41
+ if (closed) return;
42
+ closed = true;
43
+ dialog.parentNode.removeChild(dialog);
44
+ me.focus();
45
+ }
46
+ buttons[0].focus();
47
+ for (var i = 0; i < buttons.length; ++i) {
48
+ var b = buttons[i];
49
+ (function(callback) {
50
+ CodeMirror.connect(b, "click", function(e) {
51
+ CodeMirror.e_preventDefault(e);
52
+ close();
53
+ if (callback) callback(me);
54
+ });
55
+ })(callbacks[i]);
56
+ CodeMirror.connect(b, "blur", function() {
57
+ --blurring;
58
+ setTimeout(function() { if (blurring <= 0) close(); }, 200);
59
+ });
60
+ CodeMirror.connect(b, "focus", function() { ++blurring; });
61
+ }
62
+ });
63
+ })();
@@ -0,0 +1,66 @@
1
+ CodeMirror.braceRangeFinder = function(cm, line) {
2
+ var lineText = cm.getLine(line);
3
+ var startChar = lineText.lastIndexOf("{");
4
+ if (startChar < 0 || lineText.lastIndexOf("}") > startChar) return;
5
+ var tokenType = cm.getTokenAt({line: line, ch: startChar}).className;
6
+ var count = 1, lastLine = cm.lineCount(), end;
7
+ outer: for (var i = line + 1; i < lastLine; ++i) {
8
+ var text = cm.getLine(i), pos = 0;
9
+ for (;;) {
10
+ var nextOpen = text.indexOf("{", pos), nextClose = text.indexOf("}", pos);
11
+ if (nextOpen < 0) nextOpen = text.length;
12
+ if (nextClose < 0) nextClose = text.length;
13
+ pos = Math.min(nextOpen, nextClose);
14
+ if (pos == text.length) break;
15
+ if (cm.getTokenAt({line: i, ch: pos + 1}).className == tokenType) {
16
+ if (pos == nextOpen) ++count;
17
+ else if (!--count) { end = i; break outer; }
18
+ }
19
+ ++pos;
20
+ }
21
+ }
22
+ if (end == null || end == line + 1) return;
23
+ return end;
24
+ };
25
+
26
+
27
+ CodeMirror.newFoldFunction = function(rangeFinder, markText) {
28
+ var folded = [];
29
+ if (markText == null) markText = '<div style="position: absolute; left: 2px; color:#600">&#x25bc;</div>%N%';
30
+
31
+ function isFolded(cm, n) {
32
+ for (var i = 0; i < folded.length; ++i) {
33
+ var start = cm.lineInfo(folded[i].start);
34
+ if (!start) folded.splice(i--, 1);
35
+ else if (start.line == n) return {pos: i, region: folded[i]};
36
+ }
37
+ }
38
+
39
+ function expand(cm, region) {
40
+ cm.clearMarker(region.start);
41
+ for (var i = 0; i < region.hidden.length; ++i)
42
+ cm.showLine(region.hidden[i]);
43
+ }
44
+
45
+ return function(cm, line) {
46
+ cm.operation(function() {
47
+ var known = isFolded(cm, line);
48
+ if (known) {
49
+ folded.splice(known.pos, 1);
50
+ expand(cm, known.region);
51
+ } else {
52
+ var end = rangeFinder(cm, line);
53
+ if (end == null) return;
54
+ var hidden = [];
55
+ for (var i = line + 1; i < end; ++i) {
56
+ var handle = cm.hideLine(i);
57
+ if (handle) hidden.push(handle);
58
+ }
59
+ var first = cm.setMarker(line, markText);
60
+ var region = {start: first, hidden: hidden};
61
+ cm.onDeleteLine(first, function() { expand(cm, region); });
62
+ folded.push(region);
63
+ }
64
+ });
65
+ };
66
+ };
@@ -0,0 +1,291 @@
1
+ // ============== Formatting extensions ============================
2
+ // A common storage for all mode-specific formatting features
3
+ if (!CodeMirror.modeExtensions) CodeMirror.modeExtensions = {};
4
+
5
+ // Returns the extension of the editor's current mode
6
+ CodeMirror.defineExtension("getModeExt", function () {
7
+ return CodeMirror.modeExtensions[this.getOption("mode")];
8
+ });
9
+
10
+ // If the current mode is 'htmlmixed', returns the extension of a mode located at
11
+ // the specified position (can be htmlmixed, css or javascript). Otherwise, simply
12
+ // returns the extension of the editor's current mode.
13
+ CodeMirror.defineExtension("getModeExtAtPos", function (pos) {
14
+ var token = this.getTokenAt(pos);
15
+ if (token && token.state && token.state.mode)
16
+ return CodeMirror.modeExtensions[token.state.mode == "html" ? "htmlmixed" : token.state.mode];
17
+ else
18
+ return this.getModeExt();
19
+ });
20
+
21
+ // Comment/uncomment the specified range
22
+ CodeMirror.defineExtension("commentRange", function (isComment, from, to) {
23
+ var curMode = this.getModeExtAtPos(this.getCursor());
24
+ if (isComment) { // Comment range
25
+ var commentedText = this.getRange(from, to);
26
+ this.replaceRange(curMode.commentStart + this.getRange(from, to) + curMode.commentEnd
27
+ , from, to);
28
+ if (from.line == to.line && from.ch == to.ch) { // An empty comment inserted - put cursor inside
29
+ this.setCursor(from.line, from.ch + curMode.commentStart.length);
30
+ }
31
+ }
32
+ else { // Uncomment range
33
+ var selText = this.getRange(from, to);
34
+ var startIndex = selText.indexOf(curMode.commentStart);
35
+ var endIndex = selText.lastIndexOf(curMode.commentEnd);
36
+ if (startIndex > -1 && endIndex > -1 && endIndex > startIndex) {
37
+ // Take string till comment start
38
+ selText = selText.substr(0, startIndex)
39
+ // From comment start till comment end
40
+ + selText.substring(startIndex + curMode.commentStart.length, endIndex)
41
+ // From comment end till string end
42
+ + selText.substr(endIndex + curMode.commentEnd.length);
43
+ }
44
+ this.replaceRange(selText, from, to);
45
+ }
46
+ });
47
+
48
+ // Applies automatic mode-aware indentation to the specified range
49
+ CodeMirror.defineExtension("autoIndentRange", function (from, to) {
50
+ var cmInstance = this;
51
+ this.operation(function () {
52
+ for (var i = from.line; i <= to.line; i++) {
53
+ cmInstance.indentLine(i);
54
+ }
55
+ });
56
+ });
57
+
58
+ // Applies automatic formatting to the specified range
59
+ CodeMirror.defineExtension("autoFormatRange", function (from, to) {
60
+ var absStart = this.indexFromPos(from);
61
+ var absEnd = this.indexFromPos(to);
62
+ // Insert additional line breaks where necessary according to the
63
+ // mode's syntax
64
+ var res = this.getModeExt().autoFormatLineBreaks(this.getValue(), absStart, absEnd);
65
+ var cmInstance = this;
66
+
67
+ // Replace and auto-indent the range
68
+ this.operation(function () {
69
+ cmInstance.replaceRange(res, from, to);
70
+ var startLine = cmInstance.posFromIndex(absStart).line;
71
+ var endLine = cmInstance.posFromIndex(absStart + res.length).line;
72
+ for (var i = startLine; i <= endLine; i++) {
73
+ cmInstance.indentLine(i);
74
+ }
75
+ });
76
+ });
77
+
78
+ // Define extensions for a few modes
79
+
80
+ CodeMirror.modeExtensions["css"] = {
81
+ commentStart: "/*",
82
+ commentEnd: "*/",
83
+ wordWrapChars: [";", "\\{", "\\}"],
84
+ autoFormatLineBreaks: function (text) {
85
+ return text.replace(new RegExp("(;|\\{|\\})([^\r\n])", "g"), "$1\n$2");
86
+ }
87
+ };
88
+
89
+ CodeMirror.modeExtensions["javascript"] = {
90
+ commentStart: "/*",
91
+ commentEnd: "*/",
92
+ wordWrapChars: [";", "\\{", "\\}"],
93
+
94
+ getNonBreakableBlocks: function (text) {
95
+ var nonBreakableRegexes = [
96
+ new RegExp("for\\s*?\\(([\\s\\S]*?)\\)"),
97
+ new RegExp("'([\\s\\S]*?)('|$)"),
98
+ new RegExp("\"([\\s\\S]*?)(\"|$)"),
99
+ new RegExp("//.*([\r\n]|$)")
100
+ ];
101
+ var nonBreakableBlocks = new Array();
102
+ for (var i = 0; i < nonBreakableRegexes.length; i++) {
103
+ var curPos = 0;
104
+ while (curPos < text.length) {
105
+ var m = text.substr(curPos).match(nonBreakableRegexes[i]);
106
+ if (m != null) {
107
+ nonBreakableBlocks.push({
108
+ start: curPos + m.index,
109
+ end: curPos + m.index + m[0].length
110
+ });
111
+ curPos += m.index + Math.max(1, m[0].length);
112
+ }
113
+ else { // No more matches
114
+ break;
115
+ }
116
+ }
117
+ }
118
+ nonBreakableBlocks.sort(function (a, b) {
119
+ return a.start - b.start;
120
+ });
121
+
122
+ return nonBreakableBlocks;
123
+ },
124
+
125
+ autoFormatLineBreaks: function (text) {
126
+ var curPos = 0;
127
+ var reLinesSplitter = new RegExp("(;|\\{|\\})([^\r\n])", "g");
128
+ var nonBreakableBlocks = this.getNonBreakableBlocks(text);
129
+ if (nonBreakableBlocks != null) {
130
+ var res = "";
131
+ for (var i = 0; i < nonBreakableBlocks.length; i++) {
132
+ if (nonBreakableBlocks[i].start > curPos) { // Break lines till the block
133
+ res += text.substring(curPos, nonBreakableBlocks[i].start).replace(reLinesSplitter, "$1\n$2");
134
+ curPos = nonBreakableBlocks[i].start;
135
+ }
136
+ if (nonBreakableBlocks[i].start <= curPos
137
+ && nonBreakableBlocks[i].end >= curPos) { // Skip non-breakable block
138
+ res += text.substring(curPos, nonBreakableBlocks[i].end);
139
+ curPos = nonBreakableBlocks[i].end;
140
+ }
141
+ }
142
+ if (curPos < text.length - 1) {
143
+ res += text.substr(curPos).replace(reLinesSplitter, "$1\n$2");
144
+ }
145
+ return res;
146
+ }
147
+ else {
148
+ return text.replace(reLinesSplitter, "$1\n$2");
149
+ }
150
+ }
151
+ };
152
+
153
+ CodeMirror.modeExtensions["xml"] = {
154
+ commentStart: "<!--",
155
+ commentEnd: "-->",
156
+ wordWrapChars: [">"],
157
+
158
+ autoFormatLineBreaks: function (text) {
159
+ var lines = text.split("\n");
160
+ var reProcessedPortion = new RegExp("(^\\s*?<|^[^<]*?)(.+)(>\\s*?$|[^>]*?$)");
161
+ var reOpenBrackets = new RegExp("<", "g");
162
+ var reCloseBrackets = new RegExp("(>)([^\r\n])", "g");
163
+ for (var i = 0; i < lines.length; i++) {
164
+ var mToProcess = lines[i].match(reProcessedPortion);
165
+ if (mToProcess != null && mToProcess.length > 3) { // The line starts with whitespaces and ends with whitespaces
166
+ lines[i] = mToProcess[1]
167
+ + mToProcess[2].replace(reOpenBrackets, "\n$&").replace(reCloseBrackets, "$1\n$2")
168
+ + mToProcess[3];
169
+ continue;
170
+ }
171
+ }
172
+
173
+ return lines.join("\n");
174
+ }
175
+ };
176
+
177
+ CodeMirror.modeExtensions["htmlmixed"] = {
178
+ commentStart: "<!--",
179
+ commentEnd: "-->",
180
+ wordWrapChars: [">", ";", "\\{", "\\}"],
181
+
182
+ getModeInfos: function (text, absPos) {
183
+ var modeInfos = new Array();
184
+ modeInfos[0] =
185
+ {
186
+ pos: 0,
187
+ modeExt: CodeMirror.modeExtensions["xml"],
188
+ modeName: "xml"
189
+ };
190
+
191
+ var modeMatchers = new Array();
192
+ modeMatchers[0] =
193
+ {
194
+ regex: new RegExp("<style[^>]*>([\\s\\S]*?)(</style[^>]*>|$)", "i"),
195
+ modeExt: CodeMirror.modeExtensions["css"],
196
+ modeName: "css"
197
+ };
198
+ modeMatchers[1] =
199
+ {
200
+ regex: new RegExp("<script[^>]*>([\\s\\S]*?)(</script[^>]*>|$)", "i"),
201
+ modeExt: CodeMirror.modeExtensions["javascript"],
202
+ modeName: "javascript"
203
+ };
204
+
205
+ var lastCharPos = (typeof (absPos) !== "undefined" ? absPos : text.length - 1);
206
+ // Detect modes for the entire text
207
+ for (var i = 0; i < modeMatchers.length; i++) {
208
+ var curPos = 0;
209
+ while (curPos <= lastCharPos) {
210
+ var m = text.substr(curPos).match(modeMatchers[i].regex);
211
+ if (m != null) {
212
+ if (m.length > 1 && m[1].length > 0) {
213
+ // Push block begin pos
214
+ var blockBegin = curPos + m.index + m[0].indexOf(m[1]);
215
+ modeInfos.push(
216
+ {
217
+ pos: blockBegin,
218
+ modeExt: modeMatchers[i].modeExt,
219
+ modeName: modeMatchers[i].modeName
220
+ });
221
+ // Push block end pos
222
+ modeInfos.push(
223
+ {
224
+ pos: blockBegin + m[1].length,
225
+ modeExt: modeInfos[0].modeExt,
226
+ modeName: modeInfos[0].modeName
227
+ });
228
+ curPos += m.index + m[0].length;
229
+ continue;
230
+ }
231
+ else {
232
+ curPos += m.index + Math.max(m[0].length, 1);
233
+ }
234
+ }
235
+ else { // No more matches
236
+ break;
237
+ }
238
+ }
239
+ }
240
+ // Sort mode infos
241
+ modeInfos.sort(function sortModeInfo(a, b) {
242
+ return a.pos - b.pos;
243
+ });
244
+
245
+ return modeInfos;
246
+ },
247
+
248
+ autoFormatLineBreaks: function (text, startPos, endPos) {
249
+ var modeInfos = this.getModeInfos(text);
250
+ var reBlockStartsWithNewline = new RegExp("^\\s*?\n");
251
+ var reBlockEndsWithNewline = new RegExp("\n\\s*?$");
252
+ var res = "";
253
+ // Use modes info to break lines correspondingly
254
+ if (modeInfos.length > 1) { // Deal with multi-mode text
255
+ for (var i = 1; i <= modeInfos.length; i++) {
256
+ var selStart = modeInfos[i - 1].pos;
257
+ var selEnd = (i < modeInfos.length ? modeInfos[i].pos : endPos);
258
+
259
+ if (selStart >= endPos) { // The block starts later than the needed fragment
260
+ break;
261
+ }
262
+ if (selStart < startPos) {
263
+ if (selEnd <= startPos) { // The block starts earlier than the needed fragment
264
+ continue;
265
+ }
266
+ selStart = startPos;
267
+ }
268
+ if (selEnd > endPos) {
269
+ selEnd = endPos;
270
+ }
271
+ var textPortion = text.substring(selStart, selEnd);
272
+ if (modeInfos[i - 1].modeName != "xml") { // Starting a CSS or JavaScript block
273
+ if (!reBlockStartsWithNewline.test(textPortion)
274
+ && selStart > 0) { // The block does not start with a line break
275
+ textPortion = "\n" + textPortion;
276
+ }
277
+ if (!reBlockEndsWithNewline.test(textPortion)
278
+ && selEnd < text.length - 1) { // The block does not end with a line break
279
+ textPortion += "\n";
280
+ }
281
+ }
282
+ res += modeInfos[i - 1].modeExt.autoFormatLineBreaks(textPortion);
283
+ }
284
+ }
285
+ else { // Single-mode text
286
+ res = modeInfos[0].modeExt.autoFormatLineBreaks(text.substring(startPos, endPos));
287
+ }
288
+
289
+ return res;
290
+ }
291
+ };
@@ -0,0 +1,83 @@
1
+ (function () {
2
+ function forEach(arr, f) {
3
+ for (var i = 0, e = arr.length; i < e; ++i) f(arr[i]);
4
+ }
5
+
6
+ function arrayContains(arr, item) {
7
+ if (!Array.prototype.indexOf) {
8
+ var i = arr.length;
9
+ while (i--) {
10
+ if (arr[i] === item) {
11
+ return true;
12
+ }
13
+ }
14
+ return false;
15
+ }
16
+ return arr.indexOf(item) != -1;
17
+ }
18
+
19
+ CodeMirror.javascriptHint = function(editor) {
20
+ // Find the token at the cursor
21
+ var cur = editor.getCursor(), token = editor.getTokenAt(cur), tprop = token;
22
+ // If it's not a 'word-style' token, ignore the token.
23
+ if (!/^[\w$_]*$/.test(token.string)) {
24
+ token = tprop = {start: cur.ch, end: cur.ch, string: "", state: token.state,
25
+ className: token.string == "." ? "property" : null};
26
+ }
27
+ // If it is a property, find out what it is a property of.
28
+ while (tprop.className == "property") {
29
+ tprop = editor.getTokenAt({line: cur.line, ch: tprop.start});
30
+ if (tprop.string != ".") return;
31
+ tprop = editor.getTokenAt({line: cur.line, ch: tprop.start});
32
+ if (!context) var context = [];
33
+ context.push(tprop);
34
+ }
35
+ return {list: getCompletions(token, context),
36
+ from: {line: cur.line, ch: token.start},
37
+ to: {line: cur.line, ch: token.end}};
38
+ }
39
+
40
+ var stringProps = ("charAt charCodeAt indexOf lastIndexOf substring substr slice trim trimLeft trimRight " +
41
+ "toUpperCase toLowerCase split concat match replace search").split(" ");
42
+ var arrayProps = ("length concat join splice push pop shift unshift slice reverse sort indexOf " +
43
+ "lastIndexOf every some filter forEach map reduce reduceRight ").split(" ");
44
+ var funcProps = "prototype apply call bind".split(" ");
45
+ var keywords = ("break case catch continue debugger default delete do else false finally for function " +
46
+ "if in instanceof new null return switch throw true try typeof var void while with").split(" ");
47
+
48
+ function getCompletions(token, context) {
49
+ var found = [], start = token.string;
50
+ function maybeAdd(str) {
51
+ if (str.indexOf(start) == 0 && !arrayContains(found, str)) found.push(str);
52
+ }
53
+ function gatherCompletions(obj) {
54
+ if (typeof obj == "string") forEach(stringProps, maybeAdd);
55
+ else if (obj instanceof Array) forEach(arrayProps, maybeAdd);
56
+ else if (obj instanceof Function) forEach(funcProps, maybeAdd);
57
+ for (var name in obj) maybeAdd(name);
58
+ }
59
+
60
+ if (context) {
61
+ // If this is a property, see if it belongs to some object we can
62
+ // find in the current environment.
63
+ var obj = context.pop(), base;
64
+ if (obj.className == "variable")
65
+ base = window[obj.string];
66
+ else if (obj.className == "string")
67
+ base = "";
68
+ else if (obj.className == "atom")
69
+ base = 1;
70
+ while (base != null && context.length)
71
+ base = base[context.pop().string];
72
+ if (base != null) gatherCompletions(base);
73
+ }
74
+ else {
75
+ // If not, just look in the window object and any local scope
76
+ // (reading into JS mode internals to get at the local variables)
77
+ for (var v = token.state.localVars; v; v = v.next) maybeAdd(v.name);
78
+ gatherCompletions(window);
79
+ forEach(keywords, maybeAdd);
80
+ }
81
+ return found;
82
+ }
83
+ })();
@@ -0,0 +1,51 @@
1
+ // Utility function that allows modes to be combined. The mode given
2
+ // as the base argument takes care of most of the normal mode
3
+ // functionality, but a second (typically simple) mode is used, which
4
+ // can override the style of text. Both modes get to parse all of the
5
+ // text, but when both assign a non-null style to a piece of code, the
6
+ // overlay wins, unless the combine argument was true, in which case
7
+ // the styles are combined.
8
+
9
+ CodeMirror.overlayParser = function(base, overlay, combine) {
10
+ return {
11
+ startState: function() {
12
+ return {
13
+ base: CodeMirror.startState(base),
14
+ overlay: CodeMirror.startState(overlay),
15
+ basePos: 0, baseCur: null,
16
+ overlayPos: 0, overlayCur: null
17
+ };
18
+ },
19
+ copyState: function(state) {
20
+ return {
21
+ base: CodeMirror.copyState(base, state.base),
22
+ overlay: CodeMirror.copyState(overlay, state.overlay),
23
+ basePos: state.basePos, baseCur: null,
24
+ overlayPos: state.overlayPos, overlayCur: null
25
+ };
26
+ },
27
+
28
+ token: function(stream, state) {
29
+ if (stream.start == state.basePos) {
30
+ state.baseCur = base.token(stream, state.base);
31
+ state.basePos = stream.pos;
32
+ }
33
+ if (stream.start == state.overlayPos) {
34
+ stream.pos = stream.start;
35
+ state.overlayCur = overlay.token(stream, state.overlay);
36
+ state.overlayPos = stream.pos;
37
+ }
38
+ stream.pos = Math.min(state.basePos, state.overlayPos);
39
+ if (stream.eol()) state.basePos = state.overlayPos = 0;
40
+
41
+ if (state.overlayCur == null) return state.baseCur;
42
+ if (state.baseCur != null && combine) return state.baseCur + " " + state.overlayCur;
43
+ else return state.overlayCur;
44
+ },
45
+
46
+ indent: function(state, textAfter) {
47
+ return base.indent(state.base, textAfter);
48
+ },
49
+ electricChars: base.electricChars
50
+ };
51
+ };
@@ -0,0 +1,27 @@
1
+ CodeMirror.runMode = function(string, modespec, callback) {
2
+ var mode = CodeMirror.getMode({indentUnit: 2}, modespec);
3
+ var isNode = callback.nodeType == 1;
4
+ if (isNode) {
5
+ var node = callback, accum = [];
6
+ callback = function(string, style) {
7
+ if (string == "\n")
8
+ accum.push("<br>");
9
+ else if (style)
10
+ accum.push("<span class=\"cm-" + CodeMirror.htmlEscape(style) + "\">" + CodeMirror.htmlEscape(string) + "</span>");
11
+ else
12
+ accum.push(CodeMirror.htmlEscape(string));
13
+ }
14
+ }
15
+ var lines = CodeMirror.splitLines(string), state = CodeMirror.startState(mode);
16
+ for (var i = 0, e = lines.length; i < e; ++i) {
17
+ if (i) callback("\n");
18
+ var stream = new CodeMirror.StringStream(lines[i]);
19
+ while (!stream.eol()) {
20
+ var style = mode.token(stream, state);
21
+ callback(stream.current(), style, i, stream.start);
22
+ stream.start = stream.pos;
23
+ }
24
+ }
25
+ if (isNode)
26
+ node.innerHTML = accum.join("");
27
+ };