##// END OF EJS Templates
Add linewrapping to text cells (new feature in CodeMirror).
Fernando Perez -
Show More
@@ -1,287 +1,288 b''
1 //----------------------------------------------------------------------------
1 //----------------------------------------------------------------------------
2 // Copyright (C) 2008-2011 The IPython Development Team
2 // Copyright (C) 2008-2011 The IPython Development Team
3 //
3 //
4 // Distributed under the terms of the BSD License. The full license is in
4 // Distributed under the terms of the BSD License. The full license is in
5 // the file COPYING, distributed as part of this software.
5 // the file COPYING, distributed as part of this software.
6 //----------------------------------------------------------------------------
6 //----------------------------------------------------------------------------
7
7
8 //============================================================================
8 //============================================================================
9 // TextCell
9 // TextCell
10 //============================================================================
10 //============================================================================
11
11
12 var IPython = (function (IPython) {
12 var IPython = (function (IPython) {
13
13
14 // TextCell base class
14 // TextCell base class
15
15
16 var TextCell = function (notebook) {
16 var TextCell = function (notebook) {
17 this.code_mirror_mode = this.code_mirror_mode || 'htmlmixed';
17 this.code_mirror_mode = this.code_mirror_mode || 'htmlmixed';
18 IPython.Cell.apply(this, arguments);
18 IPython.Cell.apply(this, arguments);
19 this.rendered = false;
19 this.rendered = false;
20 this.cell_type = this.cell_type || 'text';
20 this.cell_type = this.cell_type || 'text';
21 };
21 };
22
22
23
23
24 TextCell.prototype = new IPython.Cell();
24 TextCell.prototype = new IPython.Cell();
25
25
26
26
27 TextCell.prototype.create_element = function () {
27 TextCell.prototype.create_element = function () {
28 var cell = $("<div>").addClass('cell text_cell border-box-sizing');
28 var cell = $("<div>").addClass('cell text_cell border-box-sizing');
29 cell.attr('tabindex','2');
29 cell.attr('tabindex','2');
30 var input_area = $('<div/>').addClass('text_cell_input border-box-sizing');
30 var input_area = $('<div/>').addClass('text_cell_input border-box-sizing');
31 this.code_mirror = CodeMirror(input_area.get(0), {
31 this.code_mirror = CodeMirror(input_area.get(0), {
32 indentUnit : 4,
32 indentUnit : 4,
33 mode: this.code_mirror_mode,
33 mode: this.code_mirror_mode,
34 theme: 'default',
34 theme: 'default',
35 value: this.placeholder,
35 value: this.placeholder,
36 readOnly: this.read_only,
36 readOnly: this.read_only,
37 lineWrapping : true,
37 onKeyEvent: $.proxy(this.handle_codemirror_keyevent,this)
38 onKeyEvent: $.proxy(this.handle_codemirror_keyevent,this)
38 });
39 });
39 // The tabindex=-1 makes this div focusable.
40 // The tabindex=-1 makes this div focusable.
40 var render_area = $('<div/>').addClass('text_cell_render border-box-sizing').
41 var render_area = $('<div/>').addClass('text_cell_render border-box-sizing').
41 addClass('rendered_html').attr('tabindex','-1');
42 addClass('rendered_html').attr('tabindex','-1');
42 cell.append(input_area).append(render_area);
43 cell.append(input_area).append(render_area);
43 this.element = cell;
44 this.element = cell;
44 };
45 };
45
46
46
47
47 TextCell.prototype.bind_events = function () {
48 TextCell.prototype.bind_events = function () {
48 IPython.Cell.prototype.bind_events.apply(this);
49 IPython.Cell.prototype.bind_events.apply(this);
49 var that = this;
50 var that = this;
50 this.element.keydown(function (event) {
51 this.element.keydown(function (event) {
51 if (event.which === 13) {
52 if (event.which === 13) {
52 if (that.rendered) {
53 if (that.rendered) {
53 that.edit();
54 that.edit();
54 return false;
55 return false;
55 };
56 };
56 };
57 };
57 });
58 });
58 this.element.dblclick(function () {
59 this.element.dblclick(function () {
59 that.edit();
60 that.edit();
60 });
61 });
61 };
62 };
62
63
63
64
64 TextCell.prototype.handle_codemirror_keyevent = function (editor, event) {
65 TextCell.prototype.handle_codemirror_keyevent = function (editor, event) {
65 // This method gets called in CodeMirror's onKeyDown/onKeyPress
66 // This method gets called in CodeMirror's onKeyDown/onKeyPress
66 // handlers and is used to provide custom key handling. Its return
67 // handlers and is used to provide custom key handling. Its return
67 // value is used to determine if CodeMirror should ignore the event:
68 // value is used to determine if CodeMirror should ignore the event:
68 // true = ignore, false = don't ignore.
69 // true = ignore, false = don't ignore.
69
70
70 if (event.keyCode === 13 && (event.shiftKey || event.ctrlKey)) {
71 if (event.keyCode === 13 && (event.shiftKey || event.ctrlKey)) {
71 // Always ignore shift-enter in CodeMirror as we handle it.
72 // Always ignore shift-enter in CodeMirror as we handle it.
72 return true;
73 return true;
73 }
74 }
74 return false;
75 return false;
75 };
76 };
76
77
77
78
78 TextCell.prototype.select = function () {
79 TextCell.prototype.select = function () {
79 IPython.Cell.prototype.select.apply(this);
80 IPython.Cell.prototype.select.apply(this);
80 var output = this.element.find("div.text_cell_render");
81 var output = this.element.find("div.text_cell_render");
81 output.trigger('focus');
82 output.trigger('focus');
82 };
83 };
83
84
84
85
85 TextCell.prototype.unselect = function() {
86 TextCell.prototype.unselect = function() {
86 // render on selection of another cell
87 // render on selection of another cell
87 this.render();
88 this.render();
88 IPython.Cell.prototype.unselect.apply(this);
89 IPython.Cell.prototype.unselect.apply(this);
89 };
90 };
90
91
91
92
92 TextCell.prototype.edit = function () {
93 TextCell.prototype.edit = function () {
93 if ( this.read_only ) return;
94 if ( this.read_only ) return;
94 if (this.rendered === true) {
95 if (this.rendered === true) {
95 var text_cell = this.element;
96 var text_cell = this.element;
96 var output = text_cell.find("div.text_cell_render");
97 var output = text_cell.find("div.text_cell_render");
97 output.hide();
98 output.hide();
98 text_cell.find('div.text_cell_input').show();
99 text_cell.find('div.text_cell_input').show();
99 this.code_mirror.refresh();
100 this.code_mirror.refresh();
100 this.code_mirror.focus();
101 this.code_mirror.focus();
101 // We used to need an additional refresh() after the focus, but
102 // We used to need an additional refresh() after the focus, but
102 // it appears that this has been fixed in CM. This bug would show
103 // it appears that this has been fixed in CM. This bug would show
103 // up on FF when a newly loaded markdown cell was edited.
104 // up on FF when a newly loaded markdown cell was edited.
104 this.rendered = false;
105 this.rendered = false;
105 if (this.get_text() === this.placeholder) {
106 if (this.get_text() === this.placeholder) {
106 this.set_text('');
107 this.set_text('');
107 this.refresh();
108 this.refresh();
108 }
109 }
109 }
110 }
110 };
111 };
111
112
112
113
113 // Subclasses must define render.
114 // Subclasses must define render.
114 TextCell.prototype.render = function () {};
115 TextCell.prototype.render = function () {};
115
116
116
117
117 TextCell.prototype.get_text = function() {
118 TextCell.prototype.get_text = function() {
118 return this.code_mirror.getValue();
119 return this.code_mirror.getValue();
119 };
120 };
120
121
121
122
122 TextCell.prototype.set_text = function(text) {
123 TextCell.prototype.set_text = function(text) {
123 this.code_mirror.setValue(text);
124 this.code_mirror.setValue(text);
124 this.code_mirror.refresh();
125 this.code_mirror.refresh();
125 };
126 };
126
127
127
128
128 TextCell.prototype.get_rendered = function() {
129 TextCell.prototype.get_rendered = function() {
129 return this.element.find('div.text_cell_render').html();
130 return this.element.find('div.text_cell_render').html();
130 };
131 };
131
132
132
133
133 TextCell.prototype.set_rendered = function(text) {
134 TextCell.prototype.set_rendered = function(text) {
134 this.element.find('div.text_cell_render').html(text);
135 this.element.find('div.text_cell_render').html(text);
135 };
136 };
136
137
137
138
138 TextCell.prototype.at_top = function () {
139 TextCell.prototype.at_top = function () {
139 if (this.rendered) {
140 if (this.rendered) {
140 return true;
141 return true;
141 } else {
142 } else {
142 return false;
143 return false;
143 }
144 }
144 };
145 };
145
146
146
147
147 TextCell.prototype.at_bottom = function () {
148 TextCell.prototype.at_bottom = function () {
148 if (this.rendered) {
149 if (this.rendered) {
149 return true;
150 return true;
150 } else {
151 } else {
151 return false;
152 return false;
152 }
153 }
153 };
154 };
154
155
155
156
156 TextCell.prototype.fromJSON = function (data) {
157 TextCell.prototype.fromJSON = function (data) {
157 if (data.cell_type === this.cell_type) {
158 if (data.cell_type === this.cell_type) {
158 if (data.source !== undefined) {
159 if (data.source !== undefined) {
159 this.set_text(data.source);
160 this.set_text(data.source);
160 this.set_rendered(data.rendered || '');
161 this.set_rendered(data.rendered || '');
161 this.rendered = false;
162 this.rendered = false;
162 this.render();
163 this.render();
163 }
164 }
164 }
165 }
165 };
166 };
166
167
167
168
168 TextCell.prototype.toJSON = function () {
169 TextCell.prototype.toJSON = function () {
169 var data = {};
170 var data = {};
170 data.cell_type = this.cell_type;
171 data.cell_type = this.cell_type;
171 data.source = this.get_text();
172 data.source = this.get_text();
172 return data;
173 return data;
173 };
174 };
174
175
175
176
176 // HTMLCell
177 // HTMLCell
177
178
178 var HTMLCell = function (notebook) {
179 var HTMLCell = function (notebook) {
179 this.placeholder = "Type <strong>HTML</strong> and LaTeX: $\\alpha^2$";
180 this.placeholder = "Type <strong>HTML</strong> and LaTeX: $\\alpha^2$";
180 IPython.TextCell.apply(this, arguments);
181 IPython.TextCell.apply(this, arguments);
181 this.cell_type = 'html';
182 this.cell_type = 'html';
182 };
183 };
183
184
184
185
185 HTMLCell.prototype = new TextCell();
186 HTMLCell.prototype = new TextCell();
186
187
187
188
188 HTMLCell.prototype.render = function () {
189 HTMLCell.prototype.render = function () {
189 if (this.rendered === false) {
190 if (this.rendered === false) {
190 var text = this.get_text();
191 var text = this.get_text();
191 if (text === "") { text = this.placeholder; }
192 if (text === "") { text = this.placeholder; }
192 this.set_rendered(text);
193 this.set_rendered(text);
193 this.typeset();
194 this.typeset();
194 this.element.find('div.text_cell_input').hide();
195 this.element.find('div.text_cell_input').hide();
195 this.element.find("div.text_cell_render").show();
196 this.element.find("div.text_cell_render").show();
196 this.rendered = true;
197 this.rendered = true;
197 }
198 }
198 };
199 };
199
200
200
201
201 // MarkdownCell
202 // MarkdownCell
202
203
203 var MarkdownCell = function (notebook) {
204 var MarkdownCell = function (notebook) {
204 this.placeholder = "Type *Markdown* and LaTeX: $\\alpha^2$";
205 this.placeholder = "Type *Markdown* and LaTeX: $\\alpha^2$";
205 IPython.TextCell.apply(this, arguments);
206 IPython.TextCell.apply(this, arguments);
206 this.cell_type = 'markdown';
207 this.cell_type = 'markdown';
207 };
208 };
208
209
209
210
210 MarkdownCell.prototype = new TextCell();
211 MarkdownCell.prototype = new TextCell();
211
212
212
213
213 MarkdownCell.prototype.render = function () {
214 MarkdownCell.prototype.render = function () {
214 if (this.rendered === false) {
215 if (this.rendered === false) {
215 var text = this.get_text();
216 var text = this.get_text();
216 if (text === "") { text = this.placeholder; }
217 if (text === "") { text = this.placeholder; }
217 var html = IPython.markdown_converter.makeHtml(text);
218 var html = IPython.markdown_converter.makeHtml(text);
218 this.set_rendered(html);
219 this.set_rendered(html);
219 this.typeset()
220 this.typeset()
220 this.element.find('div.text_cell_input').hide();
221 this.element.find('div.text_cell_input').hide();
221 this.element.find("div.text_cell_render").show();
222 this.element.find("div.text_cell_render").show();
222 var code_snippets = this.element.find("pre > code");
223 var code_snippets = this.element.find("pre > code");
223 code_snippets.replaceWith(function () {
224 code_snippets.replaceWith(function () {
224 var code = $(this).html();
225 var code = $(this).html();
225 /* Substitute br for newlines and &nbsp; for spaces
226 /* Substitute br for newlines and &nbsp; for spaces
226 before highlighting, since prettify doesn't
227 before highlighting, since prettify doesn't
227 preserve those on all browsers */
228 preserve those on all browsers */
228 code = code.replace(/(\r\n|\n|\r)/gm, "<br/>");
229 code = code.replace(/(\r\n|\n|\r)/gm, "<br/>");
229 code = code.replace(/ /gm, '&nbsp;');
230 code = code.replace(/ /gm, '&nbsp;');
230 code = prettyPrintOne(code);
231 code = prettyPrintOne(code);
231
232
232 return '<code class="prettyprint">' + code + '</code>';
233 return '<code class="prettyprint">' + code + '</code>';
233 });
234 });
234 this.rendered = true;
235 this.rendered = true;
235 }
236 }
236 };
237 };
237
238
238
239
239 // RSTCell
240 // RSTCell
240
241
241 var RSTCell = function (notebook) {
242 var RSTCell = function (notebook) {
242 this.placeholder = "Type *ReStructured Text* and LaTeX: $\\alpha^2$";
243 this.placeholder = "Type *ReStructured Text* and LaTeX: $\\alpha^2$";
243 IPython.TextCell.apply(this, arguments);
244 IPython.TextCell.apply(this, arguments);
244 this.cell_type = 'rst';
245 this.cell_type = 'rst';
245 };
246 };
246
247
247
248
248 RSTCell.prototype = new TextCell();
249 RSTCell.prototype = new TextCell();
249
250
250
251
251 RSTCell.prototype.render = function () {
252 RSTCell.prototype.render = function () {
252 if (this.rendered === false) {
253 if (this.rendered === false) {
253 var text = this.get_text();
254 var text = this.get_text();
254 if (text === "") { text = this.placeholder; }
255 if (text === "") { text = this.placeholder; }
255 var settings = {
256 var settings = {
256 processData : false,
257 processData : false,
257 cache : false,
258 cache : false,
258 type : "POST",
259 type : "POST",
259 data : text,
260 data : text,
260 headers : {'Content-Type': 'application/x-rst'},
261 headers : {'Content-Type': 'application/x-rst'},
261 success : $.proxy(this.handle_render,this)
262 success : $.proxy(this.handle_render,this)
262 };
263 };
263 $.ajax("/rstservice/render", settings);
264 $.ajax("/rstservice/render", settings);
264 this.element.find('div.text_cell_input').hide();
265 this.element.find('div.text_cell_input').hide();
265 this.element.find("div.text_cell_render").show();
266 this.element.find("div.text_cell_render").show();
266 this.set_rendered("Rendering...");
267 this.set_rendered("Rendering...");
267 }
268 }
268 };
269 };
269
270
270
271
271 RSTCell.prototype.handle_render = function (data, status, xhr) {
272 RSTCell.prototype.handle_render = function (data, status, xhr) {
272 this.set_rendered(data);
273 this.set_rendered(data);
273 this.typeset();
274 this.typeset();
274 this.rendered = true;
275 this.rendered = true;
275 };
276 };
276
277
277
278
278 IPython.TextCell = TextCell;
279 IPython.TextCell = TextCell;
279 IPython.HTMLCell = HTMLCell;
280 IPython.HTMLCell = HTMLCell;
280 IPython.MarkdownCell = MarkdownCell;
281 IPython.MarkdownCell = MarkdownCell;
281 IPython.RSTCell = RSTCell;
282 IPython.RSTCell = RSTCell;
282
283
283
284
284 return IPython;
285 return IPython;
285
286
286 }(IPython));
287 }(IPython));
287
288
General Comments 0
You need to be logged in to leave comments. Login now