comatose-rubyisbeautiful 3.0.0

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 (192) hide show
  1. data/CHANGELOG +198 -0
  2. data/Gemfile +29 -0
  3. data/Gemfile.lock +130 -0
  4. data/INSTALL +14 -0
  5. data/LICENSE +20 -0
  6. data/Manifest +188 -0
  7. data/README +0 -0
  8. data/README.markdown +113 -0
  9. data/Rakefile +5 -0
  10. data/SPECS +61 -0
  11. data/app/controllers/application_controller.rb +3 -0
  12. data/app/controllers/comatose/admin_controller.rb +425 -0
  13. data/app/controllers/comatose/application_controller.rb +30 -0
  14. data/app/controllers/comatose/base_controller.rb +167 -0
  15. data/app/helpers/application_helper.rb +2 -0
  16. data/app/helpers/comatose/admin_helper.rb +78 -0
  17. data/app/helpers/comatose/application_helper.rb +2 -0
  18. data/app/helpers/comatose/base_helper.rb +5 -0
  19. data/app/models/comatose/page.rb +166 -0
  20. data/app/views/comatose/admin/_form.html.erb +108 -0
  21. data/app/views/comatose/admin/_page_list_item.html.erb +62 -0
  22. data/app/views/comatose/admin/delete.html.erb +18 -0
  23. data/app/views/comatose/admin/edit.html.erb +5 -0
  24. data/app/views/comatose/admin/index.html.erb +34 -0
  25. data/app/views/comatose/admin/new.html.erb +5 -0
  26. data/app/views/comatose/admin/reorder.html.erb +30 -0
  27. data/app/views/comatose/admin/versions.html.erb +40 -0
  28. data/app/views/layouts/application.html.erb +14 -0
  29. data/app/views/layouts/comatose/admin.html.erb +44 -0
  30. data/app/views/layouts/comatose/base.html.erb +14 -0
  31. data/comatose-rubyisbeautiful.gemspec +65 -0
  32. data/config/environment.rb +5 -0
  33. data/config/environments/development.rb +26 -0
  34. data/config/environments/production.rb +49 -0
  35. data/config/environments/test.rb +35 -0
  36. data/config/locales/en.yml +5 -0
  37. data/config.ru +4 -0
  38. data/db/seeds.rb +11 -0
  39. data/lib/comatose/configuration.rb +87 -0
  40. data/lib/comatose/drop.rb +45 -0
  41. data/lib/comatose/engine.rb +28 -0
  42. data/lib/comatose/filters/inline_filter.rb +15 -0
  43. data/lib/comatose/filters/timeago_filter.rb +14 -0
  44. data/lib/comatose/filters/translation_filter.rb +11 -0
  45. data/lib/comatose/locale_constraint.rb +15 -0
  46. data/lib/comatose/logger.rb +10 -0
  47. data/lib/comatose/page_wrapper.rb +147 -0
  48. data/lib/comatose/processing_context.rb +103 -0
  49. data/lib/comatose/routes.rb +70 -0
  50. data/lib/comatose/tasks/admin.rb +57 -0
  51. data/lib/comatose/tasks/data.rb +79 -0
  52. data/lib/comatose/tasks/setup.rb +118 -0
  53. data/lib/comatose/text_filters.rb +148 -0
  54. data/lib/comatose/version.rb +9 -0
  55. data/lib/comatose.rb +88 -0
  56. data/lib/generators/comatose/USAGE +7 -0
  57. data/lib/generators/comatose/comatose_generator.rb +37 -0
  58. data/lib/generators/comatose/templates/comatose.rb +33 -0
  59. data/lib/generators/comatose/templates/migration.erb +32 -0
  60. data/lib/generators/comatose/templates/seeds.erb +2 -0
  61. data/lib/support/class_options.rb +36 -0
  62. data/lib/support/inline_rendering.rb +48 -0
  63. data/lib/support/route_mapper.rb +51 -0
  64. data/lib/tasks/comatose.rake +9 -0
  65. data/lib/text_filters/markdown.rb +14 -0
  66. data/lib/text_filters/markdown_smartypants.rb +15 -0
  67. data/lib/text_filters/none.rb +8 -0
  68. data/lib/text_filters/rdoc.rb +13 -0
  69. data/lib/text_filters/simple.rb +8 -0
  70. data/lib/text_filters/textile.rb +15 -0
  71. data/public/404.html +26 -0
  72. data/public/422.html +26 -0
  73. data/public/500.html +26 -0
  74. data/public/favicon.ico +0 -0
  75. data/public/images/comatose/collapsed.gif +0 -0
  76. data/public/images/comatose/expanded.gif +0 -0
  77. data/public/images/comatose/no-children.gif +0 -0
  78. data/public/images/comatose/page.gif +0 -0
  79. data/public/images/comatose/rails.png +0 -0
  80. data/public/images/comatose/spinner.gif +0 -0
  81. data/public/images/comatose/title-hover-bg.gif +0 -0
  82. data/public/javascripts/comatose/admin.js +406 -0
  83. data/public/javascripts/comatose/application.js +2 -0
  84. data/public/javascripts/comatose/dragdrop.js +974 -0
  85. data/public/javascripts/editor.js +452 -0
  86. data/public/javascripts/jquery/GPL-LICENSE.txt +278 -0
  87. data/public/javascripts/jquery/MIT-LICENSE.txt +20 -0
  88. data/public/javascripts/jquery/README +67 -0
  89. data/public/javascripts/jquery/jquery.js +11 -0
  90. data/public/javascripts/jquery/jquery.ui.draggable.js +1 -0
  91. data/public/javascripts/jquery/jquery.ui.js +1 -0
  92. data/public/javascripts/jquery/jquery.ui.resizable.js +1 -0
  93. data/public/javascripts/jquery/jquery.ui.sortable.js +1 -0
  94. data/public/javascripts/wymeditor/iframe/default/lbl-blockquote.png +0 -0
  95. data/public/javascripts/wymeditor/iframe/default/lbl-h1.png +0 -0
  96. data/public/javascripts/wymeditor/iframe/default/lbl-h2.png +0 -0
  97. data/public/javascripts/wymeditor/iframe/default/lbl-h3.png +0 -0
  98. data/public/javascripts/wymeditor/iframe/default/lbl-h4.png +0 -0
  99. data/public/javascripts/wymeditor/iframe/default/lbl-h5.png +0 -0
  100. data/public/javascripts/wymeditor/iframe/default/lbl-h6.png +0 -0
  101. data/public/javascripts/wymeditor/iframe/default/lbl-p.png +0 -0
  102. data/public/javascripts/wymeditor/iframe/default/lbl-pre.png +0 -0
  103. data/public/javascripts/wymeditor/iframe/default/wymiframe.css +90 -0
  104. data/public/javascripts/wymeditor/iframe/default/wymiframe.html +26 -0
  105. data/public/javascripts/wymeditor/jquery.wymeditor.js +4688 -0
  106. data/public/javascripts/wymeditor/jquery.wymeditor.min.js +1 -0
  107. data/public/javascripts/wymeditor/jquery.wymeditor.pack.js +1 -0
  108. data/public/javascripts/wymeditor/lang/bg.js +45 -0
  109. data/public/javascripts/wymeditor/lang/ca.js +45 -0
  110. data/public/javascripts/wymeditor/lang/cs.js +45 -0
  111. data/public/javascripts/wymeditor/lang/cy.js +45 -0
  112. data/public/javascripts/wymeditor/lang/de.js +45 -0
  113. data/public/javascripts/wymeditor/lang/en.js +45 -0
  114. data/public/javascripts/wymeditor/lang/es.js +45 -0
  115. data/public/javascripts/wymeditor/lang/fa.js +46 -0
  116. data/public/javascripts/wymeditor/lang/fi.js +44 -0
  117. data/public/javascripts/wymeditor/lang/fr.js +45 -0
  118. data/public/javascripts/wymeditor/lang/gl.js +45 -0
  119. data/public/javascripts/wymeditor/lang/he.js +45 -0
  120. data/public/javascripts/wymeditor/lang/hr.js +45 -0
  121. data/public/javascripts/wymeditor/lang/hu.js +45 -0
  122. data/public/javascripts/wymeditor/lang/it.js +45 -0
  123. data/public/javascripts/wymeditor/lang/nb.js +45 -0
  124. data/public/javascripts/wymeditor/lang/nl.js +45 -0
  125. data/public/javascripts/wymeditor/lang/nn.js +45 -0
  126. data/public/javascripts/wymeditor/lang/pl.js +45 -0
  127. data/public/javascripts/wymeditor/lang/pt-br.js +45 -0
  128. data/public/javascripts/wymeditor/lang/pt.js +45 -0
  129. data/public/javascripts/wymeditor/lang/ru.js +45 -0
  130. data/public/javascripts/wymeditor/lang/sv.js +45 -0
  131. data/public/javascripts/wymeditor/lang/tr.js +45 -0
  132. data/public/javascripts/wymeditor/lang/zh_cn.js +47 -0
  133. data/public/javascripts/wymeditor/plugins/embed/jquery.wymeditor.embed.js +52 -0
  134. data/public/javascripts/wymeditor/plugins/fullscreen/icon_fullscreen.gif +0 -0
  135. data/public/javascripts/wymeditor/plugins/fullscreen/jquery.wymeditor.fullscreen.js +127 -0
  136. data/public/javascripts/wymeditor/plugins/hovertools/jquery.wymeditor.hovertools.js +57 -0
  137. data/public/javascripts/wymeditor/plugins/resizable/jquery.wymeditor.resizable.js +91 -0
  138. data/public/javascripts/wymeditor/plugins/resizable/readme.txt +124 -0
  139. data/public/javascripts/wymeditor/plugins/tidy/README +19 -0
  140. data/public/javascripts/wymeditor/plugins/tidy/jquery.wymeditor.tidy.js +82 -0
  141. data/public/javascripts/wymeditor/plugins/tidy/tidy.php +36 -0
  142. data/public/javascripts/wymeditor/plugins/tidy/wand.png +0 -0
  143. data/public/javascripts/wymeditor/skins/compact/icons.png +0 -0
  144. data/public/javascripts/wymeditor/skins/compact/skin.css +134 -0
  145. data/public/javascripts/wymeditor/skins/compact/skin.js +35 -0
  146. data/public/javascripts/wymeditor/skins/default/icons.png +0 -0
  147. data/public/javascripts/wymeditor/skins/default/skin.css +133 -0
  148. data/public/javascripts/wymeditor/skins/default/skin.js +40 -0
  149. data/public/javascripts/wymeditor/skins/minimal/images/bg.header.gif +0 -0
  150. data/public/javascripts/wymeditor/skins/minimal/images/bg.selector.silver.gif +0 -0
  151. data/public/javascripts/wymeditor/skins/minimal/images/bg.wymeditor.png +0 -0
  152. data/public/javascripts/wymeditor/skins/minimal/images/icons.silver.gif +0 -0
  153. data/public/javascripts/wymeditor/skins/minimal/skin.css +131 -0
  154. data/public/javascripts/wymeditor/skins/minimal/skin.js +30 -0
  155. data/public/javascripts/wymeditor/skins/silver/COPYING +674 -0
  156. data/public/javascripts/wymeditor/skins/silver/README +27 -0
  157. data/public/javascripts/wymeditor/skins/silver/images/bg.header.gif +0 -0
  158. data/public/javascripts/wymeditor/skins/silver/images/bg.selector.silver.gif +0 -0
  159. data/public/javascripts/wymeditor/skins/silver/images/bg.wymeditor.png +0 -0
  160. data/public/javascripts/wymeditor/skins/silver/images/icons.silver.gif +0 -0
  161. data/public/javascripts/wymeditor/skins/silver/skin.css +297 -0
  162. data/public/javascripts/wymeditor/skins/silver/skin.js +61 -0
  163. data/public/javascripts/wymeditor/skins/twopanels/icons.png +0 -0
  164. data/public/javascripts/wymeditor/skins/twopanels/skin.css +134 -0
  165. data/public/javascripts/wymeditor/skins/twopanels/skin.js +39 -0
  166. data/public/javascripts/wymeditor/skins/wymeditor_icon.png +0 -0
  167. data/public/javascripts/wymeditor.tar +0 -0
  168. data/public/robots.txt +5 -0
  169. data/public/stylesheets/comatose/admin.css +488 -0
  170. data/public/stylesheets/comatose/base.css +9 -0
  171. data/spec/controllers/comatose/base_controller_spec.rb +14 -0
  172. data/spec/controllers/foos_controller_spec.rb +5 -0
  173. data/spec/helpers/foos_helper_spec.rb +15 -0
  174. data/spec/routing/base_routing_spec.rb +12 -0
  175. data/spec/spec_helper.rb +27 -0
  176. data/test/behaviors.rb +106 -0
  177. data/test/fixtures/comatose_pages.yml +96 -0
  178. data/test/functional/comatose_admin_controller_test.rb +114 -0
  179. data/test/functional/comatose_controller_test.rb +45 -0
  180. data/test/integration/comatose_routing_test.rb +17 -0
  181. data/test/javascripts/test.html +26 -0
  182. data/test/javascripts/test_runner.js +307 -0
  183. data/test/old_test_helper.rb +43 -0
  184. data/test/performance/browsing_test.rb +9 -0
  185. data/test/test_helper.rb +13 -0
  186. data/test/unit/class_options_test.rb +52 -0
  187. data/test/unit/comatose_page_test.rb +128 -0
  188. data/test/unit/processing_context_test.rb +108 -0
  189. data/test/unit/text_filters_test.rb +52 -0
  190. data.tar.gz.sig +1 -0
  191. metadata +379 -0
  192. metadata.gz.sig +0 -0
@@ -0,0 +1,452 @@
1
+ /*
2
+ * editor.js - a simple textarea2codeeditor transformer
3
+ *
4
+ * More information available at http://editor.scienceco.de/
5
+ *
6
+ * Copyright 2011 Florian Stascheck <levu@scienceco.de>
7
+ *
8
+ * This program is free software; you can redistribute it and/or modify
9
+ * it under the terms of the GNU General Public License as published by
10
+ * the Free Software Foundation; either version 2 of the License, or
11
+ * (at your option) any later version.
12
+ *
13
+ * This program is distributed in the hope that it will be useful,
14
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
+ * GNU General Public License for more details.
17
+ *
18
+ * You should have received a copy of the GNU General Public License
19
+ * along with this program; if not, write to the Free Software
20
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
21
+ * MA 02110-1301, USA.
22
+ *
23
+ *
24
+ */
25
+
26
+ (function ($) {
27
+ $.fn.getSel = function() {
28
+ var o = (function() {
29
+ var range, stored_range, start;
30
+ if (document.selection) {
31
+ //http://the-stickman.com/web-development/javascript/finding-selection-cursor-position-in-a-textarea-in-internet-explorer/
32
+ // The current selection
33
+ range = document.selection.createRange();
34
+ // We'll use this as a 'dummy'
35
+ stored_range = range.duplicate();
36
+ // Select all text
37
+ stored_range.moveToElementText( this[0] );
38
+ // Now move 'dummy' end point to end point of original range
39
+ stored_range.setEndPoint( 'EndToEnd', range );
40
+ // Now we can calculate start and end points
41
+ start = stored_range.text.length - range.text.length;
42
+ start -= stored_range.text.count('\n');
43
+ return [start, start+range.text.length];
44
+ }
45
+ return [this[0].selectionStart, this[0].selectionEnd];
46
+ }).call(this);
47
+ if (isNaN(o[0]) || isNaN(o[1])) {
48
+ o = [0, 0];
49
+ }
50
+ o.start = o[0];
51
+ o.end = o[1];
52
+ o.text = this.val().substr(o[0], o[1] - o[0]);
53
+ return o;
54
+ };
55
+ $.fn.setSel = function(from, to) {
56
+ var range;
57
+ if (document.selection) {
58
+ range = document.selection.createRange();
59
+ range.moveToElementText(this[0]);
60
+ range.moveStart('character', from);
61
+ range.moveEnd('character', this.text().length - to);
62
+ } else {
63
+ this[0].selectionStart = from;
64
+ this[0].selectionEnd = to;
65
+ this[0].focus();
66
+ }
67
+ return this;
68
+ };
69
+ String.prototype.count = function(subject) {
70
+ return this.substrPos(subject).length;
71
+ };
72
+ String.prototype.substrPos = function(substr) { //http://stackoverflow.com/questions/6363580/get-the-positions-of-the-substrings-before-replacing/6363765#6363765
73
+ var arr=[], idx=-1;
74
+ while ((idx=this.indexOf(substr,idx+1)) > -1) {
75
+ arr.push(idx);
76
+ }
77
+ return arr;
78
+ };
79
+ String.prototype.times = function(n) {
80
+ return Array.prototype.join.call({length:n+1}, this);
81
+ };
82
+ $.fn.editor = function() {
83
+ var ret = null, editorify = function(textfield) {
84
+ var api = {
85
+ indentWidth: 4,
86
+ lasthighlight: '',
87
+ textfield: textfield,
88
+ tabProducesSpace: true,
89
+ keydown: function(e) {},
90
+ keyup: function(e) {},
91
+ insertBefore: function(text) {
92
+ return api.insertAround(text, '');
93
+ },
94
+ insertAfter: function(text) {
95
+ return api.insertAround('', text);
96
+ },
97
+ insertAround: function(before, after) {
98
+ var txt, t, o = textfield.getSel();
99
+ t = textfield[0].scrollTop;
100
+ txt = textfield.val();
101
+ textfield.val(txt.substr(0, o.start) + before + txt.substr(o.start, o.text.length) + after + txt.substr(o.end));
102
+ textfield.setSel(o.start + before.length, o.end + before.length);
103
+ textfield[0].scrollTop = t;
104
+ return api;
105
+ },
106
+ insertInside: function(before, after) {
107
+ return api.replaceSelection(before + api.selectedText() + after);
108
+ },
109
+ replaceSelection: function(replaceWith) {
110
+ var txt, t, o = textfield.getSel();
111
+ t = textfield[0].scrollTop;
112
+ txt = textfield.val();
113
+ textfield.val(txt.substr(0, o.start) + replaceWith + txt.substr(o.end));
114
+ textfield.setSel(o.start, o.start + replaceWith.length);
115
+ textfield[0].scrollTop = t;
116
+ return api;
117
+ },
118
+ replace: function(subject, replaceWith, maxcount) {
119
+ maxcount = maxcount || false;
120
+ var t, i, count, pos, s, o = textfield[0].scrollTop;
121
+ t = textfield.val();
122
+ i = t.indexOf(subject);
123
+ if (i != -1) {
124
+ count = 0;
125
+ pos = 0;
126
+ while((i != -1) && ((maxcount === false) || (count < maxcount))) {
127
+ pos = i;
128
+ t = t.replace(subject, replaceWith);
129
+ i = t.indexOf(subject);
130
+ count++;
131
+ }
132
+ textfield.val(t);
133
+ s = pos + replaceWith.length;
134
+ textfield.setSel(s, s);
135
+ textfield[0].scrollTop = o;
136
+ }
137
+ return api;
138
+ },
139
+ highlightFirstOccurence: function(subject, from) {
140
+ from = from || 0;
141
+ var idx, t, o = textfield[0].scrollTop;
142
+ t = textfield.val();
143
+ idx = t.indexOf(subject, from);
144
+ if (idx != -1) {
145
+ api.lasthighlight = subject;
146
+ textfield.setSel(idx, idx+subject.length);
147
+ textfield[0].scrollTop = o;
148
+ }
149
+ },
150
+ highlightNextOccurence: function(subject) {
151
+ subject = subject || api.lasthighlight;
152
+ return api.highlightFirstOccurence(subject, textfield.getSel().end);
153
+ },
154
+ focus: function() {
155
+ textfield.focus();
156
+ return api;
157
+ },
158
+ currentLine: function(array) {
159
+ array = ((array === undefined) || (array === null)) ? false : array;
160
+ var start, s, end, t = textfield.val();
161
+ s = textfield.getSel();
162
+ start = t.substr(0, s.start).count("\n");
163
+ if (array) {
164
+ end = t.substr(0, s.end).count("\n");
165
+ return [start, end];
166
+ } else {
167
+ return start;
168
+ }
169
+ },
170
+ posInLine: function(end) {
171
+ end = ((end === undefined) || (end === null)) ? false : end;
172
+ var s, pos, lines, i, j=0, l, t = textfield.val();
173
+ s = textfield.getSel();
174
+ pos = end ? s.end : s.start;
175
+ lines = t.split("\n");
176
+ for (i = 0; i < lines.length; i++) {
177
+ l = lines[i].length;
178
+ if (j+1+l > pos) {
179
+ return pos - j;
180
+ }
181
+ j += l + 1;
182
+ }
183
+ return 0;
184
+ },
185
+ lineText: function(linenr, lineText) {
186
+ linenr = linenr || api.currentLine();
187
+ var lines, s, o, oldLength, t = textfield.val();
188
+ lines = t.split("\n");
189
+ if (lineText !== undefined) {
190
+ o = textfield[0].scrollTop;
191
+ s = textfield.getSel();
192
+ oldLength = lines[linenr] ? lines[linenr].length : 0;
193
+ lineText += '';
194
+ lines[linenr] = lineText;
195
+ textfield.val(lines.join("\n"));
196
+ textfield.setSel(s.start - oldLength + lineText.length, s.end - oldLength + lineText.length);
197
+ textfield[0].scrollTop = o;
198
+ } else {
199
+ if (lines[linenr]) {
200
+ return lines[linenr];
201
+ }
202
+ return '';
203
+ }
204
+ },
205
+ moveSel: function(by, stayInLine) {
206
+ var p, newp, l, s = textfield.getSel();
207
+ p = api.posInLine();
208
+ newp = p + by;
209
+ if (stayInLine) {
210
+ l = api.lineText().length;
211
+ if (newp < 0) {
212
+ newp = 0;
213
+ }
214
+ if (newp > l) {
215
+ newp = l;
216
+ }
217
+ }
218
+ s.start += newp - p;
219
+ s.end += newp - p;
220
+ textfield.setSel(s.start, s.end);
221
+ },
222
+ indentLine: function(from, to, by) {
223
+ if (from < 0) { //its indentLine(by)
224
+ by = from;
225
+ from = null;
226
+ }
227
+ if (from === undefined) {
228
+ from = api.currentLine(true);
229
+ }
230
+ if (!!from.length) {
231
+ to = from[1];
232
+ from = from[0];
233
+ } else {
234
+ to = to || from;
235
+ }
236
+ if (isNaN(by)) {
237
+ by = api.indentWidth;
238
+ }
239
+ var j, firstlineoutdented = 0, outdented = 0, i, lines, s = textfield.getSel(), t = textfield.val(), o = textfield[0].scrollTop;
240
+ lines = t.split("\n");
241
+ for (i=from; i <= to; i++) {
242
+ if (by > 0) {
243
+ lines[i] = " ".times(by) + lines[i];
244
+ } else {
245
+ for (j=0; j > by; j--) {
246
+ if (lines[i].substr(0, 1) != ' ') {
247
+ break;
248
+ }
249
+ lines[i] = lines[i].substr(1);
250
+ outdented++;
251
+ if (i == from) {
252
+ firstlineoutdented++;
253
+ }
254
+ }
255
+ }
256
+ }
257
+ t = lines.join("\n");
258
+ textfield.val(t);
259
+ if (by > 0) {
260
+ s.start += by;
261
+ s.end += (to-from+1) * by;
262
+ } else {
263
+ s.start -= firstlineoutdented;
264
+ s.end -= outdented;
265
+ }
266
+ textfield.setSel(s.start, s.end);
267
+ textfield[0].scrollTop = o;
268
+ return textfield;
269
+ },
270
+ outdentLine: function(from, to) {
271
+ return api.indentLine(from, to, -api.indentWidth);
272
+ },
273
+ adjustLine: function(linenr) {
274
+ linenr = linenr || api.currentLine();
275
+ if (linenr < 0) {
276
+ linenr = 0;
277
+ }
278
+ if (linenr === 0) {
279
+ return;
280
+ //the first line can't be adjusted because for adjusting we need lines before
281
+ }
282
+ var l, lineBeforeIndent, i, j=0, selEndAfterLine = true, selStartAfterLine = true, lines, s = textfield.getSel(), t = textfield.val(), o = textfield[0].scrollTop, currentLineIndent;
283
+ lines = t.split("\n");
284
+ for(i=0; i < linenr; i++) {
285
+ j+=lines[i].length+1;
286
+ if (j > s.start) {
287
+ selStartAfterLine = false;
288
+ }
289
+ if (j > s.end) {
290
+ selEndAfterLine = false;
291
+ }
292
+ }
293
+ l=lines[i-1];
294
+ lineBeforeIndent = 0;
295
+ for(j=0; j < l.length; j++) {
296
+ if (l.substr(j, 1) == ' ') {
297
+ lineBeforeIndent++;
298
+ } else {
299
+ break;
300
+ }
301
+ }
302
+ if (l.substr(l.length - 1) == '{') {
303
+ lineBeforeIndent += api.indentWidth;
304
+ }
305
+ l=lines[i];
306
+ currentLineIndent = 0;
307
+ for(j=0; j < l.length; j++) {
308
+ if (l.substr(j, 1) == ' ') {
309
+ currentLineIndent++;
310
+ } else {
311
+ break;
312
+ }
313
+ }
314
+ if (l.substr(currentLineIndent, 1) == '}') {
315
+ lineBeforeIndent -= api.indentWidth;
316
+ if (lineBeforeIndent < 0) {
317
+ lineBeforeIndent = 0;
318
+ }
319
+ }
320
+ api.indentLine(i, i, lineBeforeIndent - currentLineIndent);
321
+ if (selStartAfterLine) {
322
+ s.start += lineBeforeIndent - currentLineIndent;
323
+ }
324
+ if (selEndAfterLine) {
325
+ s.end += lineBeforeIndent - currentLineIndent;
326
+ }
327
+ textfield.setSel(s.start, s.end);
328
+ textfield[0].scrollTop = o;
329
+ return textfield;
330
+ }
331
+ };
332
+ var enterkeydownline = null, braceclosekey = null;
333
+ textfield.keydown(function(e) {
334
+ var p, l, i, sel, pm, s, m;
335
+ if (e.which == 9) {
336
+ e.preventDefault();
337
+ if (textfield.getSel().text === '') {
338
+ if (e.shiftKey) {
339
+ p = api.posInLine();
340
+ pm = p % api.indentWidth;
341
+ if (pm === 0) {
342
+ pm = api.indentWidth;
343
+ }
344
+ l = api.lineText();
345
+ if (api.tabProducesSpace) {
346
+ if (l.substr(p-pm, pm) == ' '.times(pm)) {
347
+ api.lineText(api.currentLine(), l.substr(0, p-pm) + l.substr(p));
348
+ } else {
349
+ api.moveSel(-api.indentWidth, true);
350
+ }
351
+ } else {
352
+ if (l.substr(p-1, 1) == "\t") {
353
+ api.lineText(api.currentLine(), l.substr(0, p-1) + l.substr(p));
354
+ } else {
355
+ api.moveSel(-api.indentWidth, true);
356
+ }
357
+ }
358
+ } else {
359
+ if (api.tabProducesSpace) {
360
+ api.insertBefore(' '.times(api.indentWidth - (api.posInLine() % api.indentWidth)));
361
+ } else {
362
+ api.insertBefore("\t");
363
+ }
364
+ }
365
+ } else {
366
+ if (e.shiftKey) {
367
+ api.outdentLine();
368
+ } else {
369
+ api.indentLine();
370
+ }
371
+ }
372
+ } else if (e.which == 13) { //enter
373
+ if (!(e.shiftKey || e.ctrlKey || e.altKey)) {
374
+ if (enterkeydownline === null) {
375
+ enterkeydownline = api.currentLine();
376
+ }
377
+ }
378
+ } else if (e.which == 36) { //home
379
+ if (!(e.ctrlKey || e.altKey)) {
380
+ p = api.posInLine();
381
+ l = api.lineText();
382
+ i = 0;
383
+ for (; i < l.length; i++) {
384
+ if (l.substr(i, 1) != (api.tabProducesSpace ? ' ' : "\t")) {
385
+ break;
386
+ }
387
+ }
388
+ if (e.shiftKey) {
389
+ sel = textfield.getSel();
390
+ if (p == i) { //mark the whole line
391
+ textfield.setSel(sel.start - p, sel.end);
392
+ } else { //mark from indentation to end
393
+ textfield.setSel(sel.start + i - p, sel.end);
394
+ }
395
+ } else {
396
+ s = 0;
397
+ if (p == i) {
398
+ s = -i; //go to 0
399
+ } else {
400
+ s = i-p; // go to i
401
+ }
402
+ api.moveSel(s);
403
+ }
404
+ e.preventDefault();
405
+ }
406
+ } else if (e.which == 8) { //backspace
407
+ if (api.tabProducesSpace && (!(e.shiftKey || e.ctrlKey || e.altKey))) {
408
+ p = api.posInLine();
409
+ l = api.lineText();
410
+ i = 0;
411
+ for (; i < l.length; i++) {
412
+ if (l.substr(i, 1) != ' ') {
413
+ break;
414
+ }
415
+ }
416
+ sel = textfield.getSel();
417
+ if ((p > 0) && (p <= i) && (sel.start == sel.end)) {
418
+ e.preventDefault();
419
+ m = p % api.indentWidth;
420
+ if (m === 0) {
421
+ m = api.indentWidth;
422
+ }
423
+ api.lineText(api.currentLine(), l.substr(0, p - m) + l.substr(p));
424
+ }
425
+ }
426
+ }
427
+ api.keydown(e);
428
+ }).keypress(function(e) {
429
+ if (String.fromCharCode(e.charCode) == '}') {
430
+ api.replaceSelection('').insertBefore('}').adjustLine();
431
+ e.preventDefault();
432
+ }
433
+ }).keyup(function(e) {
434
+ if (e.which == 13) {
435
+ var to, from = enterkeydownline+1;
436
+ to = api.currentLine();
437
+ for (; from <= to; from++) {
438
+ api.adjustLine(from);
439
+ }
440
+ enterkeydownline = null;
441
+ }
442
+ api.keyup(e);
443
+ });
444
+ return api;
445
+ }, textfield, i;
446
+ for (i=0; i<this.length; i++) {
447
+ textfield = $(this[i]);
448
+ ret = editorify(textfield);
449
+ }
450
+ return ret;
451
+ };
452
+ })(jQuery);