##// END OF EJS Templates
Refactored to JS standards. Fixed Attribution....
Aron Ahmadia -
Show More
@@ -1,239 +1,243 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 // MathJax utility functions
9 // MathJax utility functions
10 //============================================================================
10 //============================================================================
11
11
12 IPython.namespace('IPython.mathjaxutils');
12 IPython.namespace('IPython.mathjaxutils');
13
13
14 IPython.mathjaxutils = (function (IPython) {
14 IPython.mathjaxutils = (function (IPython) {
15
15
16 var init = function () {
16 var init = function () {
17 if (window.MathJax) {
17 if (window.MathJax) {
18 // MathJax loaded
18 // MathJax loaded
19 MathJax.Hub.Config({
19 MathJax.Hub.Config({
20 TeX: { equationNumbers: { autoNumber: "AMS", useLabelIds: true } },
20 TeX: { equationNumbers: { autoNumber: "AMS", useLabelIds: true } },
21 tex2jax: {
21 tex2jax: {
22 inlineMath: [ ['$','$'], ["\\(","\\)"] ],
22 inlineMath: [ ['$','$'], ["\\(","\\)"] ],
23 displayMath: [ ['$$','$$'], ["\\[","\\]"] ],
23 displayMath: [ ['$$','$$'], ["\\[","\\]"] ],
24 processEnvironments: true
24 processEnvironments: true
25 },
25 },
26 displayAlign: 'left', // Change this to 'center' to center equations.
26 displayAlign: 'left', // Change this to 'center' to center equations.
27 "HTML-CSS": {
27 "HTML-CSS": {
28 styles: {'.MathJax_Display': {"margin": 0}}
28 styles: {'.MathJax_Display': {"margin": 0}}
29 }
29 }
30 });
30 });
31 } else if (window.mathjax_url != "") {
31 } else if (window.mathjax_url != "") {
32 // Don't have MathJax, but should. Show dialog.
32 // Don't have MathJax, but should. Show dialog.
33 var dialog = $('<div></div>')
33 var dialog = $('<div></div>')
34 .append(
34 .append(
35 $("<p></p>").addClass('dialog').html(
35 $("<p></p>").addClass('dialog').html(
36 "Math/LaTeX rendering will be disabled."
36 "Math/LaTeX rendering will be disabled."
37 )
37 )
38 ).append(
38 ).append(
39 $("<p></p>").addClass('dialog').html(
39 $("<p></p>").addClass('dialog').html(
40 "If you have administrative access to the notebook server and" +
40 "If you have administrative access to the notebook server and" +
41 " a working internet connection, you can install a local copy" +
41 " a working internet connection, you can install a local copy" +
42 " of MathJax for offline use with the following command on the server" +
42 " of MathJax for offline use with the following command on the server" +
43 " at a Python or IPython prompt:"
43 " at a Python or IPython prompt:"
44 )
44 )
45 ).append(
45 ).append(
46 $("<pre></pre>").addClass('dialog').html(
46 $("<pre></pre>").addClass('dialog').html(
47 ">>> from IPython.external import mathjax; mathjax.install_mathjax()"
47 ">>> from IPython.external import mathjax; mathjax.install_mathjax()"
48 )
48 )
49 ).append(
49 ).append(
50 $("<p></p>").addClass('dialog').html(
50 $("<p></p>").addClass('dialog').html(
51 "This will try to install MathJax into the IPython source directory."
51 "This will try to install MathJax into the IPython source directory."
52 )
52 )
53 ).append(
53 ).append(
54 $("<p></p>").addClass('dialog').html(
54 $("<p></p>").addClass('dialog').html(
55 "If IPython is installed to a location that requires" +
55 "If IPython is installed to a location that requires" +
56 " administrative privileges to write, you will need to make this call as" +
56 " administrative privileges to write, you will need to make this call as" +
57 " an administrator, via 'sudo'."
57 " an administrator, via 'sudo'."
58 )
58 )
59 ).append(
59 ).append(
60 $("<p></p>").addClass('dialog').html(
60 $("<p></p>").addClass('dialog').html(
61 "When you start the notebook server, you can instruct it to disable MathJax support altogether:"
61 "When you start the notebook server, you can instruct it to disable MathJax support altogether:"
62 )
62 )
63 ).append(
63 ).append(
64 $("<pre></pre>").addClass('dialog').html(
64 $("<pre></pre>").addClass('dialog').html(
65 "$ ipython notebook --no-mathjax"
65 "$ ipython notebook --no-mathjax"
66 )
66 )
67 ).append(
67 ).append(
68 $("<p></p>").addClass('dialog').html(
68 $("<p></p>").addClass('dialog').html(
69 "which will prevent this dialog from appearing."
69 "which will prevent this dialog from appearing."
70 )
70 )
71 ).dialog({
71 ).dialog({
72 title: "Failed to retrieve MathJax from '" + window.mathjax_url + "'",
72 title: "Failed to retrieve MathJax from '" + window.mathjax_url + "'",
73 width: "70%",
73 width: "70%",
74 modal: true,
74 modal: true,
75 })
75 })
76 } else {
76 } else {
77 // No MathJax, but none expected. No dialog.
77 // No MathJax, but none expected. No dialog.
78 };
78 };
79 };
79 };
80
80
81 // Some magic for deferring mathematical expressions to MathJaX
81 // Some magic for deferring mathematical expressions to MathJax
82 // Some of the code here is adapted with permission from Stack Exchange Inc.
82 // by hiding them from the Markdown parser.
83 // Some of the code here is adapted with permission from Davide Cervone
84 // under the terms of the Apache2 license governing the MathJax project.
85 // Other minor modifications are also due to StackExchange and are used with
86 // permission.
83
87
84 var inline = "$"; // the inline math delimiter
88 var inline = "$"; // the inline math delimiter
85 var blocks, start, end, last, braces; // used in searching for math
89 var blocks, start, end, last, braces; // used in searching for math
86 var math; // stores math until pagedown (Markdown parser) is done
90 var math; // stores math until pagedown (Markdown parser) is done
87 var HUB = MathJax.Hub;
91 var HUB = MathJax.Hub;
88
92
89 // MATHSPLIT contains the pattern for math delimiters and special symbols
93 // MATHSPLIT contains the pattern for math delimiters and special symbols
90 // needed for searching for math in the text input.
94 // needed for searching for math in the text input.
91 var MATHSPLIT = /(\$\$?|\\(?:begin|end)\{[a-z]*\*?\}|\\[\\{}$]|[{}]|(?:\n\s*)+|@@\d+@@)/i;
95 var MATHSPLIT = /(\$\$?|\\(?:begin|end)\{[a-z]*\*?\}|\\[\\{}$]|[{}]|(?:\n\s*)+|@@\d+@@)/i;
92
96
93 // The math is in blocks i through j, so
97 // The math is in blocks i through j, so
94 // collect it into one block and clear the others.
98 // collect it into one block and clear the others.
95 // Replace &, <, and > by named entities.
99 // Replace &, <, and > by named entities.
96 // For IE, put <br> at the ends of comments since IE removes \n.
100 // For IE, put <br> at the ends of comments since IE removes \n.
97 // Clear the current math positions and store the index of the
101 // Clear the current math positions and store the index of the
98 // math, then push the math string onto the storage array.
102 // math, then push the math string onto the storage array.
99 // The preProcess function is called on all blocks if it has been passed in
103 // The preProcess function is called on all blocks if it has been passed in
100 function processMath(i, j, preProcess) {
104 var process_math = function (i, j, pre_process) {
101 var block = blocks.slice(i, j + 1).join("").replace(/&/g, "&amp;") // use HTML entity for &
105 var block = blocks.slice(i, j + 1).join("").replace(/&/g, "&amp;") // use HTML entity for &
102 .replace(/</g, "&lt;") // use HTML entity for <
106 .replace(/</g, "&lt;") // use HTML entity for <
103 .replace(/>/g, "&gt;") // use HTML entity for >
107 .replace(/>/g, "&gt;") // use HTML entity for >
104 ;
108 ;
105 if (HUB.Browser.isMSIE) {
109 if (HUB.Browser.isMSIE) {
106 block = block.replace(/(%[^\n]*)\n/g, "$1<br/>\n")
110 block = block.replace(/(%[^\n]*)\n/g, "$1<br/>\n")
107 }
111 }
108 while (j > i) {
112 while (j > i) {
109 blocks[j] = "";
113 blocks[j] = "";
110 j--;
114 j--;
111 }
115 }
112 blocks[i] = "@@" + math.length + "@@"; // replace the current block text with a unique tag to find later
116 blocks[i] = "@@" + math.length + "@@"; // replace the current block text with a unique tag to find later
113 if (preProcess)
117 if (pre_process)
114 block = preProcess(block);
118 block = pre_process(block);
115 math.push(block);
119 math.push(block);
116 start = end = last = null;
120 start = end = last = null;
117 }
121 }
118
122
119 // Break up the text into its component parts and search
123 // Break up the text into its component parts and search
120 // through them for math delimiters, braces, linebreaks, etc.
124 // through them for math delimiters, braces, linebreaks, etc.
121 // Math delimiters must match and braces must balance.
125 // Math delimiters must match and braces must balance.
122 // Don't allow math to pass through a double linebreak
126 // Don't allow math to pass through a double linebreak
123 // (which will be a paragraph).
127 // (which will be a paragraph).
124 //
128 //
125 function removeMath(text) {
129 var remove_math = function (text) {
126 start = end = last = null; // for tracking math delimiters
130 start = end = last = null; // for tracking math delimiters
127 math = []; // stores math strings for later
131 math = []; // stores math strings for later
128
132
129 // Except for extreme edge cases, this should catch precisely those pieces of the markdown
133 // Except for extreme edge cases, this should catch precisely those pieces of the markdown
130 // source that will later be turned into code spans. While MathJax will not TeXify code spans,
134 // source that will later be turned into code spans. While MathJax will not TeXify code spans,
131 // we still have to consider them at this point; the following issue has happened several times:
135 // we still have to consider them at this point; the following issue has happened several times:
132 //
136 //
133 // `$foo` and `$bar` are varibales. --> <code>$foo ` and `$bar</code> are variables.
137 // `$foo` and `$bar` are varibales. --> <code>$foo ` and `$bar</code> are variables.
134
138
135 var hasCodeSpans = /`/.test(text),
139 var hasCodeSpans = /`/.test(text),
136 deTilde;
140 de_tilde;
137 if (hasCodeSpans) {
141 if (hasCodeSpans) {
138 text = text.replace(/~/g, "~T").replace(/(^|[^\\])(`+)([^\n]*?[^`\n])\2(?!`)/gm, function (wholematch) {
142 text = text.replace(/~/g, "~T").replace(/(^|[^\\])(`+)([^\n]*?[^`\n])\2(?!`)/gm, function (wholematch) {
139 return wholematch.replace(/\$/g, "~D");
143 return wholematch.replace(/\$/g, "~D");
140 });
144 });
141 deTilde = function (text) { return text.replace(/~([TD])/g, function (wholematch, character) { return { T: "~", D: "$" }[character]; }) };
145 de_tilde = function (text) { return text.replace(/~([TD])/g, function (wholematch, character) { return { T: "~", D: "$" }[character]; }) };
142 } else {
146 } else {
143 deTilde = function (text) { return text; };
147 de_tilde = function (text) { return text; };
144 }
148 }
145
149
146 blocks = IPython.utils.regex_split(text.replace(/\r\n?/g, "\n"),MATHSPLIT);
150 blocks = IPython.utils.regex_split(text.replace(/\r\n?/g, "\n"),MATHSPLIT);
147
151
148 for (var i = 1, m = blocks.length; i < m; i += 2) {
152 for (var i = 1, m = blocks.length; i < m; i += 2) {
149 var block = blocks[i];
153 var block = blocks[i];
150 if (block.charAt(0) === "@") {
154 if (block.charAt(0) === "@") {
151 //
155 //
152 // Things that look like our math markers will get
156 // Things that look like our math markers will get
153 // stored and then retrieved along with the math.
157 // stored and then retrieved along with the math.
154 //
158 //
155 blocks[i] = "@@" + math.length + "@@";
159 blocks[i] = "@@" + math.length + "@@";
156 math.push(block);
160 math.push(block);
157 }
161 }
158 else if (start) {
162 else if (start) {
159 //
163 //
160 // If we are in math, look for the end delimiter,
164 // If we are in math, look for the end delimiter,
161 // but don't go past double line breaks, and
165 // but don't go past double line breaks, and
162 // and balance braces within the math.
166 // and balance braces within the math.
163 //
167 //
164 if (block === end) {
168 if (block === end) {
165 if (braces) {
169 if (braces) {
166 last = i
170 last = i
167 }
171 }
168 else {
172 else {
169 processMath(start, i, deTilde)
173 process_math(start, i, de_tilde)
170 }
174 }
171 }
175 }
172 else if (block.match(/\n.*\n/)) {
176 else if (block.match(/\n.*\n/)) {
173 if (last) {
177 if (last) {
174 i = last;
178 i = last;
175 processMath(start, i, deTilde)
179 process_math(start, i, de_tilde)
176 }
180 }
177 start = end = last = null;
181 start = end = last = null;
178 braces = 0;
182 braces = 0;
179 }
183 }
180 else if (block === "{") {
184 else if (block === "{") {
181 braces++
185 braces++
182 }
186 }
183 else if (block === "}" && braces) {
187 else if (block === "}" && braces) {
184 braces--
188 braces--
185 }
189 }
186 }
190 }
187 else {
191 else {
188 //
192 //
189 // Look for math start delimiters and when
193 // Look for math start delimiters and when
190 // found, set up the end delimiter.
194 // found, set up the end delimiter.
191 //
195 //
192 if (block === inline || block === "$$") {
196 if (block === inline || block === "$$") {
193 start = i;
197 start = i;
194 end = block;
198 end = block;
195 braces = 0;
199 braces = 0;
196 }
200 }
197 else if (block.substr(1, 5) === "begin") {
201 else if (block.substr(1, 5) === "begin") {
198 start = i;
202 start = i;
199 end = "\\end" + block.substr(6);
203 end = "\\end" + block.substr(6);
200 braces = 0;
204 braces = 0;
201 }
205 }
202 }
206 }
203 }
207 }
204 if (last) {
208 if (last) {
205 processMath(start, last, deTilde)
209 process_math(start, last, de_tilde)
206 }
210 }
207 return deTilde(blocks.join(""));
211 return de_tilde(blocks.join(""));
208 }
212 }
209
213
210 //
214 //
211 // Put back the math strings that were saved,
215 // Put back the math strings that were saved,
212 // and clear the math array (no need to keep it around).
216 // and clear the math array (no need to keep it around).
213 //
217 //
214 function replaceMath(text) {
218 var replace_math = function (text) {
215 text = text.replace(/@@(\d+)@@/g, function (match, n) {
219 text = text.replace(/@@(\d+)@@/g, function (match, n) {
216 return math[n]
220 return math[n]
217 });
221 });
218 math = null;
222 math = null;
219 return text;
223 return text;
220 }
224 }
221
225
222 function queueRender() {
226 var queue_render = function () {
223 // see https://groups.google.com/forum/?fromgroups=#!topic/mathjax-users/cpwy5eCH1ZQ
227 // see https://groups.google.com/forum/?fromgroups=#!topic/mathjax-users/cpwy5eCH1ZQ
224 MathJax.Hub.Queue(
228 MathJax.Hub.Queue(
225 ["resetEquationNumbers",MathJax.InputJax.TeX],
229 ["resetEquationNumbers",MathJax.InputJax.TeX],
226 ["PreProcess",MathJax.Hub],
230 ["PreProcess",MathJax.Hub],
227 ["Reprocess",MathJax.Hub]
231 ["Reprocess",MathJax.Hub]
228 );
232 );
229 }
233 }
230
234
231 return {
235 return {
232 init : init,
236 init : init,
233 processMath : processMath,
237 process_math : process_math,
234 removeMath : removeMath,
238 remove_math : remove_math,
235 replaceMath : replaceMath,
239 replace_math : replace_math,
236 queueRender : queueRender
240 queue_render : queue_render
237 };
241 };
238
242
239 }(IPython)); No newline at end of file
243 }(IPython));
@@ -1,421 +1,421 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 var IPython = (function (IPython) {
12 var IPython = (function (IPython) {
13
13
14 // TextCell base class
14 // TextCell base class
15 var key = IPython.utils.keycodes;
15 var key = IPython.utils.keycodes;
16
16
17 var TextCell = function () {
17 var TextCell = function () {
18 this.code_mirror_mode = this.code_mirror_mode || 'htmlmixed';
18 this.code_mirror_mode = this.code_mirror_mode || 'htmlmixed';
19 IPython.Cell.apply(this, arguments);
19 IPython.Cell.apply(this, arguments);
20 this.rendered = false;
20 this.rendered = false;
21 this.cell_type = this.cell_type || 'text';
21 this.cell_type = this.cell_type || 'text';
22 };
22 };
23
23
24
24
25 TextCell.prototype = new IPython.Cell();
25 TextCell.prototype = new IPython.Cell();
26
26
27
27
28 TextCell.prototype.create_element = function () {
28 TextCell.prototype.create_element = function () {
29 var cell = $("<div>").addClass('cell text_cell border-box-sizing');
29 var cell = $("<div>").addClass('cell text_cell border-box-sizing');
30 cell.attr('tabindex','2');
30 cell.attr('tabindex','2');
31 var input_area = $('<div/>').addClass('text_cell_input border-box-sizing');
31 var input_area = $('<div/>').addClass('text_cell_input border-box-sizing');
32 this.code_mirror = CodeMirror(input_area.get(0), {
32 this.code_mirror = CodeMirror(input_area.get(0), {
33 indentUnit : 4,
33 indentUnit : 4,
34 mode: this.code_mirror_mode,
34 mode: this.code_mirror_mode,
35 theme: 'default',
35 theme: 'default',
36 value: this.placeholder,
36 value: this.placeholder,
37 readOnly: this.read_only,
37 readOnly: this.read_only,
38 lineWrapping : true,
38 lineWrapping : true,
39 extraKeys: {"Tab": "indentMore","Shift-Tab" : "indentLess"},
39 extraKeys: {"Tab": "indentMore","Shift-Tab" : "indentLess"},
40 onKeyEvent: $.proxy(this.handle_codemirror_keyevent,this)
40 onKeyEvent: $.proxy(this.handle_codemirror_keyevent,this)
41 });
41 });
42 // The tabindex=-1 makes this div focusable.
42 // The tabindex=-1 makes this div focusable.
43 var render_area = $('<div/>').addClass('text_cell_render border-box-sizing').
43 var render_area = $('<div/>').addClass('text_cell_render border-box-sizing').
44 addClass('rendered_html').attr('tabindex','-1');
44 addClass('rendered_html').attr('tabindex','-1');
45 cell.append(input_area).append(render_area);
45 cell.append(input_area).append(render_area);
46 this.element = cell;
46 this.element = cell;
47 };
47 };
48
48
49
49
50 TextCell.prototype.bind_events = function () {
50 TextCell.prototype.bind_events = function () {
51 IPython.Cell.prototype.bind_events.apply(this);
51 IPython.Cell.prototype.bind_events.apply(this);
52 var that = this;
52 var that = this;
53 this.element.keydown(function (event) {
53 this.element.keydown(function (event) {
54 if (event.which === 13 && !event.shiftKey) {
54 if (event.which === 13 && !event.shiftKey) {
55 if (that.rendered) {
55 if (that.rendered) {
56 that.edit();
56 that.edit();
57 return false;
57 return false;
58 };
58 };
59 };
59 };
60 });
60 });
61 this.element.dblclick(function () {
61 this.element.dblclick(function () {
62 that.edit();
62 that.edit();
63 });
63 });
64 };
64 };
65
65
66
66
67 TextCell.prototype.handle_codemirror_keyevent = function (editor, event) {
67 TextCell.prototype.handle_codemirror_keyevent = function (editor, event) {
68 // This method gets called in CodeMirror's onKeyDown/onKeyPress
68 // This method gets called in CodeMirror's onKeyDown/onKeyPress
69 // handlers and is used to provide custom key handling. Its return
69 // handlers and is used to provide custom key handling. Its return
70 // value is used to determine if CodeMirror should ignore the event:
70 // value is used to determine if CodeMirror should ignore the event:
71 // true = ignore, false = don't ignore.
71 // true = ignore, false = don't ignore.
72
72
73 if (event.keyCode === 13 && (event.shiftKey || event.ctrlKey)) {
73 if (event.keyCode === 13 && (event.shiftKey || event.ctrlKey)) {
74 // Always ignore shift-enter in CodeMirror as we handle it.
74 // Always ignore shift-enter in CodeMirror as we handle it.
75 return true;
75 return true;
76 }
76 }
77 return false;
77 return false;
78 };
78 };
79
79
80
80
81 TextCell.prototype.select = function () {
81 TextCell.prototype.select = function () {
82 IPython.Cell.prototype.select.apply(this);
82 IPython.Cell.prototype.select.apply(this);
83 var output = this.element.find("div.text_cell_render");
83 var output = this.element.find("div.text_cell_render");
84 output.trigger('focus');
84 output.trigger('focus');
85 };
85 };
86
86
87
87
88 TextCell.prototype.unselect = function() {
88 TextCell.prototype.unselect = function() {
89 // render on selection of another cell
89 // render on selection of another cell
90 this.render();
90 this.render();
91 IPython.Cell.prototype.unselect.apply(this);
91 IPython.Cell.prototype.unselect.apply(this);
92 };
92 };
93
93
94
94
95 TextCell.prototype.edit = function () {
95 TextCell.prototype.edit = function () {
96 if ( this.read_only ) return;
96 if ( this.read_only ) return;
97 if (this.rendered === true) {
97 if (this.rendered === true) {
98 var text_cell = this.element;
98 var text_cell = this.element;
99 var output = text_cell.find("div.text_cell_render");
99 var output = text_cell.find("div.text_cell_render");
100 output.hide();
100 output.hide();
101 text_cell.find('div.text_cell_input').show();
101 text_cell.find('div.text_cell_input').show();
102 this.code_mirror.refresh();
102 this.code_mirror.refresh();
103 this.code_mirror.focus();
103 this.code_mirror.focus();
104 // We used to need an additional refresh() after the focus, but
104 // We used to need an additional refresh() after the focus, but
105 // it appears that this has been fixed in CM. This bug would show
105 // it appears that this has been fixed in CM. This bug would show
106 // up on FF when a newly loaded markdown cell was edited.
106 // up on FF when a newly loaded markdown cell was edited.
107 this.rendered = false;
107 this.rendered = false;
108 if (this.get_text() === this.placeholder) {
108 if (this.get_text() === this.placeholder) {
109 this.set_text('');
109 this.set_text('');
110 this.refresh();
110 this.refresh();
111 }
111 }
112 }
112 }
113 };
113 };
114
114
115
115
116 // Subclasses must define render.
116 // Subclasses must define render.
117 TextCell.prototype.render = function () {};
117 TextCell.prototype.render = function () {};
118
118
119
119
120 TextCell.prototype.get_text = function() {
120 TextCell.prototype.get_text = function() {
121 return this.code_mirror.getValue();
121 return this.code_mirror.getValue();
122 };
122 };
123
123
124
124
125 TextCell.prototype.set_text = function(text) {
125 TextCell.prototype.set_text = function(text) {
126 this.code_mirror.setValue(text);
126 this.code_mirror.setValue(text);
127 this.code_mirror.refresh();
127 this.code_mirror.refresh();
128 };
128 };
129
129
130
130
131 TextCell.prototype.get_rendered = function() {
131 TextCell.prototype.get_rendered = function() {
132 return this.element.find('div.text_cell_render').html();
132 return this.element.find('div.text_cell_render').html();
133 };
133 };
134
134
135
135
136 TextCell.prototype.set_rendered = function(text) {
136 TextCell.prototype.set_rendered = function(text) {
137 this.element.find('div.text_cell_render').html(text);
137 this.element.find('div.text_cell_render').html(text);
138 };
138 };
139
139
140
140
141 TextCell.prototype.at_top = function () {
141 TextCell.prototype.at_top = function () {
142 if (this.rendered) {
142 if (this.rendered) {
143 return true;
143 return true;
144 } else {
144 } else {
145 return false;
145 return false;
146 }
146 }
147 };
147 };
148
148
149
149
150 TextCell.prototype.at_bottom = function () {
150 TextCell.prototype.at_bottom = function () {
151 if (this.rendered) {
151 if (this.rendered) {
152 return true;
152 return true;
153 } else {
153 } else {
154 return false;
154 return false;
155 }
155 }
156 };
156 };
157
157
158
158
159 TextCell.prototype.fromJSON = function (data) {
159 TextCell.prototype.fromJSON = function (data) {
160 IPython.Cell.prototype.fromJSON.apply(this, arguments);
160 IPython.Cell.prototype.fromJSON.apply(this, arguments);
161 if (data.cell_type === this.cell_type) {
161 if (data.cell_type === this.cell_type) {
162 if (data.source !== undefined) {
162 if (data.source !== undefined) {
163 this.set_text(data.source);
163 this.set_text(data.source);
164 // make this value the starting point, so that we can only undo
164 // make this value the starting point, so that we can only undo
165 // to this state, instead of a blank cell
165 // to this state, instead of a blank cell
166 this.code_mirror.clearHistory();
166 this.code_mirror.clearHistory();
167 this.set_rendered(data.rendered || '');
167 this.set_rendered(data.rendered || '');
168 this.rendered = false;
168 this.rendered = false;
169 this.render();
169 this.render();
170 }
170 }
171 }
171 }
172 };
172 };
173
173
174
174
175 TextCell.prototype.toJSON = function () {
175 TextCell.prototype.toJSON = function () {
176 var data = IPython.Cell.prototype.toJSON.apply(this);
176 var data = IPython.Cell.prototype.toJSON.apply(this);
177 data.cell_type = this.cell_type;
177 data.cell_type = this.cell_type;
178 data.source = this.get_text();
178 data.source = this.get_text();
179 return data;
179 return data;
180 };
180 };
181
181
182
182
183 // HTMLCell
183 // HTMLCell
184
184
185 var HTMLCell = function () {
185 var HTMLCell = function () {
186 this.placeholder = "Type <strong>HTML</strong> and LaTeX: $\\alpha^2$";
186 this.placeholder = "Type <strong>HTML</strong> and LaTeX: $\\alpha^2$";
187 IPython.TextCell.apply(this, arguments);
187 IPython.TextCell.apply(this, arguments);
188 this.cell_type = 'html';
188 this.cell_type = 'html';
189 };
189 };
190
190
191
191
192 HTMLCell.prototype = new TextCell();
192 HTMLCell.prototype = new TextCell();
193
193
194
194
195 HTMLCell.prototype.render = function () {
195 HTMLCell.prototype.render = function () {
196 if (this.rendered === false) {
196 if (this.rendered === false) {
197 var text = this.get_text();
197 var text = this.get_text();
198 if (text === "") { text = this.placeholder; }
198 if (text === "") { text = this.placeholder; }
199 this.set_rendered(text);
199 this.set_rendered(text);
200 this.typeset();
200 this.typeset();
201 this.element.find('div.text_cell_input').hide();
201 this.element.find('div.text_cell_input').hide();
202 this.element.find("div.text_cell_render").show();
202 this.element.find("div.text_cell_render").show();
203 this.rendered = true;
203 this.rendered = true;
204 }
204 }
205 };
205 };
206
206
207
207
208 // MarkdownCell
208 // MarkdownCell
209
209
210 var MarkdownCell = function () {
210 var MarkdownCell = function () {
211 this.placeholder = "Type *Markdown* and LaTeX: $\\alpha^2$";
211 this.placeholder = "Type *Markdown* and LaTeX: $\\alpha^2$";
212 IPython.TextCell.apply(this, arguments);
212 IPython.TextCell.apply(this, arguments);
213 this.cell_type = 'markdown';
213 this.cell_type = 'markdown';
214 };
214 };
215
215
216
216
217 MarkdownCell.prototype = new TextCell();
217 MarkdownCell.prototype = new TextCell();
218
218
219
219
220 MarkdownCell.prototype.render = function () {
220 MarkdownCell.prototype.render = function () {
221 if (this.rendered === false) {
221 if (this.rendered === false) {
222 var text = this.get_text();
222 var text = this.get_text();
223 if (text === "") { text = this.placeholder; }
223 if (text === "") { text = this.placeholder; }
224
224
225 text = IPython.mathjaxutils.removeMath(text)
225 text = IPython.mathjaxutils.remove_math(text)
226 var html = IPython.markdown_converter.makeHtml(text);
226 var html = IPython.markdown_converter.makeHtml(text);
227 html = IPython.mathjaxutils.replaceMath(html)
227 html = IPython.mathjaxutils.replace_math(html)
228
228
229 try {
229 try {
230 this.set_rendered(html);
230 this.set_rendered(html);
231 } catch (e) {
231 } catch (e) {
232 console.log("Error running Javascript in Markdown:");
232 console.log("Error running Javascript in Markdown:");
233 console.log(e);
233 console.log(e);
234 this.set_rendered($("<div/>").addClass("js-error").html(
234 this.set_rendered($("<div/>").addClass("js-error").html(
235 "Error rendering Markdown!<br/>" + e.toString())
235 "Error rendering Markdown!<br/>" + e.toString())
236 );
236 );
237 }
237 }
238 this.typeset()
238 this.typeset()
239 this.element.find('div.text_cell_input').hide();
239 this.element.find('div.text_cell_input').hide();
240 this.element.find("div.text_cell_render").show();
240 this.element.find("div.text_cell_render").show();
241 var code_snippets = this.element.find("pre > code");
241 var code_snippets = this.element.find("pre > code");
242 code_snippets.replaceWith(function () {
242 code_snippets.replaceWith(function () {
243 var code = $(this).html();
243 var code = $(this).html();
244 /* Substitute br for newlines and &nbsp; for spaces
244 /* Substitute br for newlines and &nbsp; for spaces
245 before highlighting, since prettify doesn't
245 before highlighting, since prettify doesn't
246 preserve those on all browsers */
246 preserve those on all browsers */
247 code = code.replace(/(\r\n|\n|\r)/gm, "<br/>");
247 code = code.replace(/(\r\n|\n|\r)/gm, "<br/>");
248 code = code.replace(/ /gm, '&nbsp;');
248 code = code.replace(/ /gm, '&nbsp;');
249 code = prettyPrintOne(code);
249 code = prettyPrintOne(code);
250
250
251 return '<code class="prettyprint">' + code + '</code>';
251 return '<code class="prettyprint">' + code + '</code>';
252 });
252 });
253
253
254 IPython.mathjaxutils.queueRender()
254 IPython.mathjaxutils.queue_render()
255 this.rendered = true;
255 this.rendered = true;
256 }
256 }
257 };
257 };
258
258
259
259
260 // RawCell
260 // RawCell
261
261
262 var RawCell = function () {
262 var RawCell = function () {
263 this.placeholder = "Type plain text and LaTeX: $\\alpha^2$";
263 this.placeholder = "Type plain text and LaTeX: $\\alpha^2$";
264 this.code_mirror_mode = 'rst';
264 this.code_mirror_mode = 'rst';
265 IPython.TextCell.apply(this, arguments);
265 IPython.TextCell.apply(this, arguments);
266 this.cell_type = 'raw';
266 this.cell_type = 'raw';
267 var that = this
267 var that = this
268
268
269 this.element.focusout(
269 this.element.focusout(
270 function() { that.auto_highlight(); }
270 function() { that.auto_highlight(); }
271 );
271 );
272 };
272 };
273
273
274
274
275 RawCell.prototype = new TextCell();
275 RawCell.prototype = new TextCell();
276
276
277 RawCell.prototype.auto_highlight = function () {
277 RawCell.prototype.auto_highlight = function () {
278 this._auto_highlight(IPython.config.raw_cell_highlight);
278 this._auto_highlight(IPython.config.raw_cell_highlight);
279 };
279 };
280
280
281 RawCell.prototype.render = function () {
281 RawCell.prototype.render = function () {
282 this.rendered = true;
282 this.rendered = true;
283 this.edit();
283 this.edit();
284 };
284 };
285
285
286
286
287 RawCell.prototype.handle_codemirror_keyevent = function (editor, event) {
287 RawCell.prototype.handle_codemirror_keyevent = function (editor, event) {
288 // This method gets called in CodeMirror's onKeyDown/onKeyPress
288 // This method gets called in CodeMirror's onKeyDown/onKeyPress
289 // handlers and is used to provide custom key handling. Its return
289 // handlers and is used to provide custom key handling. Its return
290 // value is used to determine if CodeMirror should ignore the event:
290 // value is used to determine if CodeMirror should ignore the event:
291 // true = ignore, false = don't ignore.
291 // true = ignore, false = don't ignore.
292
292
293 var that = this;
293 var that = this;
294 if (event.which === key.UPARROW && event.type === 'keydown') {
294 if (event.which === key.UPARROW && event.type === 'keydown') {
295 // If we are not at the top, let CM handle the up arrow and
295 // If we are not at the top, let CM handle the up arrow and
296 // prevent the global keydown handler from handling it.
296 // prevent the global keydown handler from handling it.
297 if (!that.at_top()) {
297 if (!that.at_top()) {
298 event.stop();
298 event.stop();
299 return false;
299 return false;
300 } else {
300 } else {
301 return true;
301 return true;
302 };
302 };
303 } else if (event.which === key.DOWNARROW && event.type === 'keydown') {
303 } else if (event.which === key.DOWNARROW && event.type === 'keydown') {
304 // If we are not at the bottom, let CM handle the down arrow and
304 // If we are not at the bottom, let CM handle the down arrow and
305 // prevent the global keydown handler from handling it.
305 // prevent the global keydown handler from handling it.
306 if (!that.at_bottom()) {
306 if (!that.at_bottom()) {
307 event.stop();
307 event.stop();
308 return false;
308 return false;
309 } else {
309 } else {
310 return true;
310 return true;
311 };
311 };
312 };
312 };
313 return false;
313 return false;
314 };
314 };
315
315
316
316
317 RawCell.prototype.select = function () {
317 RawCell.prototype.select = function () {
318 IPython.Cell.prototype.select.apply(this);
318 IPython.Cell.prototype.select.apply(this);
319 this.code_mirror.refresh();
319 this.code_mirror.refresh();
320 this.code_mirror.focus();
320 this.code_mirror.focus();
321 };
321 };
322
322
323
323
324 RawCell.prototype.at_top = function () {
324 RawCell.prototype.at_top = function () {
325 var cursor = this.code_mirror.getCursor();
325 var cursor = this.code_mirror.getCursor();
326 if (cursor.line === 0 && cursor.ch === 0) {
326 if (cursor.line === 0 && cursor.ch === 0) {
327 return true;
327 return true;
328 } else {
328 } else {
329 return false;
329 return false;
330 }
330 }
331 };
331 };
332
332
333
333
334 RawCell.prototype.at_bottom = function () {
334 RawCell.prototype.at_bottom = function () {
335 var cursor = this.code_mirror.getCursor();
335 var cursor = this.code_mirror.getCursor();
336 if (cursor.line === (this.code_mirror.lineCount()-1) && cursor.ch === this.code_mirror.getLine(cursor.line).length) {
336 if (cursor.line === (this.code_mirror.lineCount()-1) && cursor.ch === this.code_mirror.getLine(cursor.line).length) {
337 return true;
337 return true;
338 } else {
338 } else {
339 return false;
339 return false;
340 }
340 }
341 };
341 };
342
342
343
343
344 // HTMLCell
344 // HTMLCell
345
345
346 var HeadingCell = function () {
346 var HeadingCell = function () {
347 this.placeholder = "Type Heading Here";
347 this.placeholder = "Type Heading Here";
348 IPython.TextCell.apply(this, arguments);
348 IPython.TextCell.apply(this, arguments);
349 this.cell_type = 'heading';
349 this.cell_type = 'heading';
350 this.level = 1;
350 this.level = 1;
351 };
351 };
352
352
353
353
354 HeadingCell.prototype = new TextCell();
354 HeadingCell.prototype = new TextCell();
355
355
356
356
357 HeadingCell.prototype.fromJSON = function (data) {
357 HeadingCell.prototype.fromJSON = function (data) {
358 if (data.level != undefined){
358 if (data.level != undefined){
359 this.level = data.level;
359 this.level = data.level;
360 }
360 }
361 IPython.TextCell.prototype.fromJSON.apply(this, arguments);
361 IPython.TextCell.prototype.fromJSON.apply(this, arguments);
362 };
362 };
363
363
364
364
365 HeadingCell.prototype.toJSON = function () {
365 HeadingCell.prototype.toJSON = function () {
366 var data = IPython.TextCell.prototype.toJSON.apply(this);
366 var data = IPython.TextCell.prototype.toJSON.apply(this);
367 data.level = this.get_level();
367 data.level = this.get_level();
368 return data;
368 return data;
369 };
369 };
370
370
371
371
372 HeadingCell.prototype.set_level = function (level) {
372 HeadingCell.prototype.set_level = function (level) {
373 this.level = level;
373 this.level = level;
374 if (this.rendered) {
374 if (this.rendered) {
375 this.rendered = false;
375 this.rendered = false;
376 this.render();
376 this.render();
377 };
377 };
378 };
378 };
379
379
380
380
381 HeadingCell.prototype.get_level = function () {
381 HeadingCell.prototype.get_level = function () {
382 return this.level;
382 return this.level;
383 };
383 };
384
384
385
385
386 HeadingCell.prototype.set_rendered = function (text) {
386 HeadingCell.prototype.set_rendered = function (text) {
387 var r = this.element.find("div.text_cell_render");
387 var r = this.element.find("div.text_cell_render");
388 r.empty();
388 r.empty();
389 r.append($('<h'+this.level+'/>').html(text));
389 r.append($('<h'+this.level+'/>').html(text));
390 };
390 };
391
391
392
392
393 HeadingCell.prototype.get_rendered = function () {
393 HeadingCell.prototype.get_rendered = function () {
394 var r = this.element.find("div.text_cell_render");
394 var r = this.element.find("div.text_cell_render");
395 return r.children().first().html();
395 return r.children().first().html();
396 };
396 };
397
397
398
398
399 HeadingCell.prototype.render = function () {
399 HeadingCell.prototype.render = function () {
400 if (this.rendered === false) {
400 if (this.rendered === false) {
401 var text = this.get_text();
401 var text = this.get_text();
402 if (text === "") { text = this.placeholder; }
402 if (text === "") { text = this.placeholder; }
403 this.set_rendered(text);
403 this.set_rendered(text);
404 this.typeset();
404 this.typeset();
405 this.element.find('div.text_cell_input').hide();
405 this.element.find('div.text_cell_input').hide();
406 this.element.find("div.text_cell_render").show();
406 this.element.find("div.text_cell_render").show();
407 this.rendered = true;
407 this.rendered = true;
408 };
408 };
409 };
409 };
410
410
411 IPython.TextCell = TextCell;
411 IPython.TextCell = TextCell;
412 IPython.HTMLCell = HTMLCell;
412 IPython.HTMLCell = HTMLCell;
413 IPython.MarkdownCell = MarkdownCell;
413 IPython.MarkdownCell = MarkdownCell;
414 IPython.RawCell = RawCell;
414 IPython.RawCell = RawCell;
415 IPython.HeadingCell = HeadingCell;
415 IPython.HeadingCell = HeadingCell;
416
416
417
417
418 return IPython;
418 return IPython;
419
419
420 }(IPython));
420 }(IPython));
421
421
General Comments 0
You need to be logged in to leave comments. Login now