##// END OF EJS Templates
Adding security.js with 1st attempt at is_safe.
Brian E. Granger -
Show More
@@ -0,0 +1,52 b''
1 //----------------------------------------------------------------------------
2 // Copyright (C) 2014 The IPython Development Team
3 //
4 // Distributed under the terms of the BSD License. The full license is in
5 // the file COPYING, distributed as part of this software.
6 //----------------------------------------------------------------------------
7
8 //============================================================================
9 // Utilities
10 //============================================================================
11 IPython.namespace('IPython.security');
12
13 IPython.security = (function (IPython) {
14 "use strict";
15
16 var utils = IPython.utils;
17
18 var is_safe = function (html) {
19 // Is the html string safe against JavaScript based attacks. This
20 // detects 1) black listed tags, 2) blacklisted attributes, 3) all
21 // event attributes (onhover, onclick, etc.).
22 var black_tags = ['script', 'style'];
23 var black_attrs = ['style'];
24 var wrapped_html = '<div>'+html+'</div>';
25 var e = $(wrapped_html);
26 var safe = true;
27 // Detect black listed tags
28 $.map(black_tags, function (tag, index) {
29 if (e.find(tag).length > 0) {
30 safe = false;
31 }
32 });
33 // Detect black listed attributes
34 $.map(black_attrs, function (attr, index) {
35 if (e.find('['+attr+']').length > 0) {
36 safe = false;
37 }
38 });
39 e.find('*').each(function (index) {
40 $.map(utils.get_attr_names($(this)), function (attr, index) {
41 if (attr.match('^on')) {safe = false;}
42 });
43 })
44 return safe;
45 }
46
47 return {
48 is_safe: is_safe
49 };
50
51 }(IPython));
52
@@ -1,514 +1,524 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 // Utilities
9 // Utilities
10 //============================================================================
10 //============================================================================
11 IPython.namespace('IPython.utils');
11 IPython.namespace('IPython.utils');
12
12
13 IPython.utils = (function (IPython) {
13 IPython.utils = (function (IPython) {
14 "use strict";
14 "use strict";
15
15
16 IPython.load_extensions = function () {
16 IPython.load_extensions = function () {
17 // load one or more IPython notebook extensions with requirejs
17 // load one or more IPython notebook extensions with requirejs
18
18
19 var extensions = [];
19 var extensions = [];
20 var extension_names = arguments;
20 var extension_names = arguments;
21 for (var i = 0; i < extension_names.length; i++) {
21 for (var i = 0; i < extension_names.length; i++) {
22 extensions.push("nbextensions/" + arguments[i]);
22 extensions.push("nbextensions/" + arguments[i]);
23 }
23 }
24
24
25 require(extensions,
25 require(extensions,
26 function () {
26 function () {
27 for (var i = 0; i < arguments.length; i++) {
27 for (var i = 0; i < arguments.length; i++) {
28 var ext = arguments[i];
28 var ext = arguments[i];
29 var ext_name = extension_names[i];
29 var ext_name = extension_names[i];
30 // success callback
30 // success callback
31 console.log("Loaded extension: " + ext_name);
31 console.log("Loaded extension: " + ext_name);
32 if (ext && ext.load_ipython_extension !== undefined) {
32 if (ext && ext.load_ipython_extension !== undefined) {
33 ext.load_ipython_extension();
33 ext.load_ipython_extension();
34 }
34 }
35 }
35 }
36 },
36 },
37 function (err) {
37 function (err) {
38 // failure callback
38 // failure callback
39 console.log("Failed to load extension(s):", err.requireModules, err);
39 console.log("Failed to load extension(s):", err.requireModules, err);
40 }
40 }
41 );
41 );
42 };
42 };
43
43
44 //============================================================================
44 //============================================================================
45 // Cross-browser RegEx Split
45 // Cross-browser RegEx Split
46 //============================================================================
46 //============================================================================
47
47
48 // This code has been MODIFIED from the code licensed below to not replace the
48 // This code has been MODIFIED from the code licensed below to not replace the
49 // default browser split. The license is reproduced here.
49 // default browser split. The license is reproduced here.
50
50
51 // see http://blog.stevenlevithan.com/archives/cross-browser-split for more info:
51 // see http://blog.stevenlevithan.com/archives/cross-browser-split for more info:
52 /*!
52 /*!
53 * Cross-Browser Split 1.1.1
53 * Cross-Browser Split 1.1.1
54 * Copyright 2007-2012 Steven Levithan <stevenlevithan.com>
54 * Copyright 2007-2012 Steven Levithan <stevenlevithan.com>
55 * Available under the MIT License
55 * Available under the MIT License
56 * ECMAScript compliant, uniform cross-browser split method
56 * ECMAScript compliant, uniform cross-browser split method
57 */
57 */
58
58
59 /**
59 /**
60 * Splits a string into an array of strings using a regex or string
60 * Splits a string into an array of strings using a regex or string
61 * separator. Matches of the separator are not included in the result array.
61 * separator. Matches of the separator are not included in the result array.
62 * However, if `separator` is a regex that contains capturing groups,
62 * However, if `separator` is a regex that contains capturing groups,
63 * backreferences are spliced into the result each time `separator` is
63 * backreferences are spliced into the result each time `separator` is
64 * matched. Fixes browser bugs compared to the native
64 * matched. Fixes browser bugs compared to the native
65 * `String.prototype.split` and can be used reliably cross-browser.
65 * `String.prototype.split` and can be used reliably cross-browser.
66 * @param {String} str String to split.
66 * @param {String} str String to split.
67 * @param {RegExp|String} separator Regex or string to use for separating
67 * @param {RegExp|String} separator Regex or string to use for separating
68 * the string.
68 * the string.
69 * @param {Number} [limit] Maximum number of items to include in the result
69 * @param {Number} [limit] Maximum number of items to include in the result
70 * array.
70 * array.
71 * @returns {Array} Array of substrings.
71 * @returns {Array} Array of substrings.
72 * @example
72 * @example
73 *
73 *
74 * // Basic use
74 * // Basic use
75 * regex_split('a b c d', ' ');
75 * regex_split('a b c d', ' ');
76 * // -> ['a', 'b', 'c', 'd']
76 * // -> ['a', 'b', 'c', 'd']
77 *
77 *
78 * // With limit
78 * // With limit
79 * regex_split('a b c d', ' ', 2);
79 * regex_split('a b c d', ' ', 2);
80 * // -> ['a', 'b']
80 * // -> ['a', 'b']
81 *
81 *
82 * // Backreferences in result array
82 * // Backreferences in result array
83 * regex_split('..word1 word2..', /([a-z]+)(\d+)/i);
83 * regex_split('..word1 word2..', /([a-z]+)(\d+)/i);
84 * // -> ['..', 'word', '1', ' ', 'word', '2', '..']
84 * // -> ['..', 'word', '1', ' ', 'word', '2', '..']
85 */
85 */
86 var regex_split = function (str, separator, limit) {
86 var regex_split = function (str, separator, limit) {
87 // If `separator` is not a regex, use `split`
87 // If `separator` is not a regex, use `split`
88 if (Object.prototype.toString.call(separator) !== "[object RegExp]") {
88 if (Object.prototype.toString.call(separator) !== "[object RegExp]") {
89 return split.call(str, separator, limit);
89 return split.call(str, separator, limit);
90 }
90 }
91 var output = [],
91 var output = [],
92 flags = (separator.ignoreCase ? "i" : "") +
92 flags = (separator.ignoreCase ? "i" : "") +
93 (separator.multiline ? "m" : "") +
93 (separator.multiline ? "m" : "") +
94 (separator.extended ? "x" : "") + // Proposed for ES6
94 (separator.extended ? "x" : "") + // Proposed for ES6
95 (separator.sticky ? "y" : ""), // Firefox 3+
95 (separator.sticky ? "y" : ""), // Firefox 3+
96 lastLastIndex = 0,
96 lastLastIndex = 0,
97 // Make `global` and avoid `lastIndex` issues by working with a copy
97 // Make `global` and avoid `lastIndex` issues by working with a copy
98 separator = new RegExp(separator.source, flags + "g"),
98 separator = new RegExp(separator.source, flags + "g"),
99 separator2, match, lastIndex, lastLength;
99 separator2, match, lastIndex, lastLength;
100 str += ""; // Type-convert
100 str += ""; // Type-convert
101
101
102 var compliantExecNpcg = typeof(/()??/.exec("")[1]) === "undefined";
102 var compliantExecNpcg = typeof(/()??/.exec("")[1]) === "undefined";
103 if (!compliantExecNpcg) {
103 if (!compliantExecNpcg) {
104 // Doesn't need flags gy, but they don't hurt
104 // Doesn't need flags gy, but they don't hurt
105 separator2 = new RegExp("^" + separator.source + "$(?!\\s)", flags);
105 separator2 = new RegExp("^" + separator.source + "$(?!\\s)", flags);
106 }
106 }
107 /* Values for `limit`, per the spec:
107 /* Values for `limit`, per the spec:
108 * If undefined: 4294967295 // Math.pow(2, 32) - 1
108 * If undefined: 4294967295 // Math.pow(2, 32) - 1
109 * If 0, Infinity, or NaN: 0
109 * If 0, Infinity, or NaN: 0
110 * If positive number: limit = Math.floor(limit); if (limit > 4294967295) limit -= 4294967296;
110 * If positive number: limit = Math.floor(limit); if (limit > 4294967295) limit -= 4294967296;
111 * If negative number: 4294967296 - Math.floor(Math.abs(limit))
111 * If negative number: 4294967296 - Math.floor(Math.abs(limit))
112 * If other: Type-convert, then use the above rules
112 * If other: Type-convert, then use the above rules
113 */
113 */
114 limit = typeof(limit) === "undefined" ?
114 limit = typeof(limit) === "undefined" ?
115 -1 >>> 0 : // Math.pow(2, 32) - 1
115 -1 >>> 0 : // Math.pow(2, 32) - 1
116 limit >>> 0; // ToUint32(limit)
116 limit >>> 0; // ToUint32(limit)
117 while (match = separator.exec(str)) {
117 while (match = separator.exec(str)) {
118 // `separator.lastIndex` is not reliable cross-browser
118 // `separator.lastIndex` is not reliable cross-browser
119 lastIndex = match.index + match[0].length;
119 lastIndex = match.index + match[0].length;
120 if (lastIndex > lastLastIndex) {
120 if (lastIndex > lastLastIndex) {
121 output.push(str.slice(lastLastIndex, match.index));
121 output.push(str.slice(lastLastIndex, match.index));
122 // Fix browsers whose `exec` methods don't consistently return `undefined` for
122 // Fix browsers whose `exec` methods don't consistently return `undefined` for
123 // nonparticipating capturing groups
123 // nonparticipating capturing groups
124 if (!compliantExecNpcg && match.length > 1) {
124 if (!compliantExecNpcg && match.length > 1) {
125 match[0].replace(separator2, function () {
125 match[0].replace(separator2, function () {
126 for (var i = 1; i < arguments.length - 2; i++) {
126 for (var i = 1; i < arguments.length - 2; i++) {
127 if (typeof(arguments[i]) === "undefined") {
127 if (typeof(arguments[i]) === "undefined") {
128 match[i] = undefined;
128 match[i] = undefined;
129 }
129 }
130 }
130 }
131 });
131 });
132 }
132 }
133 if (match.length > 1 && match.index < str.length) {
133 if (match.length > 1 && match.index < str.length) {
134 Array.prototype.push.apply(output, match.slice(1));
134 Array.prototype.push.apply(output, match.slice(1));
135 }
135 }
136 lastLength = match[0].length;
136 lastLength = match[0].length;
137 lastLastIndex = lastIndex;
137 lastLastIndex = lastIndex;
138 if (output.length >= limit) {
138 if (output.length >= limit) {
139 break;
139 break;
140 }
140 }
141 }
141 }
142 if (separator.lastIndex === match.index) {
142 if (separator.lastIndex === match.index) {
143 separator.lastIndex++; // Avoid an infinite loop
143 separator.lastIndex++; // Avoid an infinite loop
144 }
144 }
145 }
145 }
146 if (lastLastIndex === str.length) {
146 if (lastLastIndex === str.length) {
147 if (lastLength || !separator.test("")) {
147 if (lastLength || !separator.test("")) {
148 output.push("");
148 output.push("");
149 }
149 }
150 } else {
150 } else {
151 output.push(str.slice(lastLastIndex));
151 output.push(str.slice(lastLastIndex));
152 }
152 }
153 return output.length > limit ? output.slice(0, limit) : output;
153 return output.length > limit ? output.slice(0, limit) : output;
154 };
154 };
155
155
156 //============================================================================
156 //============================================================================
157 // End contributed Cross-browser RegEx Split
157 // End contributed Cross-browser RegEx Split
158 //============================================================================
158 //============================================================================
159
159
160
160
161 var uuid = function () {
161 var uuid = function () {
162 // http://www.ietf.org/rfc/rfc4122.txt
162 // http://www.ietf.org/rfc/rfc4122.txt
163 var s = [];
163 var s = [];
164 var hexDigits = "0123456789ABCDEF";
164 var hexDigits = "0123456789ABCDEF";
165 for (var i = 0; i < 32; i++) {
165 for (var i = 0; i < 32; i++) {
166 s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
166 s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
167 }
167 }
168 s[12] = "4"; // bits 12-15 of the time_hi_and_version field to 0010
168 s[12] = "4"; // bits 12-15 of the time_hi_and_version field to 0010
169 s[16] = hexDigits.substr((s[16] & 0x3) | 0x8, 1); // bits 6-7 of the clock_seq_hi_and_reserved to 01
169 s[16] = hexDigits.substr((s[16] & 0x3) | 0x8, 1); // bits 6-7 of the clock_seq_hi_and_reserved to 01
170
170
171 var uuid = s.join("");
171 var uuid = s.join("");
172 return uuid;
172 return uuid;
173 };
173 };
174
174
175
175
176 //Fix raw text to parse correctly in crazy XML
176 //Fix raw text to parse correctly in crazy XML
177 function xmlencode(string) {
177 function xmlencode(string) {
178 return string.replace(/\&/g,'&'+'amp;')
178 return string.replace(/\&/g,'&'+'amp;')
179 .replace(/</g,'&'+'lt;')
179 .replace(/</g,'&'+'lt;')
180 .replace(/>/g,'&'+'gt;')
180 .replace(/>/g,'&'+'gt;')
181 .replace(/\'/g,'&'+'apos;')
181 .replace(/\'/g,'&'+'apos;')
182 .replace(/\"/g,'&'+'quot;')
182 .replace(/\"/g,'&'+'quot;')
183 .replace(/`/g,'&'+'#96;');
183 .replace(/`/g,'&'+'#96;');
184 }
184 }
185
185
186
186
187 //Map from terminal commands to CSS classes
187 //Map from terminal commands to CSS classes
188 var ansi_colormap = {
188 var ansi_colormap = {
189 "01":"ansibold",
189 "01":"ansibold",
190
190
191 "30":"ansiblack",
191 "30":"ansiblack",
192 "31":"ansired",
192 "31":"ansired",
193 "32":"ansigreen",
193 "32":"ansigreen",
194 "33":"ansiyellow",
194 "33":"ansiyellow",
195 "34":"ansiblue",
195 "34":"ansiblue",
196 "35":"ansipurple",
196 "35":"ansipurple",
197 "36":"ansicyan",
197 "36":"ansicyan",
198 "37":"ansigray",
198 "37":"ansigray",
199
199
200 "40":"ansibgblack",
200 "40":"ansibgblack",
201 "41":"ansibgred",
201 "41":"ansibgred",
202 "42":"ansibggreen",
202 "42":"ansibggreen",
203 "43":"ansibgyellow",
203 "43":"ansibgyellow",
204 "44":"ansibgblue",
204 "44":"ansibgblue",
205 "45":"ansibgpurple",
205 "45":"ansibgpurple",
206 "46":"ansibgcyan",
206 "46":"ansibgcyan",
207 "47":"ansibggray"
207 "47":"ansibggray"
208 };
208 };
209
209
210 function _process_numbers(attrs, numbers) {
210 function _process_numbers(attrs, numbers) {
211 // process ansi escapes
211 // process ansi escapes
212 var n = numbers.shift();
212 var n = numbers.shift();
213 if (ansi_colormap[n]) {
213 if (ansi_colormap[n]) {
214 if ( ! attrs["class"] ) {
214 if ( ! attrs["class"] ) {
215 attrs["class"] = ansi_colormap[n];
215 attrs["class"] = ansi_colormap[n];
216 } else {
216 } else {
217 attrs["class"] += " " + ansi_colormap[n];
217 attrs["class"] += " " + ansi_colormap[n];
218 }
218 }
219 } else if (n == "38" || n == "48") {
219 } else if (n == "38" || n == "48") {
220 // VT100 256 color or 24 bit RGB
220 // VT100 256 color or 24 bit RGB
221 if (numbers.length < 2) {
221 if (numbers.length < 2) {
222 console.log("Not enough fields for VT100 color", numbers);
222 console.log("Not enough fields for VT100 color", numbers);
223 return;
223 return;
224 }
224 }
225
225
226 var index_or_rgb = numbers.shift();
226 var index_or_rgb = numbers.shift();
227 var r,g,b;
227 var r,g,b;
228 if (index_or_rgb == "5") {
228 if (index_or_rgb == "5") {
229 // 256 color
229 // 256 color
230 var idx = parseInt(numbers.shift());
230 var idx = parseInt(numbers.shift());
231 if (idx < 16) {
231 if (idx < 16) {
232 // indexed ANSI
232 // indexed ANSI
233 // ignore bright / non-bright distinction
233 // ignore bright / non-bright distinction
234 idx = idx % 8;
234 idx = idx % 8;
235 var ansiclass = ansi_colormap[n[0] + (idx % 8).toString()];
235 var ansiclass = ansi_colormap[n[0] + (idx % 8).toString()];
236 if ( ! attrs["class"] ) {
236 if ( ! attrs["class"] ) {
237 attrs["class"] = ansiclass;
237 attrs["class"] = ansiclass;
238 } else {
238 } else {
239 attrs["class"] += " " + ansiclass;
239 attrs["class"] += " " + ansiclass;
240 }
240 }
241 return;
241 return;
242 } else if (idx < 232) {
242 } else if (idx < 232) {
243 // 216 color 6x6x6 RGB
243 // 216 color 6x6x6 RGB
244 idx = idx - 16;
244 idx = idx - 16;
245 b = idx % 6;
245 b = idx % 6;
246 g = Math.floor(idx / 6) % 6;
246 g = Math.floor(idx / 6) % 6;
247 r = Math.floor(idx / 36) % 6;
247 r = Math.floor(idx / 36) % 6;
248 // convert to rgb
248 // convert to rgb
249 r = (r * 51);
249 r = (r * 51);
250 g = (g * 51);
250 g = (g * 51);
251 b = (b * 51);
251 b = (b * 51);
252 } else {
252 } else {
253 // grayscale
253 // grayscale
254 idx = idx - 231;
254 idx = idx - 231;
255 // it's 1-24 and should *not* include black or white,
255 // it's 1-24 and should *not* include black or white,
256 // so a 26 point scale
256 // so a 26 point scale
257 r = g = b = Math.floor(idx * 256 / 26);
257 r = g = b = Math.floor(idx * 256 / 26);
258 }
258 }
259 } else if (index_or_rgb == "2") {
259 } else if (index_or_rgb == "2") {
260 // Simple 24 bit RGB
260 // Simple 24 bit RGB
261 if (numbers.length > 3) {
261 if (numbers.length > 3) {
262 console.log("Not enough fields for RGB", numbers);
262 console.log("Not enough fields for RGB", numbers);
263 return;
263 return;
264 }
264 }
265 r = numbers.shift();
265 r = numbers.shift();
266 g = numbers.shift();
266 g = numbers.shift();
267 b = numbers.shift();
267 b = numbers.shift();
268 } else {
268 } else {
269 console.log("unrecognized control", numbers);
269 console.log("unrecognized control", numbers);
270 return;
270 return;
271 }
271 }
272 if (r !== undefined) {
272 if (r !== undefined) {
273 // apply the rgb color
273 // apply the rgb color
274 var line;
274 var line;
275 if (n == "38") {
275 if (n == "38") {
276 line = "color: ";
276 line = "color: ";
277 } else {
277 } else {
278 line = "background-color: ";
278 line = "background-color: ";
279 }
279 }
280 line = line + "rgb(" + r + "," + g + "," + b + ");"
280 line = line + "rgb(" + r + "," + g + "," + b + ");"
281 if ( !attrs["style"] ) {
281 if ( !attrs["style"] ) {
282 attrs["style"] = line;
282 attrs["style"] = line;
283 } else {
283 } else {
284 attrs["style"] += " " + line;
284 attrs["style"] += " " + line;
285 }
285 }
286 }
286 }
287 }
287 }
288 }
288 }
289
289
290 function ansispan(str) {
290 function ansispan(str) {
291 // ansispan function adapted from github.com/mmalecki/ansispan (MIT License)
291 // ansispan function adapted from github.com/mmalecki/ansispan (MIT License)
292 // regular ansi escapes (using the table above)
292 // regular ansi escapes (using the table above)
293 return str.replace(/\033\[(0?[01]|22|39)?([;\d]+)?m/g, function(match, prefix, pattern) {
293 return str.replace(/\033\[(0?[01]|22|39)?([;\d]+)?m/g, function(match, prefix, pattern) {
294 if (!pattern) {
294 if (!pattern) {
295 // [(01|22|39|)m close spans
295 // [(01|22|39|)m close spans
296 return "</span>";
296 return "</span>";
297 }
297 }
298 // consume sequence of color escapes
298 // consume sequence of color escapes
299 var numbers = pattern.match(/\d+/g);
299 var numbers = pattern.match(/\d+/g);
300 var attrs = {};
300 var attrs = {};
301 while (numbers.length > 0) {
301 while (numbers.length > 0) {
302 _process_numbers(attrs, numbers);
302 _process_numbers(attrs, numbers);
303 }
303 }
304
304
305 var span = "<span ";
305 var span = "<span ";
306 for (var attr in attrs) {
306 for (var attr in attrs) {
307 var value = attrs[attr];
307 var value = attrs[attr];
308 span = span + " " + attr + '="' + attrs[attr] + '"';
308 span = span + " " + attr + '="' + attrs[attr] + '"';
309 }
309 }
310 return span + ">";
310 return span + ">";
311 });
311 });
312 };
312 };
313
313
314 // Transform ANSI color escape codes into HTML <span> tags with css
314 // Transform ANSI color escape codes into HTML <span> tags with css
315 // classes listed in the above ansi_colormap object. The actual color used
315 // classes listed in the above ansi_colormap object. The actual color used
316 // are set in the css file.
316 // are set in the css file.
317 function fixConsole(txt) {
317 function fixConsole(txt) {
318 txt = xmlencode(txt);
318 txt = xmlencode(txt);
319 var re = /\033\[([\dA-Fa-f;]*?)m/;
319 var re = /\033\[([\dA-Fa-f;]*?)m/;
320 var opened = false;
320 var opened = false;
321 var cmds = [];
321 var cmds = [];
322 var opener = "";
322 var opener = "";
323 var closer = "";
323 var closer = "";
324
324
325 // Strip all ANSI codes that are not color related. Matches
325 // Strip all ANSI codes that are not color related. Matches
326 // all ANSI codes that do not end with "m".
326 // all ANSI codes that do not end with "m".
327 var ignored_re = /(?=(\033\[[\d;=]*[a-ln-zA-Z]{1}))\1(?!m)/g;
327 var ignored_re = /(?=(\033\[[\d;=]*[a-ln-zA-Z]{1}))\1(?!m)/g;
328 txt = txt.replace(ignored_re, "");
328 txt = txt.replace(ignored_re, "");
329
329
330 // color ansi codes
330 // color ansi codes
331 txt = ansispan(txt);
331 txt = ansispan(txt);
332 return txt;
332 return txt;
333 }
333 }
334
334
335 // Remove chunks that should be overridden by the effect of
335 // Remove chunks that should be overridden by the effect of
336 // carriage return characters
336 // carriage return characters
337 function fixCarriageReturn(txt) {
337 function fixCarriageReturn(txt) {
338 var tmp = txt;
338 var tmp = txt;
339 do {
339 do {
340 txt = tmp;
340 txt = tmp;
341 tmp = txt.replace(/\r+\n/gm, '\n'); // \r followed by \n --> newline
341 tmp = txt.replace(/\r+\n/gm, '\n'); // \r followed by \n --> newline
342 tmp = tmp.replace(/^.*\r+/gm, ''); // Other \r --> clear line
342 tmp = tmp.replace(/^.*\r+/gm, ''); // Other \r --> clear line
343 } while (tmp.length < txt.length);
343 } while (tmp.length < txt.length);
344 return txt;
344 return txt;
345 }
345 }
346
346
347 // Locate any URLs and convert them to a anchor tag
347 // Locate any URLs and convert them to a anchor tag
348 function autoLinkUrls(txt) {
348 function autoLinkUrls(txt) {
349 return txt.replace(/(^|\s)(https?|ftp)(:[^'">\s]+)/gi,
349 return txt.replace(/(^|\s)(https?|ftp)(:[^'">\s]+)/gi,
350 "$1<a target=\"_blank\" href=\"$2$3\">$2$3</a>");
350 "$1<a target=\"_blank\" href=\"$2$3\">$2$3</a>");
351 }
351 }
352
352
353 var points_to_pixels = function (points) {
353 var points_to_pixels = function (points) {
354 // A reasonably good way of converting between points and pixels.
354 // A reasonably good way of converting between points and pixels.
355 var test = $('<div style="display: none; width: 10000pt; padding:0; border:0;"></div>');
355 var test = $('<div style="display: none; width: 10000pt; padding:0; border:0;"></div>');
356 $(body).append(test);
356 $(body).append(test);
357 var pixel_per_point = test.width()/10000;
357 var pixel_per_point = test.width()/10000;
358 test.remove();
358 test.remove();
359 return Math.floor(points*pixel_per_point);
359 return Math.floor(points*pixel_per_point);
360 };
360 };
361
361
362 var always_new = function (constructor) {
362 var always_new = function (constructor) {
363 // wrapper around contructor to avoid requiring `var a = new constructor()`
363 // wrapper around contructor to avoid requiring `var a = new constructor()`
364 // useful for passing constructors as callbacks,
364 // useful for passing constructors as callbacks,
365 // not for programmer laziness.
365 // not for programmer laziness.
366 // from http://programmers.stackexchange.com/questions/118798
366 // from http://programmers.stackexchange.com/questions/118798
367 return function () {
367 return function () {
368 var obj = Object.create(constructor.prototype);
368 var obj = Object.create(constructor.prototype);
369 constructor.apply(obj, arguments);
369 constructor.apply(obj, arguments);
370 return obj;
370 return obj;
371 };
371 };
372 };
372 };
373
373
374 var url_path_join = function () {
374 var url_path_join = function () {
375 // join a sequence of url components with '/'
375 // join a sequence of url components with '/'
376 var url = '';
376 var url = '';
377 for (var i = 0; i < arguments.length; i++) {
377 for (var i = 0; i < arguments.length; i++) {
378 if (arguments[i] === '') {
378 if (arguments[i] === '') {
379 continue;
379 continue;
380 }
380 }
381 if (url.length > 0 && url[url.length-1] != '/') {
381 if (url.length > 0 && url[url.length-1] != '/') {
382 url = url + '/' + arguments[i];
382 url = url + '/' + arguments[i];
383 } else {
383 } else {
384 url = url + arguments[i];
384 url = url + arguments[i];
385 }
385 }
386 }
386 }
387 url = url.replace(/\/\/+/, '/');
387 url = url.replace(/\/\/+/, '/');
388 return url;
388 return url;
389 };
389 };
390
390
391 var parse_url = function (url) {
391 var parse_url = function (url) {
392 // an `a` element with an href allows attr-access to the parsed segments of a URL
392 // an `a` element with an href allows attr-access to the parsed segments of a URL
393 // a = parse_url("http://localhost:8888/path/name#hash")
393 // a = parse_url("http://localhost:8888/path/name#hash")
394 // a.protocol = "http:"
394 // a.protocol = "http:"
395 // a.host = "localhost:8888"
395 // a.host = "localhost:8888"
396 // a.hostname = "localhost"
396 // a.hostname = "localhost"
397 // a.port = 8888
397 // a.port = 8888
398 // a.pathname = "/path/name"
398 // a.pathname = "/path/name"
399 // a.hash = "#hash"
399 // a.hash = "#hash"
400 var a = document.createElement("a");
400 var a = document.createElement("a");
401 a.href = url;
401 a.href = url;
402 return a;
402 return a;
403 };
403 };
404
404
405 var encode_uri_components = function (uri) {
405 var encode_uri_components = function (uri) {
406 // encode just the components of a multi-segment uri,
406 // encode just the components of a multi-segment uri,
407 // leaving '/' separators
407 // leaving '/' separators
408 return uri.split('/').map(encodeURIComponent).join('/');
408 return uri.split('/').map(encodeURIComponent).join('/');
409 };
409 };
410
410
411 var url_join_encode = function () {
411 var url_join_encode = function () {
412 // join a sequence of url components with '/',
412 // join a sequence of url components with '/',
413 // encoding each component with encodeURIComponent
413 // encoding each component with encodeURIComponent
414 return encode_uri_components(url_path_join.apply(null, arguments));
414 return encode_uri_components(url_path_join.apply(null, arguments));
415 };
415 };
416
416
417
417
418 var splitext = function (filename) {
418 var splitext = function (filename) {
419 // mimic Python os.path.splitext
419 // mimic Python os.path.splitext
420 // Returns ['base', '.ext']
420 // Returns ['base', '.ext']
421 var idx = filename.lastIndexOf('.');
421 var idx = filename.lastIndexOf('.');
422 if (idx > 0) {
422 if (idx > 0) {
423 return [filename.slice(0, idx), filename.slice(idx)];
423 return [filename.slice(0, idx), filename.slice(idx)];
424 } else {
424 } else {
425 return [filename, ''];
425 return [filename, ''];
426 }
426 }
427 };
427 };
428
428
429
429
430 var escape_html = function (text) {
430 var escape_html = function (text) {
431 // escape text to HTML
431 // escape text to HTML
432 return $("<div/>").text(text).html();
432 return $("<div/>").text(text).html();
433 }
433 }
434
434
435
435
436 var get_body_data = function(key) {
436 var get_body_data = function(key) {
437 // get a url-encoded item from body.data and decode it
437 // get a url-encoded item from body.data and decode it
438 // we should never have any encoded URLs anywhere else in code
438 // we should never have any encoded URLs anywhere else in code
439 // until we are building an actual request
439 // until we are building an actual request
440 return decodeURIComponent($('body').data(key));
440 return decodeURIComponent($('body').data(key));
441 };
441 };
442
442
443
443
444 // http://stackoverflow.com/questions/2400935/browser-detection-in-javascript
444 // http://stackoverflow.com/questions/2400935/browser-detection-in-javascript
445 var browser = (function() {
445 var browser = (function() {
446 if (typeof navigator === 'undefined') {
446 if (typeof navigator === 'undefined') {
447 // navigator undefined in node
447 // navigator undefined in node
448 return 'None';
448 return 'None';
449 }
449 }
450 var N= navigator.appName, ua= navigator.userAgent, tem;
450 var N= navigator.appName, ua= navigator.userAgent, tem;
451 var M= ua.match(/(opera|chrome|safari|firefox|msie)\/?\s*(\.?\d+(\.\d+)*)/i);
451 var M= ua.match(/(opera|chrome|safari|firefox|msie)\/?\s*(\.?\d+(\.\d+)*)/i);
452 if (M && (tem= ua.match(/version\/([\.\d]+)/i))!= null) M[2]= tem[1];
452 if (M && (tem= ua.match(/version\/([\.\d]+)/i))!= null) M[2]= tem[1];
453 M= M? [M[1], M[2]]: [N, navigator.appVersion,'-?'];
453 M= M? [M[1], M[2]]: [N, navigator.appVersion,'-?'];
454 return M;
454 return M;
455 })();
455 })();
456
456
457 // http://stackoverflow.com/questions/11219582/how-to-detect-my-browser-version-and-operating-system-using-javascript
457 // http://stackoverflow.com/questions/11219582/how-to-detect-my-browser-version-and-operating-system-using-javascript
458 var platform = (function () {
458 var platform = (function () {
459 if (typeof navigator === 'undefined') {
459 if (typeof navigator === 'undefined') {
460 // navigator undefined in node
460 // navigator undefined in node
461 return 'None';
461 return 'None';
462 }
462 }
463 var OSName="None";
463 var OSName="None";
464 if (navigator.appVersion.indexOf("Win")!=-1) OSName="Windows";
464 if (navigator.appVersion.indexOf("Win")!=-1) OSName="Windows";
465 if (navigator.appVersion.indexOf("Mac")!=-1) OSName="MacOS";
465 if (navigator.appVersion.indexOf("Mac")!=-1) OSName="MacOS";
466 if (navigator.appVersion.indexOf("X11")!=-1) OSName="UNIX";
466 if (navigator.appVersion.indexOf("X11")!=-1) OSName="UNIX";
467 if (navigator.appVersion.indexOf("Linux")!=-1) OSName="Linux";
467 if (navigator.appVersion.indexOf("Linux")!=-1) OSName="Linux";
468 return OSName
468 return OSName
469 })();
469 })();
470
470
471 var is_or_has = function (a, b) {
471 var is_or_has = function (a, b) {
472 // Is b a child of a or a itself?
472 // Is b a child of a or a itself?
473 return a.has(b).length !==0 || a.is(b);
473 return a.has(b).length !==0 || a.is(b);
474 }
474 }
475
475
476 var is_focused = function (e) {
476 var is_focused = function (e) {
477 // Is element e, or one of its children focused?
477 // Is element e, or one of its children focused?
478 e = $(e);
478 e = $(e);
479 var target = $(document.activeElement);
479 var target = $(document.activeElement);
480 if (target.length > 0) {
480 if (target.length > 0) {
481 if (is_or_has(e, target)) {
481 if (is_or_has(e, target)) {
482 return true;
482 return true;
483 } else {
483 } else {
484 return false;
484 return false;
485 }
485 }
486 } else {
486 } else {
487 return false;
487 return false;
488 }
488 }
489 }
489 }
490
490
491 var get_attr_names = function (e) {
492 // Get the names of all the HTML attributes of the element e.
493 var el = $(e)[0];
494 var arr = [];
495 for (var i=0, attrs=el.attributes, l=attrs.length; i<l; i++){
496 arr.push(attrs.item(i).nodeName);
497 }
498 return arr;
499 }
491
500
492 return {
501 return {
493 regex_split : regex_split,
502 regex_split : regex_split,
494 uuid : uuid,
503 uuid : uuid,
495 fixConsole : fixConsole,
504 fixConsole : fixConsole,
496 fixCarriageReturn : fixCarriageReturn,
505 fixCarriageReturn : fixCarriageReturn,
497 autoLinkUrls : autoLinkUrls,
506 autoLinkUrls : autoLinkUrls,
498 points_to_pixels : points_to_pixels,
507 points_to_pixels : points_to_pixels,
499 get_body_data : get_body_data,
508 get_body_data : get_body_data,
500 parse_url : parse_url,
509 parse_url : parse_url,
501 url_path_join : url_path_join,
510 url_path_join : url_path_join,
502 url_join_encode : url_join_encode,
511 url_join_encode : url_join_encode,
503 encode_uri_components : encode_uri_components,
512 encode_uri_components : encode_uri_components,
504 splitext : splitext,
513 splitext : splitext,
505 escape_html : escape_html,
514 escape_html : escape_html,
506 always_new : always_new,
515 always_new : always_new,
507 browser : browser,
516 browser : browser,
508 platform: platform,
517 platform: platform,
509 is_or_has : is_or_has,
518 is_or_has : is_or_has,
510 is_focused : is_focused
519 is_focused : is_focused,
520 get_attr_names: get_attr_names
511 };
521 };
512
522
513 }(IPython));
523 }(IPython));
514
524
@@ -1,561 +1,566 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 "use strict";
20 "use strict";
21
21
22 // TextCell base class
22 // TextCell base class
23 <<<<<<< HEAD
23 var keycodes = IPython.keyboard.keycodes;
24 var keycodes = IPython.keyboard.keycodes;
25 =======
26 var key = IPython.utils.keycodes;
27 var security = IPython.security;
28 >>>>>>> 8e23f06... Adding security.js with 1st attempt at is_safe.
24
29
25 /**
30 /**
26 * Construct a new TextCell, codemirror mode is by default 'htmlmixed', and cell type is 'text'
31 * Construct a new TextCell, codemirror mode is by default 'htmlmixed', and cell type is 'text'
27 * cell start as not redered.
32 * cell start as not redered.
28 *
33 *
29 * @class TextCell
34 * @class TextCell
30 * @constructor TextCell
35 * @constructor TextCell
31 * @extend IPython.Cell
36 * @extend IPython.Cell
32 * @param {object|undefined} [options]
37 * @param {object|undefined} [options]
33 * @param [options.cm_config] {object} config to pass to CodeMirror, will extend/overwrite default config
38 * @param [options.cm_config] {object} config to pass to CodeMirror, will extend/overwrite default config
34 * @param [options.placeholder] {string} default string to use when souce in empty for rendering (only use in some TextCell subclass)
39 * @param [options.placeholder] {string} default string to use when souce in empty for rendering (only use in some TextCell subclass)
35 */
40 */
36 var TextCell = function (options) {
41 var TextCell = function (options) {
37 // in all TextCell/Cell subclasses
42 // in all TextCell/Cell subclasses
38 // do not assign most of members here, just pass it down
43 // do not assign most of members here, just pass it down
39 // in the options dict potentially overwriting what you wish.
44 // in the options dict potentially overwriting what you wish.
40 // they will be assigned in the base class.
45 // they will be assigned in the base class.
41
46
42 // we cannot put this as a class key as it has handle to "this".
47 // we cannot put this as a class key as it has handle to "this".
43 var cm_overwrite_options = {
48 var cm_overwrite_options = {
44 onKeyEvent: $.proxy(this.handle_keyevent,this)
49 onKeyEvent: $.proxy(this.handle_keyevent,this)
45 };
50 };
46
51
47 options = this.mergeopt(TextCell,options,{cm_config:cm_overwrite_options});
52 options = this.mergeopt(TextCell,options,{cm_config:cm_overwrite_options});
48
53
49 this.cell_type = this.cell_type || 'text';
54 this.cell_type = this.cell_type || 'text';
50
55
51 IPython.Cell.apply(this, [options]);
56 IPython.Cell.apply(this, [options]);
52
57
53 this.rendered = false;
58 this.rendered = false;
54 };
59 };
55
60
56 TextCell.prototype = new IPython.Cell();
61 TextCell.prototype = new IPython.Cell();
57
62
58 TextCell.options_default = {
63 TextCell.options_default = {
59 cm_config : {
64 cm_config : {
60 extraKeys: {"Tab": "indentMore","Shift-Tab" : "indentLess"},
65 extraKeys: {"Tab": "indentMore","Shift-Tab" : "indentLess"},
61 mode: 'htmlmixed',
66 mode: 'htmlmixed',
62 lineWrapping : true,
67 lineWrapping : true,
63 }
68 }
64 };
69 };
65
70
66
71
67 /**
72 /**
68 * Create the DOM element of the TextCell
73 * Create the DOM element of the TextCell
69 * @method create_element
74 * @method create_element
70 * @private
75 * @private
71 */
76 */
72 TextCell.prototype.create_element = function () {
77 TextCell.prototype.create_element = function () {
73 IPython.Cell.prototype.create_element.apply(this, arguments);
78 IPython.Cell.prototype.create_element.apply(this, arguments);
74
79
75 var cell = $("<div>").addClass('cell text_cell border-box-sizing');
80 var cell = $("<div>").addClass('cell text_cell border-box-sizing');
76 cell.attr('tabindex','2');
81 cell.attr('tabindex','2');
77
82
78 var prompt = $('<div/>').addClass('prompt input_prompt');
83 var prompt = $('<div/>').addClass('prompt input_prompt');
79 cell.append(prompt);
84 cell.append(prompt);
80 var inner_cell = $('<div/>').addClass('inner_cell');
85 var inner_cell = $('<div/>').addClass('inner_cell');
81 this.celltoolbar = new IPython.CellToolbar(this);
86 this.celltoolbar = new IPython.CellToolbar(this);
82 inner_cell.append(this.celltoolbar.element);
87 inner_cell.append(this.celltoolbar.element);
83 var input_area = $('<div/>').addClass('input_area');
88 var input_area = $('<div/>').addClass('input_area');
84 this.code_mirror = new CodeMirror(input_area.get(0), this.cm_config);
89 this.code_mirror = new CodeMirror(input_area.get(0), this.cm_config);
85 // The tabindex=-1 makes this div focusable.
90 // The tabindex=-1 makes this div focusable.
86 var render_area = $('<div/>').addClass('text_cell_render border-box-sizing').
91 var render_area = $('<div/>').addClass('text_cell_render border-box-sizing').
87 addClass('rendered_html').attr('tabindex','-1');
92 addClass('rendered_html').attr('tabindex','-1');
88 inner_cell.append(input_area).append(render_area);
93 inner_cell.append(input_area).append(render_area);
89 cell.append(inner_cell);
94 cell.append(inner_cell);
90 this.element = cell;
95 this.element = cell;
91 };
96 };
92
97
93
98
94 /**
99 /**
95 * Bind the DOM evet to cell actions
100 * Bind the DOM evet to cell actions
96 * Need to be called after TextCell.create_element
101 * Need to be called after TextCell.create_element
97 * @private
102 * @private
98 * @method bind_event
103 * @method bind_event
99 */
104 */
100 TextCell.prototype.bind_events = function () {
105 TextCell.prototype.bind_events = function () {
101 IPython.Cell.prototype.bind_events.apply(this);
106 IPython.Cell.prototype.bind_events.apply(this);
102 var that = this;
107 var that = this;
103
108
104 this.element.dblclick(function () {
109 this.element.dblclick(function () {
105 if (that.selected === false) {
110 if (that.selected === false) {
106 $([IPython.events]).trigger('select.Cell', {'cell':that});
111 $([IPython.events]).trigger('select.Cell', {'cell':that});
107 }
112 }
108 var cont = that.unrender();
113 var cont = that.unrender();
109 if (cont) {
114 if (cont) {
110 that.focus_editor();
115 that.focus_editor();
111 }
116 }
112 });
117 });
113 };
118 };
114
119
115 TextCell.prototype.handle_keyevent = function (editor, event) {
120 TextCell.prototype.handle_keyevent = function (editor, event) {
116
121
117 // console.log('CM', this.mode, event.which, event.type)
122 // console.log('CM', this.mode, event.which, event.type)
118
123
119 if (this.mode === 'command') {
124 if (this.mode === 'command') {
120 return true;
125 return true;
121 } else if (this.mode === 'edit') {
126 } else if (this.mode === 'edit') {
122 return this.handle_codemirror_keyevent(editor, event);
127 return this.handle_codemirror_keyevent(editor, event);
123 }
128 }
124 };
129 };
125
130
126 /**
131 /**
127 * This method gets called in CodeMirror's onKeyDown/onKeyPress
132 * This method gets called in CodeMirror's onKeyDown/onKeyPress
128 * handlers and is used to provide custom key handling.
133 * handlers and is used to provide custom key handling.
129 *
134 *
130 * Subclass should override this method to have custom handeling
135 * Subclass should override this method to have custom handeling
131 *
136 *
132 * @method handle_codemirror_keyevent
137 * @method handle_codemirror_keyevent
133 * @param {CodeMirror} editor - The codemirror instance bound to the cell
138 * @param {CodeMirror} editor - The codemirror instance bound to the cell
134 * @param {event} event -
139 * @param {event} event -
135 * @return {Boolean} `true` if CodeMirror should ignore the event, `false` Otherwise
140 * @return {Boolean} `true` if CodeMirror should ignore the event, `false` Otherwise
136 */
141 */
137 TextCell.prototype.handle_codemirror_keyevent = function (editor, event) {
142 TextCell.prototype.handle_codemirror_keyevent = function (editor, event) {
138 var that = this;
143 var that = this;
139
144
140 if (event.keyCode === 13 && (event.shiftKey || event.ctrlKey || event.altKey)) {
145 if (event.keyCode === 13 && (event.shiftKey || event.ctrlKey || event.altKey)) {
141 // Always ignore shift-enter in CodeMirror as we handle it.
146 // Always ignore shift-enter in CodeMirror as we handle it.
142 return true;
147 return true;
143 } else if (event.which === keycodes.up && event.type === 'keydown') {
148 } else if (event.which === keycodes.up && event.type === 'keydown') {
144 // If we are not at the top, let CM handle the up arrow and
149 // If we are not at the top, let CM handle the up arrow and
145 // prevent the global keydown handler from handling it.
150 // prevent the global keydown handler from handling it.
146 if (!that.at_top()) {
151 if (!that.at_top()) {
147 event.stop();
152 event.stop();
148 return false;
153 return false;
149 } else {
154 } else {
150 return true;
155 return true;
151 };
156 };
152 } else if (event.which === keycodes.down && event.type === 'keydown') {
157 } else if (event.which === keycodes.down && event.type === 'keydown') {
153 // If we are not at the bottom, let CM handle the down arrow and
158 // If we are not at the bottom, let CM handle the down arrow and
154 // prevent the global keydown handler from handling it.
159 // prevent the global keydown handler from handling it.
155 if (!that.at_bottom()) {
160 if (!that.at_bottom()) {
156 event.stop();
161 event.stop();
157 return false;
162 return false;
158 } else {
163 } else {
159 return true;
164 return true;
160 };
165 };
161 } else if (event.which === keycodes.esc && event.type === 'keydown') {
166 } else if (event.which === keycodes.esc && event.type === 'keydown') {
162 if (that.code_mirror.options.keyMap === "vim-insert") {
167 if (that.code_mirror.options.keyMap === "vim-insert") {
163 // vim keyMap is active and in insert mode. In this case we leave vim
168 // vim keyMap is active and in insert mode. In this case we leave vim
164 // insert mode, but remain in notebook edit mode.
169 // insert mode, but remain in notebook edit mode.
165 // Let' CM handle this event and prevent global handling.
170 // Let' CM handle this event and prevent global handling.
166 event.stop();
171 event.stop();
167 return false;
172 return false;
168 } else {
173 } else {
169 // vim keyMap is not active. Leave notebook edit mode.
174 // vim keyMap is not active. Leave notebook edit mode.
170 // Don't let CM handle the event, defer to global handling.
175 // Don't let CM handle the event, defer to global handling.
171 return true;
176 return true;
172 }
177 }
173 }
178 }
174 return false;
179 return false;
175 };
180 };
176
181
177 // Cell level actions
182 // Cell level actions
178
183
179 TextCell.prototype.select = function () {
184 TextCell.prototype.select = function () {
180 var cont = IPython.Cell.prototype.select.apply(this);
185 var cont = IPython.Cell.prototype.select.apply(this);
181 if (cont) {
186 if (cont) {
182 if (this.mode === 'edit') {
187 if (this.mode === 'edit') {
183 this.code_mirror.refresh();
188 this.code_mirror.refresh();
184 }
189 }
185 }
190 }
186 return cont;
191 return cont;
187 };
192 };
188
193
189 TextCell.prototype.unrender = function () {
194 TextCell.prototype.unrender = function () {
190 if (this.read_only) return;
195 if (this.read_only) return;
191 var cont = IPython.Cell.prototype.unrender.apply(this);
196 var cont = IPython.Cell.prototype.unrender.apply(this);
192 if (cont) {
197 if (cont) {
193 var text_cell = this.element;
198 var text_cell = this.element;
194 var output = text_cell.find("div.text_cell_render");
199 var output = text_cell.find("div.text_cell_render");
195 output.hide();
200 output.hide();
196 text_cell.find('div.input_area').show();
201 text_cell.find('div.input_area').show();
197 if (this.get_text() === this.placeholder) {
202 if (this.get_text() === this.placeholder) {
198 this.set_text('');
203 this.set_text('');
199 }
204 }
200 this.refresh();
205 this.refresh();
201 }
206 }
202 return cont;
207 return cont;
203 };
208 };
204
209
205 TextCell.prototype.execute = function () {
210 TextCell.prototype.execute = function () {
206 this.render();
211 this.render();
207 };
212 };
208
213
209 /**
214 /**
210 * setter: {{#crossLink "TextCell/set_text"}}{{/crossLink}}
215 * setter: {{#crossLink "TextCell/set_text"}}{{/crossLink}}
211 * @method get_text
216 * @method get_text
212 * @retrun {string} CodeMirror current text value
217 * @retrun {string} CodeMirror current text value
213 */
218 */
214 TextCell.prototype.get_text = function() {
219 TextCell.prototype.get_text = function() {
215 return this.code_mirror.getValue();
220 return this.code_mirror.getValue();
216 };
221 };
217
222
218 /**
223 /**
219 * @param {string} text - Codemiror text value
224 * @param {string} text - Codemiror text value
220 * @see TextCell#get_text
225 * @see TextCell#get_text
221 * @method set_text
226 * @method set_text
222 * */
227 * */
223 TextCell.prototype.set_text = function(text) {
228 TextCell.prototype.set_text = function(text) {
224 this.code_mirror.setValue(text);
229 this.code_mirror.setValue(text);
225 this.code_mirror.refresh();
230 this.code_mirror.refresh();
226 };
231 };
227
232
228 /**
233 /**
229 * setter :{{#crossLink "TextCell/set_rendered"}}{{/crossLink}}
234 * setter :{{#crossLink "TextCell/set_rendered"}}{{/crossLink}}
230 * @method get_rendered
235 * @method get_rendered
231 * @return {html} html of rendered element
236 * @return {html} html of rendered element
232 * */
237 * */
233 TextCell.prototype.get_rendered = function() {
238 TextCell.prototype.get_rendered = function() {
234 return this.element.find('div.text_cell_render').html();
239 return this.element.find('div.text_cell_render').html();
235 };
240 };
236
241
237 /**
242 /**
238 * @method set_rendered
243 * @method set_rendered
239 */
244 */
240 TextCell.prototype.set_rendered = function(text) {
245 TextCell.prototype.set_rendered = function(text) {
241 this.element.find('div.text_cell_render').html(text);
246 this.element.find('div.text_cell_render').html(text);
242 };
247 };
243
248
244 /**
249 /**
245 * @method at_top
250 * @method at_top
246 * @return {Boolean}
251 * @return {Boolean}
247 */
252 */
248 TextCell.prototype.at_top = function () {
253 TextCell.prototype.at_top = function () {
249 if (this.rendered) {
254 if (this.rendered) {
250 return true;
255 return true;
251 } else {
256 } else {
252 var cursor = this.code_mirror.getCursor();
257 var cursor = this.code_mirror.getCursor();
253 if (cursor.line === 0 && cursor.ch === 0) {
258 if (cursor.line === 0 && cursor.ch === 0) {
254 return true;
259 return true;
255 } else {
260 } else {
256 return false;
261 return false;
257 }
262 }
258 }
263 }
259 };
264 };
260
265
261 /**
266 /**
262 * @method at_bottom
267 * @method at_bottom
263 * @return {Boolean}
268 * @return {Boolean}
264 * */
269 * */
265 TextCell.prototype.at_bottom = function () {
270 TextCell.prototype.at_bottom = function () {
266 if (this.rendered) {
271 if (this.rendered) {
267 return true;
272 return true;
268 } else {
273 } else {
269 var cursor = this.code_mirror.getCursor();
274 var cursor = this.code_mirror.getCursor();
270 if (cursor.line === (this.code_mirror.lineCount()-1) && cursor.ch === this.code_mirror.getLine(cursor.line).length) {
275 if (cursor.line === (this.code_mirror.lineCount()-1) && cursor.ch === this.code_mirror.getLine(cursor.line).length) {
271 return true;
276 return true;
272 } else {
277 } else {
273 return false;
278 return false;
274 }
279 }
275 }
280 }
276 };
281 };
277
282
278 /**
283 /**
279 * Create Text cell from JSON
284 * Create Text cell from JSON
280 * @param {json} data - JSON serialized text-cell
285 * @param {json} data - JSON serialized text-cell
281 * @method fromJSON
286 * @method fromJSON
282 */
287 */
283 TextCell.prototype.fromJSON = function (data) {
288 TextCell.prototype.fromJSON = function (data) {
284 IPython.Cell.prototype.fromJSON.apply(this, arguments);
289 IPython.Cell.prototype.fromJSON.apply(this, arguments);
285 if (data.cell_type === this.cell_type) {
290 if (data.cell_type === this.cell_type) {
286 if (data.source !== undefined) {
291 if (data.source !== undefined) {
287 this.set_text(data.source);
292 this.set_text(data.source);
288 // make this value the starting point, so that we can only undo
293 // make this value the starting point, so that we can only undo
289 // to this state, instead of a blank cell
294 // to this state, instead of a blank cell
290 this.code_mirror.clearHistory();
295 this.code_mirror.clearHistory();
291 // TODO: This HTML needs to be treated as potentially dangerous
296 // TODO: This HTML needs to be treated as potentially dangerous
292 // user input and should be handled before set_rendered.
297 // user input and should be handled before set_rendered.
293 this.set_rendered(data.rendered || '');
298 this.set_rendered(data.rendered || '');
294 this.rendered = false;
299 this.rendered = false;
295 this.render();
300 this.render();
296 }
301 }
297 }
302 }
298 };
303 };
299
304
300 /** Generate JSON from cell
305 /** Generate JSON from cell
301 * @return {object} cell data serialised to json
306 * @return {object} cell data serialised to json
302 */
307 */
303 TextCell.prototype.toJSON = function () {
308 TextCell.prototype.toJSON = function () {
304 var data = IPython.Cell.prototype.toJSON.apply(this);
309 var data = IPython.Cell.prototype.toJSON.apply(this);
305 data.source = this.get_text();
310 data.source = this.get_text();
306 if (data.source == this.placeholder) {
311 if (data.source == this.placeholder) {
307 data.source = "";
312 data.source = "";
308 }
313 }
309 return data;
314 return data;
310 };
315 };
311
316
312
317
313 /**
318 /**
314 * @class MarkdownCell
319 * @class MarkdownCell
315 * @constructor MarkdownCell
320 * @constructor MarkdownCell
316 * @extends IPython.HTMLCell
321 * @extends IPython.HTMLCell
317 */
322 */
318 var MarkdownCell = function (options) {
323 var MarkdownCell = function (options) {
319 options = this.mergeopt(MarkdownCell, options);
324 options = this.mergeopt(MarkdownCell, options);
320
325
321 this.cell_type = 'markdown';
326 this.cell_type = 'markdown';
322 TextCell.apply(this, [options]);
327 TextCell.apply(this, [options]);
323 };
328 };
324
329
325 MarkdownCell.options_default = {
330 MarkdownCell.options_default = {
326 cm_config: {
331 cm_config: {
327 mode: 'gfm'
332 mode: 'gfm'
328 },
333 },
329 placeholder: "Type *Markdown* and LaTeX: $\\alpha^2$"
334 placeholder: "Type *Markdown* and LaTeX: $\\alpha^2$"
330 };
335 };
331
336
332 MarkdownCell.prototype = new TextCell();
337 MarkdownCell.prototype = new TextCell();
333
338
334 /**
339 /**
335 * @method render
340 * @method render
336 */
341 */
337 MarkdownCell.prototype.render = function () {
342 MarkdownCell.prototype.render = function () {
338 var cont = IPython.TextCell.prototype.render.apply(this);
343 var cont = IPython.TextCell.prototype.render.apply(this);
339 if (cont) {
344 if (cont) {
340 var text = this.get_text();
345 var text = this.get_text();
341 var math = null;
346 var math = null;
342 if (text === "") { text = this.placeholder; }
347 if (text === "") { text = this.placeholder; }
343 var text_and_math = IPython.mathjaxutils.remove_math(text);
348 var text_and_math = IPython.mathjaxutils.remove_math(text);
344 text = text_and_math[0];
349 text = text_and_math[0];
345 math = text_and_math[1];
350 math = text_and_math[1];
346 var html = marked.parser(marked.lexer(text));
351 var html = marked.parser(marked.lexer(text));
347 html = $(IPython.mathjaxutils.replace_math(html, math));
352 html = $(IPython.mathjaxutils.replace_math(html, math));
348 // Links in markdown cells should open in new tabs.
353 // Links in markdown cells should open in new tabs.
349 html.find("a[href]").not('[href^="#"]').attr("target", "_blank");
354 html.find("a[href]").not('[href^="#"]').attr("target", "_blank");
350 try {
355 try {
351 // TODO: This HTML needs to be treated as potentially dangerous
356 // TODO: This HTML needs to be treated as potentially dangerous
352 // user input and should be handled before set_rendered.
357 // user input and should be handled before set_rendered.
353 this.set_rendered(html);
358 this.set_rendered(html);
354 } catch (e) {
359 } catch (e) {
355 console.log("Error running Javascript in Markdown:");
360 console.log("Error running Javascript in Markdown:");
356 console.log(e);
361 console.log(e);
357 this.set_rendered(
362 this.set_rendered(
358 $("<div/>")
363 $("<div/>")
359 .append($("<div/>").text('Error rendering Markdown!').addClass("js-error"))
364 .append($("<div/>").text('Error rendering Markdown!').addClass("js-error"))
360 .append($("<div/>").text(e.toString()).addClass("js-error"))
365 .append($("<div/>").text(e.toString()).addClass("js-error"))
361 .html()
366 .html()
362 );
367 );
363 }
368 }
364 this.element.find('div.input_area').hide();
369 this.element.find('div.input_area').hide();
365 this.element.find("div.text_cell_render").show();
370 this.element.find("div.text_cell_render").show();
366 this.typeset();
371 this.typeset();
367 }
372 }
368 return cont;
373 return cont;
369 };
374 };
370
375
371
376
372 // RawCell
377 // RawCell
373
378
374 /**
379 /**
375 * @class RawCell
380 * @class RawCell
376 * @constructor RawCell
381 * @constructor RawCell
377 * @extends IPython.TextCell
382 * @extends IPython.TextCell
378 */
383 */
379 var RawCell = function (options) {
384 var RawCell = function (options) {
380
385
381 options = this.mergeopt(RawCell,options);
386 options = this.mergeopt(RawCell,options);
382 TextCell.apply(this, [options]);
387 TextCell.apply(this, [options]);
383 this.cell_type = 'raw';
388 this.cell_type = 'raw';
384 // RawCell should always hide its rendered div
389 // RawCell should always hide its rendered div
385 this.element.find('div.text_cell_render').hide();
390 this.element.find('div.text_cell_render').hide();
386 };
391 };
387
392
388 RawCell.options_default = {
393 RawCell.options_default = {
389 placeholder : "Write raw LaTeX or other formats here, for use with nbconvert.\n" +
394 placeholder : "Write raw LaTeX or other formats here, for use with nbconvert.\n" +
390 "It will not be rendered in the notebook.\n" +
395 "It will not be rendered in the notebook.\n" +
391 "When passing through nbconvert, a Raw Cell's content is added to the output unmodified."
396 "When passing through nbconvert, a Raw Cell's content is added to the output unmodified."
392 };
397 };
393
398
394 RawCell.prototype = new TextCell();
399 RawCell.prototype = new TextCell();
395
400
396 /** @method bind_events **/
401 /** @method bind_events **/
397 RawCell.prototype.bind_events = function () {
402 RawCell.prototype.bind_events = function () {
398 TextCell.prototype.bind_events.apply(this);
403 TextCell.prototype.bind_events.apply(this);
399 var that = this;
404 var that = this;
400 this.element.focusout(function() {
405 this.element.focusout(function() {
401 that.auto_highlight();
406 that.auto_highlight();
402 });
407 });
403 };
408 };
404
409
405 /**
410 /**
406 * Trigger autodetection of highlight scheme for current cell
411 * Trigger autodetection of highlight scheme for current cell
407 * @method auto_highlight
412 * @method auto_highlight
408 */
413 */
409 RawCell.prototype.auto_highlight = function () {
414 RawCell.prototype.auto_highlight = function () {
410 this._auto_highlight(IPython.config.raw_cell_highlight);
415 this._auto_highlight(IPython.config.raw_cell_highlight);
411 };
416 };
412
417
413 /** @method render **/
418 /** @method render **/
414 RawCell.prototype.render = function () {
419 RawCell.prototype.render = function () {
415 // Make sure that this cell type can never be rendered
420 // Make sure that this cell type can never be rendered
416 if (this.rendered) {
421 if (this.rendered) {
417 this.unrender();
422 this.unrender();
418 }
423 }
419 var text = this.get_text();
424 var text = this.get_text();
420 if (text === "") { text = this.placeholder; }
425 if (text === "") { text = this.placeholder; }
421 this.set_text(text);
426 this.set_text(text);
422 };
427 };
423
428
424
429
425 /**
430 /**
426 * @class HeadingCell
431 * @class HeadingCell
427 * @extends IPython.TextCell
432 * @extends IPython.TextCell
428 */
433 */
429
434
430 /**
435 /**
431 * @constructor HeadingCell
436 * @constructor HeadingCell
432 * @extends IPython.TextCell
437 * @extends IPython.TextCell
433 */
438 */
434 var HeadingCell = function (options) {
439 var HeadingCell = function (options) {
435 options = this.mergeopt(HeadingCell, options);
440 options = this.mergeopt(HeadingCell, options);
436
441
437 this.level = 1;
442 this.level = 1;
438 this.cell_type = 'heading';
443 this.cell_type = 'heading';
439 TextCell.apply(this, [options]);
444 TextCell.apply(this, [options]);
440
445
441 /**
446 /**
442 * heading level of the cell, use getter and setter to access
447 * heading level of the cell, use getter and setter to access
443 * @property level
448 * @property level
444 */
449 */
445 };
450 };
446
451
447 HeadingCell.options_default = {
452 HeadingCell.options_default = {
448 placeholder: "Type Heading Here"
453 placeholder: "Type Heading Here"
449 };
454 };
450
455
451 HeadingCell.prototype = new TextCell();
456 HeadingCell.prototype = new TextCell();
452
457
453 /** @method fromJSON */
458 /** @method fromJSON */
454 HeadingCell.prototype.fromJSON = function (data) {
459 HeadingCell.prototype.fromJSON = function (data) {
455 if (data.level !== undefined){
460 if (data.level !== undefined){
456 this.level = data.level;
461 this.level = data.level;
457 }
462 }
458 TextCell.prototype.fromJSON.apply(this, arguments);
463 TextCell.prototype.fromJSON.apply(this, arguments);
459 };
464 };
460
465
461
466
462 /** @method toJSON */
467 /** @method toJSON */
463 HeadingCell.prototype.toJSON = function () {
468 HeadingCell.prototype.toJSON = function () {
464 var data = TextCell.prototype.toJSON.apply(this);
469 var data = TextCell.prototype.toJSON.apply(this);
465 data.level = this.get_level();
470 data.level = this.get_level();
466 return data;
471 return data;
467 };
472 };
468
473
469 /**
474 /**
470 * can the cell be split into two cells
475 * can the cell be split into two cells
471 * @method is_splittable
476 * @method is_splittable
472 **/
477 **/
473 HeadingCell.prototype.is_splittable = function () {
478 HeadingCell.prototype.is_splittable = function () {
474 return false;
479 return false;
475 };
480 };
476
481
477
482
478 /**
483 /**
479 * can the cell be merged with other cells
484 * can the cell be merged with other cells
480 * @method is_mergeable
485 * @method is_mergeable
481 **/
486 **/
482 HeadingCell.prototype.is_mergeable = function () {
487 HeadingCell.prototype.is_mergeable = function () {
483 return false;
488 return false;
484 };
489 };
485
490
486 /**
491 /**
487 * Change heading level of cell, and re-render
492 * Change heading level of cell, and re-render
488 * @method set_level
493 * @method set_level
489 */
494 */
490 HeadingCell.prototype.set_level = function (level) {
495 HeadingCell.prototype.set_level = function (level) {
491 this.level = level;
496 this.level = level;
492 if (this.rendered) {
497 if (this.rendered) {
493 this.rendered = false;
498 this.rendered = false;
494 this.render();
499 this.render();
495 }
500 }
496 };
501 };
497
502
498 /** The depth of header cell, based on html (h1 to h6)
503 /** The depth of header cell, based on html (h1 to h6)
499 * @method get_level
504 * @method get_level
500 * @return {integer} level - for 1 to 6
505 * @return {integer} level - for 1 to 6
501 */
506 */
502 HeadingCell.prototype.get_level = function () {
507 HeadingCell.prototype.get_level = function () {
503 return this.level;
508 return this.level;
504 };
509 };
505
510
506
511
507 HeadingCell.prototype.set_rendered = function (html) {
512 HeadingCell.prototype.set_rendered = function (html) {
508 this.element.find("div.text_cell_render").html(html);
513 this.element.find("div.text_cell_render").html(html);
509 };
514 };
510
515
511
516
512 HeadingCell.prototype.get_rendered = function () {
517 HeadingCell.prototype.get_rendered = function () {
513 var r = this.element.find("div.text_cell_render");
518 var r = this.element.find("div.text_cell_render");
514 return r.children().first().html();
519 return r.children().first().html();
515 };
520 };
516
521
517
522
518 HeadingCell.prototype.render = function () {
523 HeadingCell.prototype.render = function () {
519 var cont = IPython.TextCell.prototype.render.apply(this);
524 var cont = IPython.TextCell.prototype.render.apply(this);
520 if (cont) {
525 if (cont) {
521 var text = this.get_text();
526 var text = this.get_text();
522 var math = null;
527 var math = null;
523 // Markdown headings must be a single line
528 // Markdown headings must be a single line
524 text = text.replace(/\n/g, ' ');
529 text = text.replace(/\n/g, ' ');
525 if (text === "") { text = this.placeholder; }
530 if (text === "") { text = this.placeholder; }
526 text = Array(this.level + 1).join("#") + " " + text;
531 text = Array(this.level + 1).join("#") + " " + text;
527 var text_and_math = IPython.mathjaxutils.remove_math(text);
532 var text_and_math = IPython.mathjaxutils.remove_math(text);
528 text = text_and_math[0];
533 text = text_and_math[0];
529 math = text_and_math[1];
534 math = text_and_math[1];
530 var html = marked.parser(marked.lexer(text));
535 var html = marked.parser(marked.lexer(text));
531 var h = $(IPython.mathjaxutils.replace_math(html, math));
536 var h = $(IPython.mathjaxutils.replace_math(html, math));
532 // add id and linkback anchor
537 // add id and linkback anchor
533 var hash = h.text().replace(/ /g, '-');
538 var hash = h.text().replace(/ /g, '-');
534 h.attr('id', hash);
539 h.attr('id', hash);
535 h.append(
540 h.append(
536 $('<a/>')
541 $('<a/>')
537 .addClass('anchor-link')
542 .addClass('anchor-link')
538 .attr('href', '#' + hash)
543 .attr('href', '#' + hash)
539 .text('ΒΆ')
544 .text('ΒΆ')
540 );
545 );
541 // TODO: This HTML needs to be treated as potentially dangerous
546 // TODO: This HTML needs to be treated as potentially dangerous
542 // user input and should be handled before set_rendered.
547 // user input and should be handled before set_rendered.
543 this.set_rendered(h);
548 this.set_rendered(h);
544 this.typeset();
549 this.typeset();
545 this.element.find('div.input_area').hide();
550 this.element.find('div.input_area').hide();
546 this.element.find("div.text_cell_render").show();
551 this.element.find("div.text_cell_render").show();
547
552
548 }
553 }
549 return cont;
554 return cont;
550 };
555 };
551
556
552 IPython.TextCell = TextCell;
557 IPython.TextCell = TextCell;
553 IPython.MarkdownCell = MarkdownCell;
558 IPython.MarkdownCell = MarkdownCell;
554 IPython.RawCell = RawCell;
559 IPython.RawCell = RawCell;
555 IPython.HeadingCell = HeadingCell;
560 IPython.HeadingCell = HeadingCell;
556
561
557
562
558 return IPython;
563 return IPython;
559
564
560 }(IPython));
565 }(IPython));
561
566
@@ -1,353 +1,354 b''
1 {% extends "page.html" %}
1 {% extends "page.html" %}
2
2
3 {% block stylesheet %}
3 {% block stylesheet %}
4
4
5 {% if mathjax_url %}
5 {% if mathjax_url %}
6 <script type="text/javascript" src="{{mathjax_url}}?config=TeX-AMS_HTML-full&delayStartupUntil=configured" charset="utf-8"></script>
6 <script type="text/javascript" src="{{mathjax_url}}?config=TeX-AMS_HTML-full&delayStartupUntil=configured" charset="utf-8"></script>
7 {% endif %}
7 {% endif %}
8 <script type="text/javascript">
8 <script type="text/javascript">
9 // MathJax disabled, set as null to distingish from *missing* MathJax,
9 // MathJax disabled, set as null to distingish from *missing* MathJax,
10 // where it will be undefined, and should prompt a dialog later.
10 // where it will be undefined, and should prompt a dialog later.
11 window.mathjax_url = "{{mathjax_url}}";
11 window.mathjax_url = "{{mathjax_url}}";
12 </script>
12 </script>
13
13
14 <link rel="stylesheet" href="{{ static_url("components/codemirror/lib/codemirror.css") }}">
14 <link rel="stylesheet" href="{{ static_url("components/codemirror/lib/codemirror.css") }}">
15
15
16 {{super()}}
16 {{super()}}
17
17
18 <link rel="stylesheet" href="{{ static_url("notebook/css/override.css") }}" type="text/css" />
18 <link rel="stylesheet" href="{{ static_url("notebook/css/override.css") }}" type="text/css" />
19
19
20 {% endblock %}
20 {% endblock %}
21
21
22 {% block params %}
22 {% block params %}
23
23
24 data-project="{{project}}"
24 data-project="{{project}}"
25 data-base-url="{{base_url}}"
25 data-base-url="{{base_url}}"
26 data-notebook-name="{{notebook_name}}"
26 data-notebook-name="{{notebook_name}}"
27 data-notebook-path="{{notebook_path}}"
27 data-notebook-path="{{notebook_path}}"
28 class="notebook_app"
28 class="notebook_app"
29
29
30 {% endblock %}
30 {% endblock %}
31
31
32
32
33 {% block header %}
33 {% block header %}
34
34
35 <span id="save_widget" class="nav pull-left">
35 <span id="save_widget" class="nav pull-left">
36 <span id="notebook_name"></span>
36 <span id="notebook_name"></span>
37 <span id="checkpoint_status"></span>
37 <span id="checkpoint_status"></span>
38 <span id="autosave_status"></span>
38 <span id="autosave_status"></span>
39 </span>
39 </span>
40
40
41 {% endblock %}
41 {% endblock %}
42
42
43
43
44 {% block site %}
44 {% block site %}
45
45
46 <div id="menubar-container" class="container">
46 <div id="menubar-container" class="container">
47 <div id="menubar">
47 <div id="menubar">
48 <div class="navbar">
48 <div class="navbar">
49 <div class="navbar-inner">
49 <div class="navbar-inner">
50 <div class="container">
50 <div class="container">
51 <ul id="menus" class="nav">
51 <ul id="menus" class="nav">
52 <li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown">File</a>
52 <li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown">File</a>
53 <ul id="file_menu" class="dropdown-menu">
53 <ul id="file_menu" class="dropdown-menu">
54 <li id="new_notebook"
54 <li id="new_notebook"
55 title="Make a new notebook (Opens a new window)">
55 title="Make a new notebook (Opens a new window)">
56 <a href="#">New</a></li>
56 <a href="#">New</a></li>
57 <li id="open_notebook"
57 <li id="open_notebook"
58 title="Opens a new window with the Dashboard view">
58 title="Opens a new window with the Dashboard view">
59 <a href="#">Open...</a></li>
59 <a href="#">Open...</a></li>
60 <!-- <hr/> -->
60 <!-- <hr/> -->
61 <li class="divider"></li>
61 <li class="divider"></li>
62 <li id="copy_notebook"
62 <li id="copy_notebook"
63 title="Open a copy of this notebook's contents and start a new kernel">
63 title="Open a copy of this notebook's contents and start a new kernel">
64 <a href="#">Make a Copy...</a></li>
64 <a href="#">Make a Copy...</a></li>
65 <li id="rename_notebook"><a href="#">Rename...</a></li>
65 <li id="rename_notebook"><a href="#">Rename...</a></li>
66 <li id="save_checkpoint"><a href="#">Save and Checkpoint</a></li>
66 <li id="save_checkpoint"><a href="#">Save and Checkpoint</a></li>
67 <!-- <hr/> -->
67 <!-- <hr/> -->
68 <li class="divider"></li>
68 <li class="divider"></li>
69 <li id="restore_checkpoint" class="dropdown-submenu"><a href="#">Revert to Checkpoint</a>
69 <li id="restore_checkpoint" class="dropdown-submenu"><a href="#">Revert to Checkpoint</a>
70 <ul class="dropdown-menu">
70 <ul class="dropdown-menu">
71 <li><a href="#"></a></li>
71 <li><a href="#"></a></li>
72 <li><a href="#"></a></li>
72 <li><a href="#"></a></li>
73 <li><a href="#"></a></li>
73 <li><a href="#"></a></li>
74 <li><a href="#"></a></li>
74 <li><a href="#"></a></li>
75 <li><a href="#"></a></li>
75 <li><a href="#"></a></li>
76 </ul>
76 </ul>
77 </li>
77 </li>
78 <li class="divider"></li>
78 <li class="divider"></li>
79 <li id="print_preview"><a href="#">Print Preview</a></li>
79 <li id="print_preview"><a href="#">Print Preview</a></li>
80 <li class="dropdown-submenu"><a href="#">Download as</a>
80 <li class="dropdown-submenu"><a href="#">Download as</a>
81 <ul class="dropdown-menu">
81 <ul class="dropdown-menu">
82 <li id="download_ipynb"><a href="#">IPython Notebook (.ipynb)</a></li>
82 <li id="download_ipynb"><a href="#">IPython Notebook (.ipynb)</a></li>
83 <li id="download_py"><a href="#">Python (.py)</a></li>
83 <li id="download_py"><a href="#">Python (.py)</a></li>
84 <li id="download_html"><a href="#">HTML (.html)</a></li>
84 <li id="download_html"><a href="#">HTML (.html)</a></li>
85 <li id="download_rst"><a href="#">reST (.rst)</a></li>
85 <li id="download_rst"><a href="#">reST (.rst)</a></li>
86 </ul>
86 </ul>
87 </li>
87 </li>
88 <li class="divider"></li>
88 <li class="divider"></li>
89
89
90 <li id="kill_and_exit"
90 <li id="kill_and_exit"
91 title="Shutdown this notebook's kernel, and close this window">
91 title="Shutdown this notebook's kernel, and close this window">
92 <a href="#" >Close and halt</a></li>
92 <a href="#" >Close and halt</a></li>
93 </ul>
93 </ul>
94 </li>
94 </li>
95 <li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown">Edit</a>
95 <li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown">Edit</a>
96 <ul id="edit_menu" class="dropdown-menu">
96 <ul id="edit_menu" class="dropdown-menu">
97 <li id="cut_cell"><a href="#">Cut Cell</a></li>
97 <li id="cut_cell"><a href="#">Cut Cell</a></li>
98 <li id="copy_cell"><a href="#">Copy Cell</a></li>
98 <li id="copy_cell"><a href="#">Copy Cell</a></li>
99 <li id="paste_cell_above" class="disabled"><a href="#">Paste Cell Above</a></li>
99 <li id="paste_cell_above" class="disabled"><a href="#">Paste Cell Above</a></li>
100 <li id="paste_cell_below" class="disabled"><a href="#">Paste Cell Below</a></li>
100 <li id="paste_cell_below" class="disabled"><a href="#">Paste Cell Below</a></li>
101 <li id="paste_cell_replace" class="disabled"><a href="#">Paste Cell &amp; Replace</a></li>
101 <li id="paste_cell_replace" class="disabled"><a href="#">Paste Cell &amp; Replace</a></li>
102 <li id="delete_cell"><a href="#">Delete Cell</a></li>
102 <li id="delete_cell"><a href="#">Delete Cell</a></li>
103 <li id="undelete_cell" class="disabled"><a href="#">Undo Delete Cell</a></li>
103 <li id="undelete_cell" class="disabled"><a href="#">Undo Delete Cell</a></li>
104 <li class="divider"></li>
104 <li class="divider"></li>
105 <li id="split_cell"><a href="#">Split Cell</a></li>
105 <li id="split_cell"><a href="#">Split Cell</a></li>
106 <li id="merge_cell_above"><a href="#">Merge Cell Above</a></li>
106 <li id="merge_cell_above"><a href="#">Merge Cell Above</a></li>
107 <li id="merge_cell_below"><a href="#">Merge Cell Below</a></li>
107 <li id="merge_cell_below"><a href="#">Merge Cell Below</a></li>
108 <li class="divider"></li>
108 <li class="divider"></li>
109 <li id="move_cell_up"><a href="#">Move Cell Up</a></li>
109 <li id="move_cell_up"><a href="#">Move Cell Up</a></li>
110 <li id="move_cell_down"><a href="#">Move Cell Down</a></li>
110 <li id="move_cell_down"><a href="#">Move Cell Down</a></li>
111 <li class="divider"></li>
111 <li class="divider"></li>
112 <li id="edit_nb_metadata"><a href="#">Edit Notebook Metadata</a></li>
112 <li id="edit_nb_metadata"><a href="#">Edit Notebook Metadata</a></li>
113 </ul>
113 </ul>
114 </li>
114 </li>
115 <li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown">View</a>
115 <li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown">View</a>
116 <ul id="view_menu" class="dropdown-menu">
116 <ul id="view_menu" class="dropdown-menu">
117 <li id="toggle_header"
117 <li id="toggle_header"
118 title="Show/Hide the IPython Notebook logo and notebook title (above menu bar)">
118 title="Show/Hide the IPython Notebook logo and notebook title (above menu bar)">
119 <a href="#">Toggle Header</a></li>
119 <a href="#">Toggle Header</a></li>
120 <li id="toggle_toolbar"
120 <li id="toggle_toolbar"
121 title="Show/Hide the action icons (below menu bar)">
121 title="Show/Hide the action icons (below menu bar)">
122 <a href="#">Toggle Toolbar</a></li>
122 <a href="#">Toggle Toolbar</a></li>
123 </ul>
123 </ul>
124 </li>
124 </li>
125 <li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown">Insert</a>
125 <li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown">Insert</a>
126 <ul id="insert_menu" class="dropdown-menu">
126 <ul id="insert_menu" class="dropdown-menu">
127 <li id="insert_cell_above"
127 <li id="insert_cell_above"
128 title="Insert an empty Code cell above the currently active cell">
128 title="Insert an empty Code cell above the currently active cell">
129 <a href="#">Insert Cell Above</a></li>
129 <a href="#">Insert Cell Above</a></li>
130 <li id="insert_cell_below"
130 <li id="insert_cell_below"
131 title="Insert an empty Code cell below the currently active cell">
131 title="Insert an empty Code cell below the currently active cell">
132 <a href="#">Insert Cell Below</a></li>
132 <a href="#">Insert Cell Below</a></li>
133 </ul>
133 </ul>
134 </li>
134 </li>
135 <li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown">Cell</a>
135 <li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown">Cell</a>
136 <ul id="cell_menu" class="dropdown-menu">
136 <ul id="cell_menu" class="dropdown-menu">
137 <li id="run_cell" title="Run this cell, and move cursor to the next one">
137 <li id="run_cell" title="Run this cell, and move cursor to the next one">
138 <a href="#">Run</a></li>
138 <a href="#">Run</a></li>
139 <li id="run_cell_select_below" title="Run this cell, select below">
139 <li id="run_cell_select_below" title="Run this cell, select below">
140 <a href="#">Run and Select Below</a></li>
140 <a href="#">Run and Select Below</a></li>
141 <li id="run_cell_insert_below" title="Run this cell, insert below">
141 <li id="run_cell_insert_below" title="Run this cell, insert below">
142 <a href="#">Run and Insert Below</a></li>
142 <a href="#">Run and Insert Below</a></li>
143 <li id="run_all_cells" title="Run all cells in the notebook">
143 <li id="run_all_cells" title="Run all cells in the notebook">
144 <a href="#">Run All</a></li>
144 <a href="#">Run All</a></li>
145 <li id="run_all_cells_above" title="Run all cells above (but not including) this cell">
145 <li id="run_all_cells_above" title="Run all cells above (but not including) this cell">
146 <a href="#">Run All Above</a></li>
146 <a href="#">Run All Above</a></li>
147 <li id="run_all_cells_below" title="Run this cell and all cells below it">
147 <li id="run_all_cells_below" title="Run this cell and all cells below it">
148 <a href="#">Run All Below</a></li>
148 <a href="#">Run All Below</a></li>
149 <li class="divider"></li>
149 <li class="divider"></li>
150 <li id="change_cell_type" class="dropdown-submenu"
150 <li id="change_cell_type" class="dropdown-submenu"
151 title="All cells in the notebook have a cell type. By default, new cells are created as 'Code' cells">
151 title="All cells in the notebook have a cell type. By default, new cells are created as 'Code' cells">
152 <a href="#">Cell Type</a>
152 <a href="#">Cell Type</a>
153 <ul class="dropdown-menu">
153 <ul class="dropdown-menu">
154 <li id="to_code"
154 <li id="to_code"
155 title="Contents will be sent to the kernel for execution, and output will display in the footer of cell">
155 title="Contents will be sent to the kernel for execution, and output will display in the footer of cell">
156 <a href="#">Code</a></li>
156 <a href="#">Code</a></li>
157 <li id="to_markdown"
157 <li id="to_markdown"
158 title="Contents will be rendered as HTML and serve as explanatory text">
158 title="Contents will be rendered as HTML and serve as explanatory text">
159 <a href="#">Markdown</a></li>
159 <a href="#">Markdown</a></li>
160 <li id="to_raw"
160 <li id="to_raw"
161 title="Contents will pass through nbconvert unmodified">
161 title="Contents will pass through nbconvert unmodified">
162 <a href="#">Raw NBConvert</a></li>
162 <a href="#">Raw NBConvert</a></li>
163 <li id="to_heading1"><a href="#">Heading 1</a></li>
163 <li id="to_heading1"><a href="#">Heading 1</a></li>
164 <li id="to_heading2"><a href="#">Heading 2</a></li>
164 <li id="to_heading2"><a href="#">Heading 2</a></li>
165 <li id="to_heading3"><a href="#">Heading 3</a></li>
165 <li id="to_heading3"><a href="#">Heading 3</a></li>
166 <li id="to_heading4"><a href="#">Heading 4</a></li>
166 <li id="to_heading4"><a href="#">Heading 4</a></li>
167 <li id="to_heading5"><a href="#">Heading 5</a></li>
167 <li id="to_heading5"><a href="#">Heading 5</a></li>
168 <li id="to_heading6"><a href="#">Heading 6</a></li>
168 <li id="to_heading6"><a href="#">Heading 6</a></li>
169 </ul>
169 </ul>
170 </li>
170 </li>
171 <li class="divider"></li>
171 <li class="divider"></li>
172 <li id="current_outputs" class="dropdown-submenu"><a href="#">Current Output</a>
172 <li id="current_outputs" class="dropdown-submenu"><a href="#">Current Output</a>
173 <ul class="dropdown-menu">
173 <ul class="dropdown-menu">
174 <li id="toggle_current_output"
174 <li id="toggle_current_output"
175 title="Hide/Show the output of the current cell">
175 title="Hide/Show the output of the current cell">
176 <a href="#">Toggle</a>
176 <a href="#">Toggle</a>
177 </li>
177 </li>
178 <li id="toggle_current_output_scroll"
178 <li id="toggle_current_output_scroll"
179 title="Scroll the output of the current cell">
179 title="Scroll the output of the current cell">
180 <a href="#">Toggle Scrolling</a>
180 <a href="#">Toggle Scrolling</a>
181 </li>
181 </li>
182 <li id="clear_current_output"
182 <li id="clear_current_output"
183 title="Clear the output of the current cell">
183 title="Clear the output of the current cell">
184 <a href="#">Clear</a>
184 <a href="#">Clear</a>
185 </li>
185 </li>
186 </ul>
186 </ul>
187 </li>
187 </li>
188 <li id="all_outputs" class="dropdown-submenu"><a href="#">All Output</a>
188 <li id="all_outputs" class="dropdown-submenu"><a href="#">All Output</a>
189 <ul class="dropdown-menu">
189 <ul class="dropdown-menu">
190 <li id="toggle_all_output"
190 <li id="toggle_all_output"
191 title="Hide/Show the output of all cells">
191 title="Hide/Show the output of all cells">
192 <a href="#">Toggle</a>
192 <a href="#">Toggle</a>
193 </li>
193 </li>
194 <li id="toggle_all_output_scroll"
194 <li id="toggle_all_output_scroll"
195 title="Scroll the output of all cells">
195 title="Scroll the output of all cells">
196 <a href="#">Toggle Scrolling</a>
196 <a href="#">Toggle Scrolling</a>
197 </li>
197 </li>
198 <li id="clear_all_output"
198 <li id="clear_all_output"
199 title="Clear the output of all cells">
199 title="Clear the output of all cells">
200 <a href="#">Clear</a>
200 <a href="#">Clear</a>
201 </li>
201 </li>
202 </ul>
202 </ul>
203 </li>
203 </li>
204 </ul>
204 </ul>
205 </li>
205 </li>
206 <li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown">Kernel</a>
206 <li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown">Kernel</a>
207 <ul id="kernel_menu" class="dropdown-menu">
207 <ul id="kernel_menu" class="dropdown-menu">
208 <li id="int_kernel"
208 <li id="int_kernel"
209 title="Send KeyboardInterrupt (CTRL-C) to the Kernel">
209 title="Send KeyboardInterrupt (CTRL-C) to the Kernel">
210 <a href="#">Interrupt</a></li>
210 <a href="#">Interrupt</a></li>
211 <li id="restart_kernel"
211 <li id="restart_kernel"
212 title="Restart the Kernel">
212 title="Restart the Kernel">
213 <a href="#">Restart</a></li>
213 <a href="#">Restart</a></li>
214 </ul>
214 </ul>
215 </li>
215 </li>
216 <li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown">Help</a>
216 <li class="dropdown"><a href="#" class="dropdown-toggle" data-toggle="dropdown">Help</a>
217 <ul id="help_menu" class="dropdown-menu">
217 <ul id="help_menu" class="dropdown-menu">
218 <li id="keyboard_shortcuts" title="Opens a tooltip with all keyboard shortcuts"><a href="#">Keyboard Shortcuts</a></li>
218 <li id="keyboard_shortcuts" title="Opens a tooltip with all keyboard shortcuts"><a href="#">Keyboard Shortcuts</a></li>
219 <li class="divider"></li>
219 <li class="divider"></li>
220 {% set
220 {% set
221 sections = (
221 sections = (
222 (
222 (
223 ("http://ipython.org/documentation.html","IPython Help",True),
223 ("http://ipython.org/documentation.html","IPython Help",True),
224 ("http://nbviewer.ipython.org/github/ipython/ipython/tree/master/examples/notebooks/", "Notebook Examples", True),
224 ("http://nbviewer.ipython.org/github/ipython/ipython/tree/master/examples/notebooks/", "Notebook Examples", True),
225 ("http://ipython.org/ipython-doc/stable/interactive/notebook.html","Notebook Help",True),
225 ("http://ipython.org/ipython-doc/stable/interactive/notebook.html","Notebook Help",True),
226 ("http://ipython.org/ipython-doc/dev/interactive/cm_keyboard.html","Editor Shortcuts",True),
226 ("http://ipython.org/ipython-doc/dev/interactive/cm_keyboard.html","Editor Shortcuts",True),
227 ),(
227 ),(
228 ("http://docs.python.org","Python",True),
228 ("http://docs.python.org","Python",True),
229 ("http://docs.scipy.org/doc/numpy/reference/","NumPy",True),
229 ("http://docs.scipy.org/doc/numpy/reference/","NumPy",True),
230 ("http://docs.scipy.org/doc/scipy/reference/","SciPy",True),
230 ("http://docs.scipy.org/doc/scipy/reference/","SciPy",True),
231 ("http://matplotlib.org/contents.html","Matplotlib",True),
231 ("http://matplotlib.org/contents.html","Matplotlib",True),
232 ("http://docs.sympy.org/dev/index.html","SymPy",True),
232 ("http://docs.sympy.org/dev/index.html","SymPy",True),
233 ("http://pandas.pydata.org/pandas-docs/stable/","pandas", True)
233 ("http://pandas.pydata.org/pandas-docs/stable/","pandas", True)
234 )
234 )
235 )
235 )
236 %}
236 %}
237
237
238 {% for helplinks in sections %}
238 {% for helplinks in sections %}
239 {% for link in helplinks %}
239 {% for link in helplinks %}
240 <li><a href="{{link[0]}}" {{'target="_blank" title="Opens in a new window"' if link[2]}}>
240 <li><a href="{{link[0]}}" {{'target="_blank" title="Opens in a new window"' if link[2]}}>
241 {{'<i class="icon-external-link menu-icon pull-right"></i>' if link[2]}}
241 {{'<i class="icon-external-link menu-icon pull-right"></i>' if link[2]}}
242 {{link[1]}}
242 {{link[1]}}
243 </a></li>
243 </a></li>
244 {% endfor %}
244 {% endfor %}
245 {% if not loop.last %}
245 {% if not loop.last %}
246 <li class="divider"></li>
246 <li class="divider"></li>
247 {% endif %}
247 {% endif %}
248 {% endfor %}
248 {% endfor %}
249 </li>
249 </li>
250 </ul>
250 </ul>
251 </li>
251 </li>
252 </ul>
252 </ul>
253 <div id="kernel_indicator" class="indicator_area pull-right">
253 <div id="kernel_indicator" class="indicator_area pull-right">
254 <i id="kernel_indicator_icon"></i>
254 <i id="kernel_indicator_icon"></i>
255 </div>
255 </div>
256 <div id="modal_indicator" class="indicator_area pull-right">
256 <div id="modal_indicator" class="indicator_area pull-right">
257 <i id="modal_indicator_icon"></i>
257 <i id="modal_indicator_icon"></i>
258 </div>
258 </div>
259 <div id="notification_area"></div>
259 <div id="notification_area"></div>
260 </div>
260 </div>
261 </div>
261 </div>
262 </div>
262 </div>
263 </div>
263 </div>
264 <div id="maintoolbar" class="navbar">
264 <div id="maintoolbar" class="navbar">
265 <div class="toolbar-inner navbar-inner navbar-nobg">
265 <div class="toolbar-inner navbar-inner navbar-nobg">
266 <div id="maintoolbar-container" class="container"></div>
266 <div id="maintoolbar-container" class="container"></div>
267 </div>
267 </div>
268 </div>
268 </div>
269 </div>
269 </div>
270
270
271 <div id="ipython-main-app">
271 <div id="ipython-main-app">
272
272
273 <div id="notebook_panel">
273 <div id="notebook_panel">
274 <div id="notebook"></div>
274 <div id="notebook"></div>
275 <div id="pager_splitter"></div>
275 <div id="pager_splitter"></div>
276 <div id="pager">
276 <div id="pager">
277 <div id='pager_button_area'>
277 <div id='pager_button_area'>
278 </div>
278 </div>
279 <div id="pager-container" class="container"></div>
279 <div id="pager-container" class="container"></div>
280 </div>
280 </div>
281 </div>
281 </div>
282
282
283 </div>
283 </div>
284 <div id='tooltip' class='ipython_tooltip' style='display:none'></div>
284 <div id='tooltip' class='ipython_tooltip' style='display:none'></div>
285
285
286
286
287 {% endblock %}
287 {% endblock %}
288
288
289
289
290 {% block script %}
290 {% block script %}
291
291
292 {{super()}}
292 {{super()}}
293
293
294 <script src="{{ static_url("components/codemirror/lib/codemirror.js") }}" charset="utf-8"></script>
294 <script src="{{ static_url("components/codemirror/lib/codemirror.js") }}" charset="utf-8"></script>
295 <script type="text/javascript">
295 <script type="text/javascript">
296 CodeMirror.modeURL = "{{ static_url("components/codemirror/mode/%N/%N.js", include_version=False) }}";
296 CodeMirror.modeURL = "{{ static_url("components/codemirror/mode/%N/%N.js", include_version=False) }}";
297 </script>
297 </script>
298 <script src="{{ static_url("components/codemirror/addon/mode/loadmode.js") }}" charset="utf-8"></script>
298 <script src="{{ static_url("components/codemirror/addon/mode/loadmode.js") }}" charset="utf-8"></script>
299 <script src="{{ static_url("components/codemirror/addon/mode/multiplex.js") }}" charset="utf-8"></script>
299 <script src="{{ static_url("components/codemirror/addon/mode/multiplex.js") }}" charset="utf-8"></script>
300 <script src="{{ static_url("components/codemirror/addon/mode/overlay.js") }}" charset="utf-8"></script>
300 <script src="{{ static_url("components/codemirror/addon/mode/overlay.js") }}" charset="utf-8"></script>
301 <script src="{{ static_url("components/codemirror/addon/edit/matchbrackets.js") }}" charset="utf-8"></script>
301 <script src="{{ static_url("components/codemirror/addon/edit/matchbrackets.js") }}" charset="utf-8"></script>
302 <script src="{{ static_url("components/codemirror/addon/edit/closebrackets.js") }}" charset="utf-8"></script>
302 <script src="{{ static_url("components/codemirror/addon/edit/closebrackets.js") }}" charset="utf-8"></script>
303 <script src="{{ static_url("components/codemirror/addon/comment/comment.js") }}" charset="utf-8"></script>
303 <script src="{{ static_url("components/codemirror/addon/comment/comment.js") }}" charset="utf-8"></script>
304 <script src="{{ static_url("components/codemirror/mode/htmlmixed/htmlmixed.js") }}" charset="utf-8"></script>
304 <script src="{{ static_url("components/codemirror/mode/htmlmixed/htmlmixed.js") }}" charset="utf-8"></script>
305 <script src="{{ static_url("components/codemirror/mode/xml/xml.js") }}" charset="utf-8"></script>
305 <script src="{{ static_url("components/codemirror/mode/xml/xml.js") }}" charset="utf-8"></script>
306 <script src="{{ static_url("components/codemirror/mode/javascript/javascript.js") }}" charset="utf-8"></script>
306 <script src="{{ static_url("components/codemirror/mode/javascript/javascript.js") }}" charset="utf-8"></script>
307 <script src="{{ static_url("components/codemirror/mode/css/css.js") }}" charset="utf-8"></script>
307 <script src="{{ static_url("components/codemirror/mode/css/css.js") }}" charset="utf-8"></script>
308 <script src="{{ static_url("components/codemirror/mode/rst/rst.js") }}" charset="utf-8"></script>
308 <script src="{{ static_url("components/codemirror/mode/rst/rst.js") }}" charset="utf-8"></script>
309 <script src="{{ static_url("components/codemirror/mode/markdown/markdown.js") }}" charset="utf-8"></script>
309 <script src="{{ static_url("components/codemirror/mode/markdown/markdown.js") }}" charset="utf-8"></script>
310 <script src="{{ static_url("components/codemirror/mode/gfm/gfm.js") }}" charset="utf-8"></script>
310 <script src="{{ static_url("components/codemirror/mode/gfm/gfm.js") }}" charset="utf-8"></script>
311 <script src="{{ static_url("components/codemirror/mode/python/python.js") }}" charset="utf-8"></script>
311 <script src="{{ static_url("components/codemirror/mode/python/python.js") }}" charset="utf-8"></script>
312 <script src="{{ static_url("notebook/js/codemirror-ipython.js") }}" charset="utf-8"></script>
312 <script src="{{ static_url("notebook/js/codemirror-ipython.js") }}" charset="utf-8"></script>
313
313
314 <script src="{{ static_url("components/highlight.js/build/highlight.pack.js") }}" charset="utf-8"></script>
314 <script src="{{ static_url("components/highlight.js/build/highlight.pack.js") }}" charset="utf-8"></script>
315
315
316 <script src="{{ static_url("dateformat/date.format.js") }}" charset="utf-8"></script>
316 <script src="{{ static_url("dateformat/date.format.js") }}" charset="utf-8"></script>
317
317
318 <script src="{{ static_url("base/js/events.js") }}" type="text/javascript" charset="utf-8"></script>
318 <script src="{{ static_url("base/js/events.js") }}" type="text/javascript" charset="utf-8"></script>
319 <script src="{{ static_url("base/js/utils.js") }}" type="text/javascript" charset="utf-8"></script>
319 <script src="{{ static_url("base/js/utils.js") }}" type="text/javascript" charset="utf-8"></script>
320 <script src="{{ static_url("base/js/keyboard.js") }}" type="text/javascript" charset="utf-8"></script>
320 <script src="{{ static_url("base/js/keyboard.js") }}" type="text/javascript" charset="utf-8"></script>
321 <script src="{{ static_url("base/js/security.js") }}" type="text/javascript" charset="utf-8"></script>
321 <script src="{{ static_url("base/js/dialog.js") }}" type="text/javascript" charset="utf-8"></script>
322 <script src="{{ static_url("base/js/dialog.js") }}" type="text/javascript" charset="utf-8"></script>
322 <script src="{{ static_url("services/kernels/js/kernel.js") }}" type="text/javascript" charset="utf-8"></script>
323 <script src="{{ static_url("services/kernels/js/kernel.js") }}" type="text/javascript" charset="utf-8"></script>
323 <script src="{{ static_url("services/kernels/js/comm.js") }}" type="text/javascript" charset="utf-8"></script>
324 <script src="{{ static_url("services/kernels/js/comm.js") }}" type="text/javascript" charset="utf-8"></script>
324 <script src="{{ static_url("services/sessions/js/session.js") }}" type="text/javascript" charset="utf-8"></script>
325 <script src="{{ static_url("services/sessions/js/session.js") }}" type="text/javascript" charset="utf-8"></script>
325 <script src="{{ static_url("notebook/js/layoutmanager.js") }}" type="text/javascript" charset="utf-8"></script>
326 <script src="{{ static_url("notebook/js/layoutmanager.js") }}" type="text/javascript" charset="utf-8"></script>
326 <script src="{{ static_url("notebook/js/mathjaxutils.js") }}" type="text/javascript" charset="utf-8"></script>
327 <script src="{{ static_url("notebook/js/mathjaxutils.js") }}" type="text/javascript" charset="utf-8"></script>
327 <script src="{{ static_url("notebook/js/outputarea.js") }}" type="text/javascript" charset="utf-8"></script>
328 <script src="{{ static_url("notebook/js/outputarea.js") }}" type="text/javascript" charset="utf-8"></script>
328 <script src="{{ static_url("notebook/js/cell.js") }}" type="text/javascript" charset="utf-8"></script>
329 <script src="{{ static_url("notebook/js/cell.js") }}" type="text/javascript" charset="utf-8"></script>
329 <script src="{{ static_url("notebook/js/celltoolbar.js") }}" type="text/javascript" charset="utf-8"></script>
330 <script src="{{ static_url("notebook/js/celltoolbar.js") }}" type="text/javascript" charset="utf-8"></script>
330 <script src="{{ static_url("notebook/js/codecell.js") }}" type="text/javascript" charset="utf-8"></script>
331 <script src="{{ static_url("notebook/js/codecell.js") }}" type="text/javascript" charset="utf-8"></script>
331 <script src="{{ static_url("notebook/js/completer.js") }}" type="text/javascript" charset="utf-8"></script>
332 <script src="{{ static_url("notebook/js/completer.js") }}" type="text/javascript" charset="utf-8"></script>
332 <script src="{{ static_url("notebook/js/textcell.js") }}" type="text/javascript" charset="utf-8"></script>
333 <script src="{{ static_url("notebook/js/textcell.js") }}" type="text/javascript" charset="utf-8"></script>
333 <script src="{{ static_url("notebook/js/savewidget.js") }}" type="text/javascript" charset="utf-8"></script>
334 <script src="{{ static_url("notebook/js/savewidget.js") }}" type="text/javascript" charset="utf-8"></script>
334 <script src="{{ static_url("notebook/js/quickhelp.js") }}" type="text/javascript" charset="utf-8"></script>
335 <script src="{{ static_url("notebook/js/quickhelp.js") }}" type="text/javascript" charset="utf-8"></script>
335 <script src="{{ static_url("notebook/js/pager.js") }}" type="text/javascript" charset="utf-8"></script>
336 <script src="{{ static_url("notebook/js/pager.js") }}" type="text/javascript" charset="utf-8"></script>
336 <script src="{{ static_url("notebook/js/menubar.js") }}" type="text/javascript" charset="utf-8"></script>
337 <script src="{{ static_url("notebook/js/menubar.js") }}" type="text/javascript" charset="utf-8"></script>
337 <script src="{{ static_url("notebook/js/toolbar.js") }}" type="text/javascript" charset="utf-8"></script>
338 <script src="{{ static_url("notebook/js/toolbar.js") }}" type="text/javascript" charset="utf-8"></script>
338 <script src="{{ static_url("notebook/js/maintoolbar.js") }}" type="text/javascript" charset="utf-8"></script>
339 <script src="{{ static_url("notebook/js/maintoolbar.js") }}" type="text/javascript" charset="utf-8"></script>
339 <script src="{{ static_url("notebook/js/notebook.js") }}" type="text/javascript" charset="utf-8"></script>
340 <script src="{{ static_url("notebook/js/notebook.js") }}" type="text/javascript" charset="utf-8"></script>
340 <script src="{{ static_url("notebook/js/keyboardmanager.js") }}" type="text/javascript" charset="utf-8"></script>
341 <script src="{{ static_url("notebook/js/keyboardmanager.js") }}" type="text/javascript" charset="utf-8"></script>
341 <script src="{{ static_url("notebook/js/notificationwidget.js") }}" type="text/javascript" charset="utf-8"></script>
342 <script src="{{ static_url("notebook/js/notificationwidget.js") }}" type="text/javascript" charset="utf-8"></script>
342 <script src="{{ static_url("notebook/js/notificationarea.js") }}" type="text/javascript" charset="utf-8"></script>
343 <script src="{{ static_url("notebook/js/notificationarea.js") }}" type="text/javascript" charset="utf-8"></script>
343 <script src="{{ static_url("notebook/js/tooltip.js") }}" type="text/javascript" charset="utf-8"></script>
344 <script src="{{ static_url("notebook/js/tooltip.js") }}" type="text/javascript" charset="utf-8"></script>
344 <script src="{{ static_url("notebook/js/config.js") }}" type="text/javascript" charset="utf-8"></script>
345 <script src="{{ static_url("notebook/js/config.js") }}" type="text/javascript" charset="utf-8"></script>
345 <script src="{{ static_url("notebook/js/main.js") }}" type="text/javascript" charset="utf-8"></script>
346 <script src="{{ static_url("notebook/js/main.js") }}" type="text/javascript" charset="utf-8"></script>
346
347
347 <script src="{{ static_url("notebook/js/contexthint.js") }}" charset="utf-8"></script>
348 <script src="{{ static_url("notebook/js/contexthint.js") }}" charset="utf-8"></script>
348
349
349 <script src="{{ static_url("notebook/js/celltoolbarpresets/default.js") }}" type="text/javascript" charset="utf-8"></script>
350 <script src="{{ static_url("notebook/js/celltoolbarpresets/default.js") }}" type="text/javascript" charset="utf-8"></script>
350 <script src="{{ static_url("notebook/js/celltoolbarpresets/rawcell.js") }}" type="text/javascript" charset="utf-8"></script>
351 <script src="{{ static_url("notebook/js/celltoolbarpresets/rawcell.js") }}" type="text/javascript" charset="utf-8"></script>
351 <script src="{{ static_url("notebook/js/celltoolbarpresets/slideshow.js") }}" type="text/javascript" charset="utf-8"></script>
352 <script src="{{ static_url("notebook/js/celltoolbarpresets/slideshow.js") }}" type="text/javascript" charset="utf-8"></script>
352
353
353 {% endblock %}
354 {% endblock %}
General Comments 0
You need to be logged in to leave comments. Login now