##// END OF EJS Templates
Fixing Shift-Enter bug in text cells....
Brian Granger -
Show More
@@ -1,348 +1,348
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 lineWrapping : true,
38 onKeyEvent: $.proxy(this.handle_codemirror_keyevent,this)
38 onKeyEvent: $.proxy(this.handle_codemirror_keyevent,this)
39 });
39 });
40 // The tabindex=-1 makes this div focusable.
40 // The tabindex=-1 makes this div focusable.
41 var render_area = $('<div/>').addClass('text_cell_render border-box-sizing').
41 var render_area = $('<div/>').addClass('text_cell_render border-box-sizing').
42 addClass('rendered_html').attr('tabindex','-1');
42 addClass('rendered_html').attr('tabindex','-1');
43 cell.append(input_area).append(render_area);
43 cell.append(input_area).append(render_area);
44 this.element = cell;
44 this.element = cell;
45 };
45 };
46
46
47
47
48 TextCell.prototype.bind_events = function () {
48 TextCell.prototype.bind_events = function () {
49 IPython.Cell.prototype.bind_events.apply(this);
49 IPython.Cell.prototype.bind_events.apply(this);
50 var that = this;
50 var that = this;
51 this.element.keydown(function (event) {
51 this.element.keydown(function (event) {
52 if (event.which === 13) {
52 if (event.which === 13 && !event.shiftKey) {
53 if (that.rendered) {
53 if (that.rendered) {
54 that.edit();
54 that.edit();
55 return false;
55 return false;
56 };
56 };
57 };
57 };
58 });
58 });
59 this.element.dblclick(function () {
59 this.element.dblclick(function () {
60 that.edit();
60 that.edit();
61 });
61 });
62 };
62 };
63
63
64
64
65 TextCell.prototype.handle_codemirror_keyevent = function (editor, event) {
65 TextCell.prototype.handle_codemirror_keyevent = function (editor, event) {
66 // This method gets called in CodeMirror's onKeyDown/onKeyPress
66 // This method gets called in CodeMirror's onKeyDown/onKeyPress
67 // handlers and is used to provide custom key handling. Its return
67 // handlers and is used to provide custom key handling. Its return
68 // value is used to determine if CodeMirror should ignore the event:
68 // value is used to determine if CodeMirror should ignore the event:
69 // true = ignore, false = don't ignore.
69 // true = ignore, false = don't ignore.
70
70
71 if (event.keyCode === 13 && (event.shiftKey || event.ctrlKey)) {
71 if (event.keyCode === 13 && (event.shiftKey || event.ctrlKey)) {
72 // Always ignore shift-enter in CodeMirror as we handle it.
72 // Always ignore shift-enter in CodeMirror as we handle it.
73 return true;
73 return true;
74 }
74 }
75 return false;
75 return false;
76 };
76 };
77
77
78
78
79 TextCell.prototype.select = function () {
79 TextCell.prototype.select = function () {
80 IPython.Cell.prototype.select.apply(this);
80 IPython.Cell.prototype.select.apply(this);
81 var output = this.element.find("div.text_cell_render");
81 var output = this.element.find("div.text_cell_render");
82 output.trigger('focus');
82 output.trigger('focus');
83 };
83 };
84
84
85
85
86 TextCell.prototype.unselect = function() {
86 TextCell.prototype.unselect = function() {
87 // render on selection of another cell
87 // render on selection of another cell
88 this.render();
88 this.render();
89 IPython.Cell.prototype.unselect.apply(this);
89 IPython.Cell.prototype.unselect.apply(this);
90 };
90 };
91
91
92
92
93 TextCell.prototype.edit = function () {
93 TextCell.prototype.edit = function () {
94 if ( this.read_only ) return;
94 if ( this.read_only ) return;
95 if (this.rendered === true) {
95 if (this.rendered === true) {
96 var text_cell = this.element;
96 var text_cell = this.element;
97 var output = text_cell.find("div.text_cell_render");
97 var output = text_cell.find("div.text_cell_render");
98 output.hide();
98 output.hide();
99 text_cell.find('div.text_cell_input').show();
99 text_cell.find('div.text_cell_input').show();
100 this.code_mirror.refresh();
100 this.code_mirror.refresh();
101 this.code_mirror.focus();
101 this.code_mirror.focus();
102 // We used to need an additional refresh() after the focus, but
102 // We used to need an additional refresh() after the focus, but
103 // 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
104 // up on FF when a newly loaded markdown cell was edited.
104 // up on FF when a newly loaded markdown cell was edited.
105 this.rendered = false;
105 this.rendered = false;
106 if (this.get_text() === this.placeholder) {
106 if (this.get_text() === this.placeholder) {
107 this.set_text('');
107 this.set_text('');
108 this.refresh();
108 this.refresh();
109 }
109 }
110 }
110 }
111 };
111 };
112
112
113
113
114 // Subclasses must define render.
114 // Subclasses must define render.
115 TextCell.prototype.render = function () {};
115 TextCell.prototype.render = function () {};
116
116
117
117
118 TextCell.prototype.get_text = function() {
118 TextCell.prototype.get_text = function() {
119 return this.code_mirror.getValue();
119 return this.code_mirror.getValue();
120 };
120 };
121
121
122
122
123 TextCell.prototype.set_text = function(text) {
123 TextCell.prototype.set_text = function(text) {
124 this.code_mirror.setValue(text);
124 this.code_mirror.setValue(text);
125 this.code_mirror.refresh();
125 this.code_mirror.refresh();
126 };
126 };
127
127
128
128
129 TextCell.prototype.get_rendered = function() {
129 TextCell.prototype.get_rendered = function() {
130 return this.element.find('div.text_cell_render').html();
130 return this.element.find('div.text_cell_render').html();
131 };
131 };
132
132
133
133
134 TextCell.prototype.set_rendered = function(text) {
134 TextCell.prototype.set_rendered = function(text) {
135 this.element.find('div.text_cell_render').html(text);
135 this.element.find('div.text_cell_render').html(text);
136 };
136 };
137
137
138
138
139 TextCell.prototype.at_top = function () {
139 TextCell.prototype.at_top = function () {
140 if (this.rendered) {
140 if (this.rendered) {
141 return true;
141 return true;
142 } else {
142 } else {
143 return false;
143 return false;
144 }
144 }
145 };
145 };
146
146
147
147
148 TextCell.prototype.at_bottom = function () {
148 TextCell.prototype.at_bottom = function () {
149 if (this.rendered) {
149 if (this.rendered) {
150 return true;
150 return true;
151 } else {
151 } else {
152 return false;
152 return false;
153 }
153 }
154 };
154 };
155
155
156
156
157 TextCell.prototype.fromJSON = function (data) {
157 TextCell.prototype.fromJSON = function (data) {
158 if (data.cell_type === this.cell_type) {
158 if (data.cell_type === this.cell_type) {
159 if (data.source !== undefined) {
159 if (data.source !== undefined) {
160 this.set_text(data.source);
160 this.set_text(data.source);
161 this.set_rendered(data.rendered || '');
161 this.set_rendered(data.rendered || '');
162 this.rendered = false;
162 this.rendered = false;
163 this.render();
163 this.render();
164 }
164 }
165 }
165 }
166 };
166 };
167
167
168
168
169 TextCell.prototype.toJSON = function () {
169 TextCell.prototype.toJSON = function () {
170 var data = {};
170 var data = {};
171 data.cell_type = this.cell_type;
171 data.cell_type = this.cell_type;
172 data.source = this.get_text();
172 data.source = this.get_text();
173 return data;
173 return data;
174 };
174 };
175
175
176
176
177 // HTMLCell
177 // HTMLCell
178
178
179 var HTMLCell = function (notebook) {
179 var HTMLCell = function (notebook) {
180 this.placeholder = "Type <strong>HTML</strong> and LaTeX: $\\alpha^2$";
180 this.placeholder = "Type <strong>HTML</strong> and LaTeX: $\\alpha^2$";
181 IPython.TextCell.apply(this, arguments);
181 IPython.TextCell.apply(this, arguments);
182 this.cell_type = 'html';
182 this.cell_type = 'html';
183 };
183 };
184
184
185
185
186 HTMLCell.prototype = new TextCell();
186 HTMLCell.prototype = new TextCell();
187
187
188
188
189 HTMLCell.prototype.render = function () {
189 HTMLCell.prototype.render = function () {
190 if (this.rendered === false) {
190 if (this.rendered === false) {
191 var text = this.get_text();
191 var text = this.get_text();
192 if (text === "") { text = this.placeholder; }
192 if (text === "") { text = this.placeholder; }
193 this.set_rendered(text);
193 this.set_rendered(text);
194 this.typeset();
194 this.typeset();
195 this.element.find('div.text_cell_input').hide();
195 this.element.find('div.text_cell_input').hide();
196 this.element.find("div.text_cell_render").show();
196 this.element.find("div.text_cell_render").show();
197 this.rendered = true;
197 this.rendered = true;
198 }
198 }
199 };
199 };
200
200
201
201
202 // MarkdownCell
202 // MarkdownCell
203
203
204 var MarkdownCell = function (notebook) {
204 var MarkdownCell = function (notebook) {
205 this.placeholder = "Type *Markdown* and LaTeX: $\\alpha^2$";
205 this.placeholder = "Type *Markdown* and LaTeX: $\\alpha^2$";
206 IPython.TextCell.apply(this, arguments);
206 IPython.TextCell.apply(this, arguments);
207 this.cell_type = 'markdown';
207 this.cell_type = 'markdown';
208 };
208 };
209
209
210
210
211 MarkdownCell.prototype = new TextCell();
211 MarkdownCell.prototype = new TextCell();
212
212
213
213
214 MarkdownCell.prototype.render = function () {
214 MarkdownCell.prototype.render = function () {
215 if (this.rendered === false) {
215 if (this.rendered === false) {
216 var text = this.get_text();
216 var text = this.get_text();
217 if (text === "") { text = this.placeholder; }
217 if (text === "") { text = this.placeholder; }
218 var html = IPython.markdown_converter.makeHtml(text);
218 var html = IPython.markdown_converter.makeHtml(text);
219 this.set_rendered(html);
219 this.set_rendered(html);
220 this.typeset()
220 this.typeset()
221 this.element.find('div.text_cell_input').hide();
221 this.element.find('div.text_cell_input').hide();
222 this.element.find("div.text_cell_render").show();
222 this.element.find("div.text_cell_render").show();
223 var code_snippets = this.element.find("pre > code");
223 var code_snippets = this.element.find("pre > code");
224 code_snippets.replaceWith(function () {
224 code_snippets.replaceWith(function () {
225 var code = $(this).html();
225 var code = $(this).html();
226 /* Substitute br for newlines and &nbsp; for spaces
226 /* Substitute br for newlines and &nbsp; for spaces
227 before highlighting, since prettify doesn't
227 before highlighting, since prettify doesn't
228 preserve those on all browsers */
228 preserve those on all browsers */
229 code = code.replace(/(\r\n|\n|\r)/gm, "<br/>");
229 code = code.replace(/(\r\n|\n|\r)/gm, "<br/>");
230 code = code.replace(/ /gm, '&nbsp;');
230 code = code.replace(/ /gm, '&nbsp;');
231 code = prettyPrintOne(code);
231 code = prettyPrintOne(code);
232
232
233 return '<code class="prettyprint">' + code + '</code>';
233 return '<code class="prettyprint">' + code + '</code>';
234 });
234 });
235 this.rendered = true;
235 this.rendered = true;
236 }
236 }
237 };
237 };
238
238
239
239
240 // PlaintextCell
240 // PlaintextCell
241
241
242 var PlaintextCell = function (notebook) {
242 var PlaintextCell = function (notebook) {
243 this.placeholder = "Type plain text and LaTeX: $\\alpha^2$";
243 this.placeholder = "Type plain text and LaTeX: $\\alpha^2$";
244 this.code_mirror_mode = 'rst';
244 this.code_mirror_mode = 'rst';
245 IPython.TextCell.apply(this, arguments);
245 IPython.TextCell.apply(this, arguments);
246 this.cell_type = 'plaintext';
246 this.cell_type = 'plaintext';
247 };
247 };
248
248
249
249
250 PlaintextCell.prototype = new TextCell();
250 PlaintextCell.prototype = new TextCell();
251
251
252
252
253 PlaintextCell.prototype.render = function () {
253 PlaintextCell.prototype.render = function () {
254 this.rendered = true;
254 this.rendered = true;
255 this.edit();
255 this.edit();
256 };
256 };
257
257
258
258
259 PlaintextCell.prototype.select = function () {
259 PlaintextCell.prototype.select = function () {
260 IPython.Cell.prototype.select.apply(this);
260 IPython.Cell.prototype.select.apply(this);
261 this.code_mirror.refresh();
261 this.code_mirror.refresh();
262 this.code_mirror.focus();
262 this.code_mirror.focus();
263 };
263 };
264
264
265
265
266 PlaintextCell.prototype.at_top = function () {
266 PlaintextCell.prototype.at_top = function () {
267 var cursor = this.code_mirror.getCursor();
267 var cursor = this.code_mirror.getCursor();
268 if (cursor.line === 0) {
268 if (cursor.line === 0) {
269 return true;
269 return true;
270 } else {
270 } else {
271 return false;
271 return false;
272 }
272 }
273 };
273 };
274
274
275
275
276 PlaintextCell.prototype.at_bottom = function () {
276 PlaintextCell.prototype.at_bottom = function () {
277 var cursor = this.code_mirror.getCursor();
277 var cursor = this.code_mirror.getCursor();
278 if (cursor.line === (this.code_mirror.lineCount()-1)) {
278 if (cursor.line === (this.code_mirror.lineCount()-1)) {
279 return true;
279 return true;
280 } else {
280 } else {
281 return false;
281 return false;
282 }
282 }
283 };
283 };
284
284
285
285
286 // HTMLCell
286 // HTMLCell
287
287
288 var HeadingCell = function (notebook) {
288 var HeadingCell = function (notebook) {
289 this.placeholder = "Type Heading Here";
289 this.placeholder = "Type Heading Here";
290 IPython.TextCell.apply(this, arguments);
290 IPython.TextCell.apply(this, arguments);
291 this.cell_type = 'heading';
291 this.cell_type = 'heading';
292 this.level = 1;
292 this.level = 1;
293 };
293 };
294
294
295
295
296 HeadingCell.prototype = new TextCell();
296 HeadingCell.prototype = new TextCell();
297
297
298
298
299 HeadingCell.prototype.set_level = function (level) {
299 HeadingCell.prototype.set_level = function (level) {
300 this.level = level;
300 this.level = level;
301 if (this.rendered) {
301 if (this.rendered) {
302 this.rendered = false;
302 this.rendered = false;
303 this.render();
303 this.render();
304 };
304 };
305 };
305 };
306
306
307
307
308 HeadingCell.prototype.get_level = function () {
308 HeadingCell.prototype.get_level = function () {
309 return this.level;
309 return this.level;
310 };
310 };
311
311
312
312
313 HeadingCell.prototype.set_rendered = function (text) {
313 HeadingCell.prototype.set_rendered = function (text) {
314 var r = this.element.find("div.text_cell_render");
314 var r = this.element.find("div.text_cell_render");
315 r.empty();
315 r.empty();
316 r.append($('<h'+this.level+'/>').html(text));
316 r.append($('<h'+this.level+'/>').html(text));
317 };
317 };
318
318
319
319
320 HeadingCell.prototype.get_rendered = function () {
320 HeadingCell.prototype.get_rendered = function () {
321 var r = this.element.find("div.text_cell_render");
321 var r = this.element.find("div.text_cell_render");
322 return r.children().first().html();
322 return r.children().first().html();
323 };
323 };
324
324
325
325
326 HeadingCell.prototype.render = function () {
326 HeadingCell.prototype.render = function () {
327 if (this.rendered === false) {
327 if (this.rendered === false) {
328 var text = this.get_text();
328 var text = this.get_text();
329 if (text === "") { text = this.placeholder; }
329 if (text === "") { text = this.placeholder; }
330 this.set_rendered(text);
330 this.set_rendered(text);
331 this.typeset();
331 this.typeset();
332 this.element.find('div.text_cell_input').hide();
332 this.element.find('div.text_cell_input').hide();
333 this.element.find("div.text_cell_render").show();
333 this.element.find("div.text_cell_render").show();
334 this.rendered = true;
334 this.rendered = true;
335 };
335 };
336 };
336 };
337
337
338 IPython.TextCell = TextCell;
338 IPython.TextCell = TextCell;
339 IPython.HTMLCell = HTMLCell;
339 IPython.HTMLCell = HTMLCell;
340 IPython.MarkdownCell = MarkdownCell;
340 IPython.MarkdownCell = MarkdownCell;
341 IPython.PlaintextCell = PlaintextCell;
341 IPython.PlaintextCell = PlaintextCell;
342 IPython.HeadingCell = HeadingCell;
342 IPython.HeadingCell = HeadingCell;
343
343
344
344
345 return IPython;
345 return IPython;
346
346
347 }(IPython));
347 }(IPython));
348
348
General Comments 0
You need to be logged in to leave comments. Login now