ledger_web 1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+ };