##// END OF EJS Templates
Merge pull request #3557 from minrk/target_blank...
Matthias Bussonnier -
r11220:a2db0ffd merge
parent child Browse files
Show More
@@ -1,550 +1,552 b''
1 //----------------------------------------------------------------------------
1 //----------------------------------------------------------------------------
2 // Copyright (C) 2008-2012 The IPython Development Team
2 // Copyright (C) 2008-2012 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
12
13
13
14 /**
14 /**
15 A module that allow to create different type of Text Cell
15 A module that allow to create different type of Text Cell
16 @module IPython
16 @module IPython
17 @namespace IPython
17 @namespace IPython
18 */
18 */
19 var IPython = (function (IPython) {
19 var IPython = (function (IPython) {
20
20
21 // TextCell base class
21 // TextCell base class
22 var key = IPython.utils.keycodes;
22 var key = IPython.utils.keycodes;
23
23
24 /**
24 /**
25 * Construct a new TextCell, codemirror mode is by default 'htmlmixed', and cell type is 'text'
25 * Construct a new TextCell, codemirror mode is by default 'htmlmixed', and cell type is 'text'
26 * cell start as not redered.
26 * cell start as not redered.
27 *
27 *
28 * @class TextCell
28 * @class TextCell
29 * @constructor TextCell
29 * @constructor TextCell
30 * @extend Ipython.Cell
30 * @extend Ipython.Cell
31 * @param {object|undefined} [options]
31 * @param {object|undefined} [options]
32 * @param [options.cm_config] {object} config to pass to CodeMirror, will extend/overwrite default config
32 * @param [options.cm_config] {object} config to pass to CodeMirror, will extend/overwrite default config
33 * @param [options.placeholder] {string} default string to use when souce in empty for rendering (only use in some TextCell subclass)
33 * @param [options.placeholder] {string} default string to use when souce in empty for rendering (only use in some TextCell subclass)
34 */
34 */
35 var TextCell = function (options) {
35 var TextCell = function (options) {
36 // in all TextCell/Cell subclasses
36 // in all TextCell/Cell subclasses
37 // do not assign most of members here, just pass it down
37 // do not assign most of members here, just pass it down
38 // in the options dict potentially overwriting what you wish.
38 // in the options dict potentially overwriting what you wish.
39 // they will be assigned in the base class.
39 // they will be assigned in the base class.
40
40
41 // we cannot put this as a class key as it has handle to "this".
41 // we cannot put this as a class key as it has handle to "this".
42 var cm_overwrite_options = {
42 var cm_overwrite_options = {
43 onKeyEvent: $.proxy(this.handle_codemirror_keyevent,this)
43 onKeyEvent: $.proxy(this.handle_codemirror_keyevent,this)
44 };
44 };
45
45
46 options = this.mergeopt(TextCell,options,{cm_config:cm_overwrite_options});
46 options = this.mergeopt(TextCell,options,{cm_config:cm_overwrite_options});
47
47
48 IPython.Cell.apply(this, [options]);
48 IPython.Cell.apply(this, [options]);
49
49
50
50
51 this.rendered = false;
51 this.rendered = false;
52 this.cell_type = this.cell_type || 'text';
52 this.cell_type = this.cell_type || 'text';
53 };
53 };
54
54
55 TextCell.prototype = new IPython.Cell();
55 TextCell.prototype = new IPython.Cell();
56
56
57 TextCell.options_default = {
57 TextCell.options_default = {
58 cm_config : {
58 cm_config : {
59 extraKeys: {"Tab": "indentMore","Shift-Tab" : "indentLess"},
59 extraKeys: {"Tab": "indentMore","Shift-Tab" : "indentLess"},
60 mode: 'htmlmixed',
60 mode: 'htmlmixed',
61 lineWrapping : true,
61 lineWrapping : true,
62 }
62 }
63 };
63 };
64
64
65
65
66
66
67 /**
67 /**
68 * Create the DOM element of the TextCell
68 * Create the DOM element of the TextCell
69 * @method create_element
69 * @method create_element
70 * @private
70 * @private
71 */
71 */
72 TextCell.prototype.create_element = function () {
72 TextCell.prototype.create_element = function () {
73 IPython.Cell.prototype.create_element.apply(this, arguments);
73 IPython.Cell.prototype.create_element.apply(this, arguments);
74 var cell = $("<div>").addClass('cell text_cell border-box-sizing');
74 var cell = $("<div>").addClass('cell text_cell border-box-sizing');
75 cell.attr('tabindex','2');
75 cell.attr('tabindex','2');
76
76
77 this.celltoolbar = new IPython.CellToolbar(this);
77 this.celltoolbar = new IPython.CellToolbar(this);
78 cell.append(this.celltoolbar.element);
78 cell.append(this.celltoolbar.element);
79
79
80 var input_area = $('<div/>').addClass('text_cell_input border-box-sizing');
80 var input_area = $('<div/>').addClass('text_cell_input border-box-sizing');
81 this.code_mirror = CodeMirror(input_area.get(0), this.cm_config);
81 this.code_mirror = CodeMirror(input_area.get(0), this.cm_config);
82
82
83 // The tabindex=-1 makes this div focusable.
83 // The tabindex=-1 makes this div focusable.
84 var render_area = $('<div/>').addClass('text_cell_render border-box-sizing').
84 var render_area = $('<div/>').addClass('text_cell_render border-box-sizing').
85 addClass('rendered_html').attr('tabindex','-1');
85 addClass('rendered_html').attr('tabindex','-1');
86 cell.append(input_area).append(render_area);
86 cell.append(input_area).append(render_area);
87 this.element = cell;
87 this.element = cell;
88 };
88 };
89
89
90
90
91 /**
91 /**
92 * Bind the DOM evet to cell actions
92 * Bind the DOM evet to cell actions
93 * Need to be called after TextCell.create_element
93 * Need to be called after TextCell.create_element
94 * @private
94 * @private
95 * @method bind_event
95 * @method bind_event
96 */
96 */
97 TextCell.prototype.bind_events = function () {
97 TextCell.prototype.bind_events = function () {
98 IPython.Cell.prototype.bind_events.apply(this);
98 IPython.Cell.prototype.bind_events.apply(this);
99 var that = this;
99 var that = this;
100 this.element.keydown(function (event) {
100 this.element.keydown(function (event) {
101 if (event.which === 13 && !event.shiftKey) {
101 if (event.which === 13 && !event.shiftKey) {
102 if (that.rendered) {
102 if (that.rendered) {
103 that.edit();
103 that.edit();
104 return false;
104 return false;
105 };
105 };
106 };
106 };
107 });
107 });
108 this.element.dblclick(function () {
108 this.element.dblclick(function () {
109 that.edit();
109 that.edit();
110 });
110 });
111 };
111 };
112
112
113 /**
113 /**
114 * This method gets called in CodeMirror's onKeyDown/onKeyPress
114 * This method gets called in CodeMirror's onKeyDown/onKeyPress
115 * handlers and is used to provide custom key handling.
115 * handlers and is used to provide custom key handling.
116 *
116 *
117 * Subclass should override this method to have custom handeling
117 * Subclass should override this method to have custom handeling
118 *
118 *
119 * @method handle_codemirror_keyevent
119 * @method handle_codemirror_keyevent
120 * @param {CodeMirror} editor - The codemirror instance bound to the cell
120 * @param {CodeMirror} editor - The codemirror instance bound to the cell
121 * @param {event} event -
121 * @param {event} event -
122 * @return {Boolean} `true` if CodeMirror should ignore the event, `false` Otherwise
122 * @return {Boolean} `true` if CodeMirror should ignore the event, `false` Otherwise
123 */
123 */
124 TextCell.prototype.handle_codemirror_keyevent = function (editor, event) {
124 TextCell.prototype.handle_codemirror_keyevent = function (editor, event) {
125
125
126 if (event.keyCode === 13 && (event.shiftKey || event.ctrlKey)) {
126 if (event.keyCode === 13 && (event.shiftKey || event.ctrlKey)) {
127 // Always ignore shift-enter in CodeMirror as we handle it.
127 // Always ignore shift-enter in CodeMirror as we handle it.
128 return true;
128 return true;
129 }
129 }
130 return false;
130 return false;
131 };
131 };
132
132
133 /**
133 /**
134 * Select the current cell and trigger 'focus'
134 * Select the current cell and trigger 'focus'
135 * @method select
135 * @method select
136 */
136 */
137 TextCell.prototype.select = function () {
137 TextCell.prototype.select = function () {
138 IPython.Cell.prototype.select.apply(this);
138 IPython.Cell.prototype.select.apply(this);
139 var output = this.element.find("div.text_cell_render");
139 var output = this.element.find("div.text_cell_render");
140 output.trigger('focus');
140 output.trigger('focus');
141 };
141 };
142
142
143 /**
143 /**
144 * unselect the current cell and `render` it
144 * unselect the current cell and `render` it
145 * @method unselect
145 * @method unselect
146 */
146 */
147 TextCell.prototype.unselect = function() {
147 TextCell.prototype.unselect = function() {
148 // render on selection of another cell
148 // render on selection of another cell
149 this.render();
149 this.render();
150 IPython.Cell.prototype.unselect.apply(this);
150 IPython.Cell.prototype.unselect.apply(this);
151 };
151 };
152
152
153 /**
153 /**
154 *
154 *
155 * put the current cell in edition mode
155 * put the current cell in edition mode
156 * @method edit
156 * @method edit
157 */
157 */
158 TextCell.prototype.edit = function () {
158 TextCell.prototype.edit = function () {
159 if ( this.read_only ) return;
159 if ( this.read_only ) return;
160 if (this.rendered === true) {
160 if (this.rendered === true) {
161 var text_cell = this.element;
161 var text_cell = this.element;
162 var output = text_cell.find("div.text_cell_render");
162 var output = text_cell.find("div.text_cell_render");
163 output.hide();
163 output.hide();
164 text_cell.find('div.text_cell_input').show();
164 text_cell.find('div.text_cell_input').show();
165 this.code_mirror.refresh();
165 this.code_mirror.refresh();
166 this.code_mirror.focus();
166 this.code_mirror.focus();
167 // We used to need an additional refresh() after the focus, but
167 // We used to need an additional refresh() after the focus, but
168 // it appears that this has been fixed in CM. This bug would show
168 // it appears that this has been fixed in CM. This bug would show
169 // up on FF when a newly loaded markdown cell was edited.
169 // up on FF when a newly loaded markdown cell was edited.
170 this.rendered = false;
170 this.rendered = false;
171 if (this.get_text() === this.placeholder) {
171 if (this.get_text() === this.placeholder) {
172 this.set_text('');
172 this.set_text('');
173 this.refresh();
173 this.refresh();
174 }
174 }
175 }
175 }
176 };
176 };
177
177
178
178
179 /**
179 /**
180 * Empty, Subclasses must define render.
180 * Empty, Subclasses must define render.
181 * @method render
181 * @method render
182 */
182 */
183 TextCell.prototype.render = function () {};
183 TextCell.prototype.render = function () {};
184
184
185
185
186 /**
186 /**
187 * setter: {{#crossLink "TextCell/set_text"}}{{/crossLink}}
187 * setter: {{#crossLink "TextCell/set_text"}}{{/crossLink}}
188 * @method get_text
188 * @method get_text
189 * @retrun {string} CodeMirror current text value
189 * @retrun {string} CodeMirror current text value
190 */
190 */
191 TextCell.prototype.get_text = function() {
191 TextCell.prototype.get_text = function() {
192 return this.code_mirror.getValue();
192 return this.code_mirror.getValue();
193 };
193 };
194
194
195 /**
195 /**
196 * @param {string} text - Codemiror text value
196 * @param {string} text - Codemiror text value
197 * @see TextCell#get_text
197 * @see TextCell#get_text
198 * @method set_text
198 * @method set_text
199 * */
199 * */
200 TextCell.prototype.set_text = function(text) {
200 TextCell.prototype.set_text = function(text) {
201 this.code_mirror.setValue(text);
201 this.code_mirror.setValue(text);
202 this.code_mirror.refresh();
202 this.code_mirror.refresh();
203 };
203 };
204
204
205 /**
205 /**
206 * setter :{{#crossLink "TextCell/set_rendered"}}{{/crossLink}}
206 * setter :{{#crossLink "TextCell/set_rendered"}}{{/crossLink}}
207 * @method get_rendered
207 * @method get_rendered
208 * @return {html} html of rendered element
208 * @return {html} html of rendered element
209 * */
209 * */
210 TextCell.prototype.get_rendered = function() {
210 TextCell.prototype.get_rendered = function() {
211 return this.element.find('div.text_cell_render').html();
211 return this.element.find('div.text_cell_render').html();
212 };
212 };
213
213
214 /**
214 /**
215 * @method set_rendered
215 * @method set_rendered
216 */
216 */
217 TextCell.prototype.set_rendered = function(text) {
217 TextCell.prototype.set_rendered = function(text) {
218 this.element.find('div.text_cell_render').html(text);
218 this.element.find('div.text_cell_render').html(text);
219 };
219 };
220
220
221 /**
221 /**
222 * not deprecated, but implementation wrong
222 * not deprecated, but implementation wrong
223 * @method at_top
223 * @method at_top
224 * @deprecated
224 * @deprecated
225 * @return {Boolean} true is cell rendered, false otherwise
225 * @return {Boolean} true is cell rendered, false otherwise
226 * I doubt this is what it is supposed to do
226 * I doubt this is what it is supposed to do
227 * this implementation is completly false
227 * this implementation is completly false
228 */
228 */
229 TextCell.prototype.at_top = function () {
229 TextCell.prototype.at_top = function () {
230 if (this.rendered) {
230 if (this.rendered) {
231 return true;
231 return true;
232 } else {
232 } else {
233 return false;
233 return false;
234 }
234 }
235 };
235 };
236
236
237
237
238 /**
238 /**
239 * not deprecated, but implementation wrong
239 * not deprecated, but implementation wrong
240 * @method at_bottom
240 * @method at_bottom
241 * @deprecated
241 * @deprecated
242 * @return {Boolean} true is cell rendered, false otherwise
242 * @return {Boolean} true is cell rendered, false otherwise
243 * I doubt this is what it is supposed to do
243 * I doubt this is what it is supposed to do
244 * this implementation is completly false
244 * this implementation is completly false
245 * */
245 * */
246 TextCell.prototype.at_bottom = function () {
246 TextCell.prototype.at_bottom = function () {
247 if (this.rendered) {
247 if (this.rendered) {
248 return true;
248 return true;
249 } else {
249 } else {
250 return false;
250 return false;
251 }
251 }
252 };
252 };
253
253
254 /**
254 /**
255 * Create Text cell from JSON
255 * Create Text cell from JSON
256 * @param {json} data - JSON serialized text-cell
256 * @param {json} data - JSON serialized text-cell
257 * @method fromJSON
257 * @method fromJSON
258 */
258 */
259 TextCell.prototype.fromJSON = function (data) {
259 TextCell.prototype.fromJSON = function (data) {
260 IPython.Cell.prototype.fromJSON.apply(this, arguments);
260 IPython.Cell.prototype.fromJSON.apply(this, arguments);
261 if (data.cell_type === this.cell_type) {
261 if (data.cell_type === this.cell_type) {
262 if (data.source !== undefined) {
262 if (data.source !== undefined) {
263 this.set_text(data.source);
263 this.set_text(data.source);
264 // make this value the starting point, so that we can only undo
264 // make this value the starting point, so that we can only undo
265 // to this state, instead of a blank cell
265 // to this state, instead of a blank cell
266 this.code_mirror.clearHistory();
266 this.code_mirror.clearHistory();
267 this.set_rendered(data.rendered || '');
267 this.set_rendered(data.rendered || '');
268 this.rendered = false;
268 this.rendered = false;
269 this.render();
269 this.render();
270 }
270 }
271 }
271 }
272 };
272 };
273
273
274 /** Generate JSON from cell
274 /** Generate JSON from cell
275 * @return {object} cell data serialised to json
275 * @return {object} cell data serialised to json
276 */
276 */
277 TextCell.prototype.toJSON = function () {
277 TextCell.prototype.toJSON = function () {
278 var data = IPython.Cell.prototype.toJSON.apply(this);
278 var data = IPython.Cell.prototype.toJSON.apply(this);
279 data.cell_type = this.cell_type;
279 data.cell_type = this.cell_type;
280 data.source = this.get_text();
280 data.source = this.get_text();
281 return data;
281 return data;
282 };
282 };
283
283
284
284
285 /**
285 /**
286 * @class MarkdownCell
286 * @class MarkdownCell
287 * @constructor MarkdownCell
287 * @constructor MarkdownCell
288 * @extends Ipython.HtmlCell
288 * @extends Ipython.HtmlCell
289 */
289 */
290 var MarkdownCell = function (options) {
290 var MarkdownCell = function (options) {
291 var options = options || {};
291 var options = options || {};
292
292
293 options = this.mergeopt(MarkdownCell,options);
293 options = this.mergeopt(MarkdownCell,options);
294 TextCell.apply(this, [options]);
294 TextCell.apply(this, [options]);
295
295
296 this.cell_type = 'markdown';
296 this.cell_type = 'markdown';
297 };
297 };
298
298
299 MarkdownCell.options_default = {
299 MarkdownCell.options_default = {
300 cm_config: {
300 cm_config: {
301 mode: 'gfm'
301 mode: 'gfm'
302 },
302 },
303 placeholder: "Type *Markdown* and LaTeX: $\\alpha^2$"
303 placeholder: "Type *Markdown* and LaTeX: $\\alpha^2$"
304 }
304 }
305
305
306
306
307
307
308
308
309 MarkdownCell.prototype = new TextCell();
309 MarkdownCell.prototype = new TextCell();
310
310
311 /**
311 /**
312 * @method render
312 * @method render
313 */
313 */
314 MarkdownCell.prototype.render = function () {
314 MarkdownCell.prototype.render = function () {
315 if (this.rendered === false) {
315 if (this.rendered === false) {
316 var text = this.get_text();
316 var text = this.get_text();
317 if (text === "") { text = this.placeholder; }
317 if (text === "") { text = this.placeholder; }
318 text = IPython.mathjaxutils.remove_math(text);
318 text = IPython.mathjaxutils.remove_math(text);
319 var html = marked.parser(marked.lexer(text));
319 var html = marked.parser(marked.lexer(text));
320 html = IPython.mathjaxutils.replace_math(html);
320 html = $(IPython.mathjaxutils.replace_math(html));
321 // links in markdown cells should open in new tabs
322 html.find("a[href]").attr("target", "_blank");
321 try {
323 try {
322 this.set_rendered(html);
324 this.set_rendered(html);
323 } catch (e) {
325 } catch (e) {
324 console.log("Error running Javascript in Markdown:");
326 console.log("Error running Javascript in Markdown:");
325 console.log(e);
327 console.log(e);
326 this.set_rendered($("<div/>").addClass("js-error").html(
328 this.set_rendered($("<div/>").addClass("js-error").html(
327 "Error rendering Markdown!<br/>" + e.toString())
329 "Error rendering Markdown!<br/>" + e.toString())
328 );
330 );
329 }
331 }
330 this.element.find('div.text_cell_input').hide();
332 this.element.find('div.text_cell_input').hide();
331 this.element.find("div.text_cell_render").show();
333 this.element.find("div.text_cell_render").show();
332 this.typeset()
334 this.typeset()
333 this.rendered = true;
335 this.rendered = true;
334 }
336 }
335 };
337 };
336
338
337
339
338 // RawCell
340 // RawCell
339
341
340 /**
342 /**
341 * @class RawCell
343 * @class RawCell
342 * @constructor RawCell
344 * @constructor RawCell
343 * @extends Ipython.TextCell
345 * @extends Ipython.TextCell
344 */
346 */
345 var RawCell = function (options) {
347 var RawCell = function (options) {
346
348
347 options = this.mergeopt(RawCell,options)
349 options = this.mergeopt(RawCell,options)
348 TextCell.apply(this, [options]);
350 TextCell.apply(this, [options]);
349
351
350 this.cell_type = 'raw';
352 this.cell_type = 'raw';
351
353
352 var that = this
354 var that = this
353 this.element.focusout(
355 this.element.focusout(
354 function() { that.auto_highlight(); }
356 function() { that.auto_highlight(); }
355 );
357 );
356 };
358 };
357
359
358 RawCell.options_default = {
360 RawCell.options_default = {
359 placeholder : "Type plain text and LaTeX: $\\alpha^2$"
361 placeholder : "Type plain text and LaTeX: $\\alpha^2$"
360 };
362 };
361
363
362
364
363
365
364 RawCell.prototype = new TextCell();
366 RawCell.prototype = new TextCell();
365
367
366 /**
368 /**
367 * Trigger autodetection of highlight scheme for current cell
369 * Trigger autodetection of highlight scheme for current cell
368 * @method auto_highlight
370 * @method auto_highlight
369 */
371 */
370 RawCell.prototype.auto_highlight = function () {
372 RawCell.prototype.auto_highlight = function () {
371 this._auto_highlight(IPython.config.raw_cell_highlight);
373 this._auto_highlight(IPython.config.raw_cell_highlight);
372 };
374 };
373
375
374 /** @method render **/
376 /** @method render **/
375 RawCell.prototype.render = function () {
377 RawCell.prototype.render = function () {
376 this.rendered = true;
378 this.rendered = true;
377 this.edit();
379 this.edit();
378 };
380 };
379
381
380
382
381 /** @method handle_codemirror_keyevent **/
383 /** @method handle_codemirror_keyevent **/
382 RawCell.prototype.handle_codemirror_keyevent = function (editor, event) {
384 RawCell.prototype.handle_codemirror_keyevent = function (editor, event) {
383
385
384 var that = this;
386 var that = this;
385 if (event.which === key.UPARROW && event.type === 'keydown') {
387 if (event.which === key.UPARROW && event.type === 'keydown') {
386 // If we are not at the top, let CM handle the up arrow and
388 // If we are not at the top, let CM handle the up arrow and
387 // prevent the global keydown handler from handling it.
389 // prevent the global keydown handler from handling it.
388 if (!that.at_top()) {
390 if (!that.at_top()) {
389 event.stop();
391 event.stop();
390 return false;
392 return false;
391 } else {
393 } else {
392 return true;
394 return true;
393 };
395 };
394 } else if (event.which === key.DOWNARROW && event.type === 'keydown') {
396 } else if (event.which === key.DOWNARROW && event.type === 'keydown') {
395 // If we are not at the bottom, let CM handle the down arrow and
397 // If we are not at the bottom, let CM handle the down arrow and
396 // prevent the global keydown handler from handling it.
398 // prevent the global keydown handler from handling it.
397 if (!that.at_bottom()) {
399 if (!that.at_bottom()) {
398 event.stop();
400 event.stop();
399 return false;
401 return false;
400 } else {
402 } else {
401 return true;
403 return true;
402 };
404 };
403 };
405 };
404 return false;
406 return false;
405 };
407 };
406
408
407 /** @method select **/
409 /** @method select **/
408 RawCell.prototype.select = function () {
410 RawCell.prototype.select = function () {
409 IPython.Cell.prototype.select.apply(this);
411 IPython.Cell.prototype.select.apply(this);
410 this.code_mirror.refresh();
412 this.code_mirror.refresh();
411 this.code_mirror.focus();
413 this.code_mirror.focus();
412 };
414 };
413
415
414 /** @method at_top **/
416 /** @method at_top **/
415 RawCell.prototype.at_top = function () {
417 RawCell.prototype.at_top = function () {
416 var cursor = this.code_mirror.getCursor();
418 var cursor = this.code_mirror.getCursor();
417 if (cursor.line === 0 && cursor.ch === 0) {
419 if (cursor.line === 0 && cursor.ch === 0) {
418 return true;
420 return true;
419 } else {
421 } else {
420 return false;
422 return false;
421 }
423 }
422 };
424 };
423
425
424
426
425 /** @method at_bottom **/
427 /** @method at_bottom **/
426 RawCell.prototype.at_bottom = function () {
428 RawCell.prototype.at_bottom = function () {
427 var cursor = this.code_mirror.getCursor();
429 var cursor = this.code_mirror.getCursor();
428 if (cursor.line === (this.code_mirror.lineCount()-1) && cursor.ch === this.code_mirror.getLine(cursor.line).length) {
430 if (cursor.line === (this.code_mirror.lineCount()-1) && cursor.ch === this.code_mirror.getLine(cursor.line).length) {
429 return true;
431 return true;
430 } else {
432 } else {
431 return false;
433 return false;
432 }
434 }
433 };
435 };
434
436
435
437
436 /**
438 /**
437 * @class HeadingCell
439 * @class HeadingCell
438 * @extends Ipython.TextCell
440 * @extends Ipython.TextCell
439 */
441 */
440
442
441 /**
443 /**
442 * @constructor HeadingCell
444 * @constructor HeadingCell
443 * @extends Ipython.TextCell
445 * @extends Ipython.TextCell
444 */
446 */
445 var HeadingCell = function (options) {
447 var HeadingCell = function (options) {
446
448
447 options = this.mergeopt(HeadingCell,options)
449 options = this.mergeopt(HeadingCell,options)
448 TextCell.apply(this, [options]);
450 TextCell.apply(this, [options]);
449
451
450 /**
452 /**
451 * heading level of the cell, use getter and setter to access
453 * heading level of the cell, use getter and setter to access
452 * @property level
454 * @property level
453 */
455 */
454 this.level = 1;
456 this.level = 1;
455 this.cell_type = 'heading';
457 this.cell_type = 'heading';
456 };
458 };
457
459
458 HeadingCell.options_default = {
460 HeadingCell.options_default = {
459 placeholder: "Type Heading Here"
461 placeholder: "Type Heading Here"
460 };
462 };
461
463
462 HeadingCell.prototype = new TextCell();
464 HeadingCell.prototype = new TextCell();
463
465
464 /** @method fromJSON */
466 /** @method fromJSON */
465 HeadingCell.prototype.fromJSON = function (data) {
467 HeadingCell.prototype.fromJSON = function (data) {
466 if (data.level != undefined){
468 if (data.level != undefined){
467 this.level = data.level;
469 this.level = data.level;
468 }
470 }
469 TextCell.prototype.fromJSON.apply(this, arguments);
471 TextCell.prototype.fromJSON.apply(this, arguments);
470 };
472 };
471
473
472
474
473 /** @method toJSON */
475 /** @method toJSON */
474 HeadingCell.prototype.toJSON = function () {
476 HeadingCell.prototype.toJSON = function () {
475 var data = TextCell.prototype.toJSON.apply(this);
477 var data = TextCell.prototype.toJSON.apply(this);
476 data.level = this.get_level();
478 data.level = this.get_level();
477 return data;
479 return data;
478 };
480 };
479
481
480
482
481 /**
483 /**
482 * Change heading level of cell, and re-render
484 * Change heading level of cell, and re-render
483 * @method set_level
485 * @method set_level
484 */
486 */
485 HeadingCell.prototype.set_level = function (level) {
487 HeadingCell.prototype.set_level = function (level) {
486 this.level = level;
488 this.level = level;
487 if (this.rendered) {
489 if (this.rendered) {
488 this.rendered = false;
490 this.rendered = false;
489 this.render();
491 this.render();
490 };
492 };
491 };
493 };
492
494
493 /** The depth of header cell, based on html (h1 to h6)
495 /** The depth of header cell, based on html (h1 to h6)
494 * @method get_level
496 * @method get_level
495 * @return {integer} level - for 1 to 6
497 * @return {integer} level - for 1 to 6
496 */
498 */
497 HeadingCell.prototype.get_level = function () {
499 HeadingCell.prototype.get_level = function () {
498 return this.level;
500 return this.level;
499 };
501 };
500
502
501
503
502 HeadingCell.prototype.set_rendered = function (text) {
504 HeadingCell.prototype.set_rendered = function (text) {
503 var r = this.element.find("div.text_cell_render");
505 var r = this.element.find("div.text_cell_render");
504 r.empty();
506 r.empty();
505 var link = text.replace(/ /g, '_');
507 var link = text.replace(/ /g, '_');
506 r.append(
508 r.append(
507 $('<h'+this.level+'/>')
509 $('<h'+this.level+'/>')
508 .append(
510 .append(
509 $('<a/>')
511 $('<a/>')
510 .addClass('heading-anchor')
512 .addClass('heading-anchor')
511 .attr('id', link)
513 .attr('id', link)
512 .html(text)
514 .html(text)
513 ).append(
515 ).append(
514 $('<a/>')
516 $('<a/>')
515 .addClass('anchor-link')
517 .addClass('anchor-link')
516 .attr('href', '#' + link)
518 .attr('href', '#' + link)
517 .text('ΒΆ')
519 .text('ΒΆ')
518 )
520 )
519 );
521 );
520 };
522 };
521
523
522
524
523 HeadingCell.prototype.get_rendered = function () {
525 HeadingCell.prototype.get_rendered = function () {
524 var r = this.element.find("div.text_cell_render");
526 var r = this.element.find("div.text_cell_render");
525 return r.children().first().html();
527 return r.children().first().html();
526 };
528 };
527
529
528
530
529 HeadingCell.prototype.render = function () {
531 HeadingCell.prototype.render = function () {
530 if (this.rendered === false) {
532 if (this.rendered === false) {
531 var text = this.get_text();
533 var text = this.get_text();
532 if (text === "") { text = this.placeholder; }
534 if (text === "") { text = this.placeholder; }
533 this.set_rendered(text);
535 this.set_rendered(text);
534 this.typeset();
536 this.typeset();
535 this.element.find('div.text_cell_input').hide();
537 this.element.find('div.text_cell_input').hide();
536 this.element.find("div.text_cell_render").show();
538 this.element.find("div.text_cell_render").show();
537 this.rendered = true;
539 this.rendered = true;
538 };
540 };
539 };
541 };
540
542
541 IPython.TextCell = TextCell;
543 IPython.TextCell = TextCell;
542 IPython.MarkdownCell = MarkdownCell;
544 IPython.MarkdownCell = MarkdownCell;
543 IPython.RawCell = RawCell;
545 IPython.RawCell = RawCell;
544 IPython.HeadingCell = HeadingCell;
546 IPython.HeadingCell = HeadingCell;
545
547
546
548
547 return IPython;
549 return IPython;
548
550
549 }(IPython));
551 }(IPython));
550
552
General Comments 0
You need to be logged in to leave comments. Login now