##// END OF EJS Templates
various fixes in utils.js...
Min RK -
Show More
@@ -1,869 +1,829 b''
1 // Copyright (c) IPython Development Team.
1 // Copyright (c) IPython Development Team.
2 // Distributed under the terms of the Modified BSD License.
2 // Distributed under the terms of the Modified BSD License.
3
3
4 define([
4 define([
5 'base/js/namespace',
5 'base/js/namespace',
6 'jquery',
6 'jquery',
7 'codemirror/lib/codemirror',
7 'codemirror/lib/codemirror',
8 // silently upgrades CodeMirror
8 // silently upgrades CodeMirror
9 'codemirror/mode/meta',
9 'codemirror/mode/meta',
10 ], function(IPython, $, CodeMirror){
10 ], function(IPython, $, CodeMirror){
11 "use strict";
11 "use strict";
12
12
13 IPython.load_extensions = function () {
13 IPython.load_extensions = function () {
14 // load one or more IPython notebook extensions with requirejs
14 // load one or more IPython notebook extensions with requirejs
15
15
16 var extensions = [];
16 var extensions = [];
17 var extension_names = arguments;
17 var extension_names = arguments;
18 for (var i = 0; i < extension_names.length; i++) {
18 for (var i = 0; i < extension_names.length; i++) {
19 extensions.push("nbextensions/" + arguments[i]);
19 extensions.push("nbextensions/" + arguments[i]);
20 }
20 }
21
21
22 require(extensions,
22 require(extensions,
23 function () {
23 function () {
24 for (var i = 0; i < arguments.length; i++) {
24 for (var i = 0; i < arguments.length; i++) {
25 var ext = arguments[i];
25 var ext = arguments[i];
26 var ext_name = extension_names[i];
26 var ext_name = extension_names[i];
27 // success callback
27 // success callback
28 console.log("Loaded extension: " + ext_name);
28 console.log("Loaded extension: " + ext_name);
29 if (ext && ext.load_ipython_extension !== undefined) {
29 if (ext && ext.load_ipython_extension !== undefined) {
30 ext.load_ipython_extension();
30 ext.load_ipython_extension();
31 }
31 }
32 }
32 }
33 },
33 },
34 function (err) {
34 function (err) {
35 // failure callback
35 // failure callback
36 console.log("Failed to load extension(s):", err.requireModules, err);
36 console.log("Failed to load extension(s):", err.requireModules, err);
37 }
37 }
38 );
38 );
39 };
39 };
40
40
41 //============================================================================
41 //============================================================================
42 // Cross-browser RegEx Split
42 // Cross-browser RegEx Split
43 //============================================================================
43 //============================================================================
44
44
45 // This code has been MODIFIED from the code licensed below to not replace the
45 // This code has been MODIFIED from the code licensed below to not replace the
46 // default browser split. The license is reproduced here.
46 // default browser split. The license is reproduced here.
47
47
48 // see http://blog.stevenlevithan.com/archives/cross-browser-split for more info:
48 // see http://blog.stevenlevithan.com/archives/cross-browser-split for more info:
49 /*!
49 /*!
50 * Cross-Browser Split 1.1.1
50 * Cross-Browser Split 1.1.1
51 * Copyright 2007-2012 Steven Levithan <stevenlevithan.com>
51 * Copyright 2007-2012 Steven Levithan <stevenlevithan.com>
52 * Available under the MIT License
52 * Available under the MIT License
53 * ECMAScript compliant, uniform cross-browser split method
53 * ECMAScript compliant, uniform cross-browser split method
54 */
54 */
55
55
56 /**
56 /**
57 * Splits a string into an array of strings using a regex or string
57 * Splits a string into an array of strings using a regex or string
58 * separator. Matches of the separator are not included in the result array.
58 * separator. Matches of the separator are not included in the result array.
59 * However, if `separator` is a regex that contains capturing groups,
59 * However, if `separator` is a regex that contains capturing groups,
60 * backreferences are spliced into the result each time `separator` is
60 * backreferences are spliced into the result each time `separator` is
61 * matched. Fixes browser bugs compared to the native
61 * matched. Fixes browser bugs compared to the native
62 * `String.prototype.split` and can be used reliably cross-browser.
62 * `String.prototype.split` and can be used reliably cross-browser.
63 * @param {String} str String to split.
63 * @param {String} str String to split.
64 * @param {RegExp|String} separator Regex or string to use for separating
64 * @param {RegExp} separator Regex to use for separating
65 * the string.
65 * the string.
66 * @param {Number} [limit] Maximum number of items to include in the result
66 * @param {Number} [limit] Maximum number of items to include in the result
67 * array.
67 * array.
68 * @returns {Array} Array of substrings.
68 * @returns {Array} Array of substrings.
69 * @example
69 * @example
70 *
70 *
71 * // Basic use
71 * // Basic use
72 * regex_split('a b c d', ' ');
72 * regex_split('a b c d', ' ');
73 * // -> ['a', 'b', 'c', 'd']
73 * // -> ['a', 'b', 'c', 'd']
74 *
74 *
75 * // With limit
75 * // With limit
76 * regex_split('a b c d', ' ', 2);
76 * regex_split('a b c d', ' ', 2);
77 * // -> ['a', 'b']
77 * // -> ['a', 'b']
78 *
78 *
79 * // Backreferences in result array
79 * // Backreferences in result array
80 * regex_split('..word1 word2..', /([a-z]+)(\d+)/i);
80 * regex_split('..word1 word2..', /([a-z]+)(\d+)/i);
81 * // -> ['..', 'word', '1', ' ', 'word', '2', '..']
81 * // -> ['..', 'word', '1', ' ', 'word', '2', '..']
82 */
82 */
83 var regex_split = function (str, separator, limit) {
83 var regex_split = function (str, separator, limit) {
84 // If `separator` is not a regex, use `split`
85 if (Object.prototype.toString.call(separator) !== "[object RegExp]") {
86 return split.call(str, separator, limit);
87 }
88 var output = [],
84 var output = [],
89 flags = (separator.ignoreCase ? "i" : "") +
85 flags = (separator.ignoreCase ? "i" : "") +
90 (separator.multiline ? "m" : "") +
86 (separator.multiline ? "m" : "") +
91 (separator.extended ? "x" : "") + // Proposed for ES6
87 (separator.extended ? "x" : "") + // Proposed for ES6
92 (separator.sticky ? "y" : ""), // Firefox 3+
88 (separator.sticky ? "y" : ""), // Firefox 3+
93 lastLastIndex = 0,
89 lastLastIndex = 0,
94 // Make `global` and avoid `lastIndex` issues by working with a copy
95 separator = new RegExp(separator.source, flags + "g"),
96 separator2, match, lastIndex, lastLength;
90 separator2, match, lastIndex, lastLength;
97 str += ""; // Type-convert
91 // Make `global` and avoid `lastIndex` issues by working with a copy
92 separator = new RegExp(separator.source, flags + "g");
98
93
99 var compliantExecNpcg = typeof(/()??/.exec("")[1]) === "undefined";
94 var compliantExecNpcg = typeof(/()??/.exec("")[1]) === "undefined";
100 if (!compliantExecNpcg) {
95 if (!compliantExecNpcg) {
101 // Doesn't need flags gy, but they don't hurt
96 // Doesn't need flags gy, but they don't hurt
102 separator2 = new RegExp("^" + separator.source + "$(?!\\s)", flags);
97 separator2 = new RegExp("^" + separator.source + "$(?!\\s)", flags);
103 }
98 }
104 /* Values for `limit`, per the spec:
99 /* Values for `limit`, per the spec:
105 * If undefined: 4294967295 // Math.pow(2, 32) - 1
100 * If undefined: 4294967295 // Math.pow(2, 32) - 1
106 * If 0, Infinity, or NaN: 0
101 * If 0, Infinity, or NaN: 0
107 * If positive number: limit = Math.floor(limit); if (limit > 4294967295) limit -= 4294967296;
102 * If positive number: limit = Math.floor(limit); if (limit > 4294967295) limit -= 4294967296;
108 * If negative number: 4294967296 - Math.floor(Math.abs(limit))
103 * If negative number: 4294967296 - Math.floor(Math.abs(limit))
109 * If other: Type-convert, then use the above rules
104 * If other: Type-convert, then use the above rules
110 */
105 */
111 limit = typeof(limit) === "undefined" ?
106 limit = typeof(limit) === "undefined" ?
112 -1 >>> 0 : // Math.pow(2, 32) - 1
107 -1 >>> 0 : // Math.pow(2, 32) - 1
113 limit >>> 0; // ToUint32(limit)
108 limit >>> 0; // ToUint32(limit)
114 while (match = separator.exec(str)) {
109 for (match = separator.exec(str); match; match = separator.exec(str)) {
115 // `separator.lastIndex` is not reliable cross-browser
110 // `separator.lastIndex` is not reliable cross-browser
116 lastIndex = match.index + match[0].length;
111 lastIndex = match.index + match[0].length;
117 if (lastIndex > lastLastIndex) {
112 if (lastIndex > lastLastIndex) {
118 output.push(str.slice(lastLastIndex, match.index));
113 output.push(str.slice(lastLastIndex, match.index));
119 // Fix browsers whose `exec` methods don't consistently return `undefined` for
114 // Fix browsers whose `exec` methods don't consistently return `undefined` for
120 // nonparticipating capturing groups
115 // nonparticipating capturing groups
121 if (!compliantExecNpcg && match.length > 1) {
116 if (!compliantExecNpcg && match.length > 1) {
122 match[0].replace(separator2, function () {
117 match[0].replace(separator2, function () {
123 for (var i = 1; i < arguments.length - 2; i++) {
118 for (var i = 1; i < arguments.length - 2; i++) {
124 if (typeof(arguments[i]) === "undefined") {
119 if (typeof(arguments[i]) === "undefined") {
125 match[i] = undefined;
120 match[i] = undefined;
126 }
121 }
127 }
122 }
128 });
123 });
129 }
124 }
130 if (match.length > 1 && match.index < str.length) {
125 if (match.length > 1 && match.index < str.length) {
131 Array.prototype.push.apply(output, match.slice(1));
126 Array.prototype.push.apply(output, match.slice(1));
132 }
127 }
133 lastLength = match[0].length;
128 lastLength = match[0].length;
134 lastLastIndex = lastIndex;
129 lastLastIndex = lastIndex;
135 if (output.length >= limit) {
130 if (output.length >= limit) {
136 break;
131 break;
137 }
132 }
138 }
133 }
139 if (separator.lastIndex === match.index) {
134 if (separator.lastIndex === match.index) {
140 separator.lastIndex++; // Avoid an infinite loop
135 separator.lastIndex++; // Avoid an infinite loop
141 }
136 }
142 }
137 }
143 if (lastLastIndex === str.length) {
138 if (lastLastIndex === str.length) {
144 if (lastLength || !separator.test("")) {
139 if (lastLength || !separator.test("")) {
145 output.push("");
140 output.push("");
146 }
141 }
147 } else {
142 } else {
148 output.push(str.slice(lastLastIndex));
143 output.push(str.slice(lastLastIndex));
149 }
144 }
150 return output.length > limit ? output.slice(0, limit) : output;
145 return output.length > limit ? output.slice(0, limit) : output;
151 };
146 };
152
147
153 //============================================================================
148 //============================================================================
154 // End contributed Cross-browser RegEx Split
149 // End contributed Cross-browser RegEx Split
155 //============================================================================
150 //============================================================================
156
151
157
152
158 var uuid = function () {
153 var uuid = function () {
159 /**
154 /**
160 * http://www.ietf.org/rfc/rfc4122.txt
155 * http://www.ietf.org/rfc/rfc4122.txt
161 */
156 */
162 var s = [];
157 var s = [];
163 var hexDigits = "0123456789ABCDEF";
158 var hexDigits = "0123456789ABCDEF";
164 for (var i = 0; i < 32; i++) {
159 for (var i = 0; i < 32; i++) {
165 s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
160 s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
166 }
161 }
167 s[12] = "4"; // bits 12-15 of the time_hi_and_version field to 0010
162 s[12] = "4"; // bits 12-15 of the time_hi_and_version field to 0010
168 s[16] = hexDigits.substr((s[16] & 0x3) | 0x8, 1); // bits 6-7 of the clock_seq_hi_and_reserved to 01
163 s[16] = hexDigits.substr((s[16] & 0x3) | 0x8, 1); // bits 6-7 of the clock_seq_hi_and_reserved to 01
169
164
170 var uuid = s.join("");
165 var uuid = s.join("");
171 return uuid;
166 return uuid;
172 };
167 };
173
168
174
169
175 //Fix raw text to parse correctly in crazy XML
170 //Fix raw text to parse correctly in crazy XML
176 function xmlencode(string) {
171 function xmlencode(string) {
177 return string.replace(/\&/g,'&'+'amp;')
172 return string.replace(/\&/g,'&'+'amp;')
178 .replace(/</g,'&'+'lt;')
173 .replace(/</g,'&'+'lt;')
179 .replace(/>/g,'&'+'gt;')
174 .replace(/>/g,'&'+'gt;')
180 .replace(/\'/g,'&'+'apos;')
175 .replace(/\'/g,'&'+'apos;')
181 .replace(/\"/g,'&'+'quot;')
176 .replace(/\"/g,'&'+'quot;')
182 .replace(/`/g,'&'+'#96;');
177 .replace(/`/g,'&'+'#96;');
183 }
178 }
184
179
185
180
186 //Map from terminal commands to CSS classes
181 //Map from terminal commands to CSS classes
187 var ansi_colormap = {
182 var ansi_colormap = {
188 "01":"ansibold",
183 "01":"ansibold",
189
184
190 "30":"ansiblack",
185 "30":"ansiblack",
191 "31":"ansired",
186 "31":"ansired",
192 "32":"ansigreen",
187 "32":"ansigreen",
193 "33":"ansiyellow",
188 "33":"ansiyellow",
194 "34":"ansiblue",
189 "34":"ansiblue",
195 "35":"ansipurple",
190 "35":"ansipurple",
196 "36":"ansicyan",
191 "36":"ansicyan",
197 "37":"ansigray",
192 "37":"ansigray",
198
193
199 "40":"ansibgblack",
194 "40":"ansibgblack",
200 "41":"ansibgred",
195 "41":"ansibgred",
201 "42":"ansibggreen",
196 "42":"ansibggreen",
202 "43":"ansibgyellow",
197 "43":"ansibgyellow",
203 "44":"ansibgblue",
198 "44":"ansibgblue",
204 "45":"ansibgpurple",
199 "45":"ansibgpurple",
205 "46":"ansibgcyan",
200 "46":"ansibgcyan",
206 "47":"ansibggray"
201 "47":"ansibggray"
207 };
202 };
208
203
209 function _process_numbers(attrs, numbers) {
204 function _process_numbers(attrs, numbers) {
210 // process ansi escapes
205 // process ansi escapes
211 var n = numbers.shift();
206 var n = numbers.shift();
212 if (ansi_colormap[n]) {
207 if (ansi_colormap[n]) {
213 if ( ! attrs["class"] ) {
208 if ( ! attrs["class"] ) {
214 attrs["class"] = ansi_colormap[n];
209 attrs["class"] = ansi_colormap[n];
215 } else {
210 } else {
216 attrs["class"] += " " + ansi_colormap[n];
211 attrs["class"] += " " + ansi_colormap[n];
217 }
212 }
218 } else if (n == "38" || n == "48") {
213 } else if (n == "38" || n == "48") {
219 // VT100 256 color or 24 bit RGB
214 // VT100 256 color or 24 bit RGB
220 if (numbers.length < 2) {
215 if (numbers.length < 2) {
221 console.log("Not enough fields for VT100 color", numbers);
216 console.log("Not enough fields for VT100 color", numbers);
222 return;
217 return;
223 }
218 }
224
219
225 var index_or_rgb = numbers.shift();
220 var index_or_rgb = numbers.shift();
226 var r,g,b;
221 var r,g,b;
227 if (index_or_rgb == "5") {
222 if (index_or_rgb == "5") {
228 // 256 color
223 // 256 color
229 var idx = parseInt(numbers.shift());
224 var idx = parseInt(numbers.shift(), 10);
230 if (idx < 16) {
225 if (idx < 16) {
231 // indexed ANSI
226 // indexed ANSI
232 // ignore bright / non-bright distinction
227 // ignore bright / non-bright distinction
233 idx = idx % 8;
228 idx = idx % 8;
234 var ansiclass = ansi_colormap[n[0] + (idx % 8).toString()];
229 var ansiclass = ansi_colormap[n[0] + (idx % 8).toString()];
235 if ( ! attrs["class"] ) {
230 if ( ! attrs["class"] ) {
236 attrs["class"] = ansiclass;
231 attrs["class"] = ansiclass;
237 } else {
232 } else {
238 attrs["class"] += " " + ansiclass;
233 attrs["class"] += " " + ansiclass;
239 }
234 }
240 return;
235 return;
241 } else if (idx < 232) {
236 } else if (idx < 232) {
242 // 216 color 6x6x6 RGB
237 // 216 color 6x6x6 RGB
243 idx = idx - 16;
238 idx = idx - 16;
244 b = idx % 6;
239 b = idx % 6;
245 g = Math.floor(idx / 6) % 6;
240 g = Math.floor(idx / 6) % 6;
246 r = Math.floor(idx / 36) % 6;
241 r = Math.floor(idx / 36) % 6;
247 // convert to rgb
242 // convert to rgb
248 r = (r * 51);
243 r = (r * 51);
249 g = (g * 51);
244 g = (g * 51);
250 b = (b * 51);
245 b = (b * 51);
251 } else {
246 } else {
252 // grayscale
247 // grayscale
253 idx = idx - 231;
248 idx = idx - 231;
254 // it's 1-24 and should *not* include black or white,
249 // it's 1-24 and should *not* include black or white,
255 // so a 26 point scale
250 // so a 26 point scale
256 r = g = b = Math.floor(idx * 256 / 26);
251 r = g = b = Math.floor(idx * 256 / 26);
257 }
252 }
258 } else if (index_or_rgb == "2") {
253 } else if (index_or_rgb == "2") {
259 // Simple 24 bit RGB
254 // Simple 24 bit RGB
260 if (numbers.length > 3) {
255 if (numbers.length > 3) {
261 console.log("Not enough fields for RGB", numbers);
256 console.log("Not enough fields for RGB", numbers);
262 return;
257 return;
263 }
258 }
264 r = numbers.shift();
259 r = numbers.shift();
265 g = numbers.shift();
260 g = numbers.shift();
266 b = numbers.shift();
261 b = numbers.shift();
267 } else {
262 } else {
268 console.log("unrecognized control", numbers);
263 console.log("unrecognized control", numbers);
269 return;
264 return;
270 }
265 }
271 if (r !== undefined) {
266 if (r !== undefined) {
272 // apply the rgb color
267 // apply the rgb color
273 var line;
268 var line;
274 if (n == "38") {
269 if (n == "38") {
275 line = "color: ";
270 line = "color: ";
276 } else {
271 } else {
277 line = "background-color: ";
272 line = "background-color: ";
278 }
273 }
279 line = line + "rgb(" + r + "," + g + "," + b + ");";
274 line = line + "rgb(" + r + "," + g + "," + b + ");";
280 if ( !attrs.style ) {
275 if ( !attrs.style ) {
281 attrs.style = line;
276 attrs.style = line;
282 } else {
277 } else {
283 attrs.style += " " + line;
278 attrs.style += " " + line;
284 }
279 }
285 }
280 }
286 }
281 }
287 }
282 }
288
283
289 function ansispan(str) {
284 function ansispan(str) {
290 // ansispan function adapted from github.com/mmalecki/ansispan (MIT License)
285 // ansispan function adapted from github.com/mmalecki/ansispan (MIT License)
291 // regular ansi escapes (using the table above)
286 // regular ansi escapes (using the table above)
292 var is_open = false;
287 var is_open = false;
293 return str.replace(/\033\[(0?[01]|22|39)?([;\d]+)?m/g, function(match, prefix, pattern) {
288 return str.replace(/\033\[(0?[01]|22|39)?([;\d]+)?m/g, function(match, prefix, pattern) {
294 if (!pattern) {
289 if (!pattern) {
295 // [(01|22|39|)m close spans
290 // [(01|22|39|)m close spans
296 if (is_open) {
291 if (is_open) {
297 is_open = false;
292 is_open = false;
298 return "</span>";
293 return "</span>";
299 } else {
294 } else {
300 return "";
295 return "";
301 }
296 }
302 } else {
297 } else {
303 is_open = true;
298 is_open = true;
304
299
305 // consume sequence of color escapes
300 // consume sequence of color escapes
306 var numbers = pattern.match(/\d+/g);
301 var numbers = pattern.match(/\d+/g);
307 var attrs = {};
302 var attrs = {};
308 while (numbers.length > 0) {
303 while (numbers.length > 0) {
309 _process_numbers(attrs, numbers);
304 _process_numbers(attrs, numbers);
310 }
305 }
311
306
312 var span = "<span ";
307 var span = "<span ";
313 for (var attr in attrs) {
308 Object.keys(attrs).map(function (attr) {
314 var value = attrs[attr];
315 span = span + " " + attr + '="' + attrs[attr] + '"';
309 span = span + " " + attr + '="' + attrs[attr] + '"';
316 }
310 });
317 return span + ">";
311 return span + ">";
318 }
312 }
319 });
313 });
320 }
314 }
321
315
322 // Transform ANSI color escape codes into HTML <span> tags with css
316 // Transform ANSI color escape codes into HTML <span> tags with css
323 // classes listed in the above ansi_colormap object. The actual color used
317 // classes listed in the above ansi_colormap object. The actual color used
324 // are set in the css file.
318 // are set in the css file.
325 function fixConsole(txt) {
319 function fixConsole(txt) {
326 txt = xmlencode(txt);
320 txt = xmlencode(txt);
327 var re = /\033\[([\dA-Fa-f;]*?)m/;
328 var opened = false;
329 var cmds = [];
330 var opener = "";
331 var closer = "";
332
321
333 // Strip all ANSI codes that are not color related. Matches
322 // Strip all ANSI codes that are not color related. Matches
334 // all ANSI codes that do not end with "m".
323 // all ANSI codes that do not end with "m".
335 var ignored_re = /(?=(\033\[[\d;=]*[a-ln-zA-Z]{1}))\1(?!m)/g;
324 var ignored_re = /(?=(\033\[[\d;=]*[a-ln-zA-Z]{1}))\1(?!m)/g;
336 txt = txt.replace(ignored_re, "");
325 txt = txt.replace(ignored_re, "");
337
326
338 // color ansi codes
327 // color ansi codes
339 txt = ansispan(txt);
328 txt = ansispan(txt);
340 return txt;
329 return txt;
341 }
330 }
342
331
343 // Remove chunks that should be overridden by the effect of
332 // Remove chunks that should be overridden by the effect of
344 // carriage return characters
333 // carriage return characters
345 function fixCarriageReturn(txt) {
334 function fixCarriageReturn(txt) {
346 var tmp = txt;
335 var tmp = txt;
347 do {
336 do {
348 txt = tmp;
337 txt = tmp;
349 tmp = txt.replace(/\r+\n/gm, '\n'); // \r followed by \n --> newline
338 tmp = txt.replace(/\r+\n/gm, '\n'); // \r followed by \n --> newline
350 tmp = tmp.replace(/^.*\r+/gm, ''); // Other \r --> clear line
339 tmp = tmp.replace(/^.*\r+/gm, ''); // Other \r --> clear line
351 } while (tmp.length < txt.length);
340 } while (tmp.length < txt.length);
352 return txt;
341 return txt;
353 }
342 }
354
343
355 // Locate any URLs and convert them to a anchor tag
344 // Locate any URLs and convert them to a anchor tag
356 function autoLinkUrls(txt) {
345 function autoLinkUrls(txt) {
357 return txt.replace(/(^|\s)(https?|ftp)(:[^'">\s]+)/gi,
346 return txt.replace(/(^|\s)(https?|ftp)(:[^'">\s]+)/gi,
358 "$1<a target=\"_blank\" href=\"$2$3\">$2$3</a>");
347 "$1<a target=\"_blank\" href=\"$2$3\">$2$3</a>");
359 }
348 }
360
349
361 var points_to_pixels = function (points) {
350 var points_to_pixels = function (points) {
362 /**
351 /**
363 * A reasonably good way of converting between points and pixels.
352 * A reasonably good way of converting between points and pixels.
364 */
353 */
365 var test = $('<div style="display: none; width: 10000pt; padding:0; border:0;"></div>');
354 var test = $('<div style="display: none; width: 10000pt; padding:0; border:0;"></div>');
366 $(body).append(test);
355 $('body').append(test);
367 var pixel_per_point = test.width()/10000;
356 var pixel_per_point = test.width()/10000;
368 test.remove();
357 test.remove();
369 return Math.floor(points*pixel_per_point);
358 return Math.floor(points*pixel_per_point);
370 };
359 };
371
360
372 var always_new = function (constructor) {
361 var always_new = function (constructor) {
373 /**
362 /**
374 * wrapper around contructor to avoid requiring `var a = new constructor()`
363 * wrapper around contructor to avoid requiring `var a = new constructor()`
375 * useful for passing constructors as callbacks,
364 * useful for passing constructors as callbacks,
376 * not for programmer laziness.
365 * not for programmer laziness.
377 * from http://programmers.stackexchange.com/questions/118798
366 * from http://programmers.stackexchange.com/questions/118798
378 */
367 */
379 return function () {
368 return function () {
380 var obj = Object.create(constructor.prototype);
369 var obj = Object.create(constructor.prototype);
381 constructor.apply(obj, arguments);
370 constructor.apply(obj, arguments);
382 return obj;
371 return obj;
383 };
372 };
384 };
373 };
385
374
386 var url_path_join = function () {
375 var url_path_join = function () {
387 /**
376 /**
388 * join a sequence of url components with '/'
377 * join a sequence of url components with '/'
389 */
378 */
390 var url = '';
379 var url = '';
391 for (var i = 0; i < arguments.length; i++) {
380 for (var i = 0; i < arguments.length; i++) {
392 if (arguments[i] === '') {
381 if (arguments[i] === '') {
393 continue;
382 continue;
394 }
383 }
395 if (url.length > 0 && url[url.length-1] != '/') {
384 if (url.length > 0 && url[url.length-1] != '/') {
396 url = url + '/' + arguments[i];
385 url = url + '/' + arguments[i];
397 } else {
386 } else {
398 url = url + arguments[i];
387 url = url + arguments[i];
399 }
388 }
400 }
389 }
401 url = url.replace(/\/\/+/, '/');
390 url = url.replace(/\/\/+/, '/');
402 return url;
391 return url;
403 };
392 };
404
393
405 var url_path_split = function (path) {
394 var url_path_split = function (path) {
406 /**
395 /**
407 * Like os.path.split for URLs.
396 * Like os.path.split for URLs.
408 * Always returns two strings, the directory path and the base filename
397 * Always returns two strings, the directory path and the base filename
409 */
398 */
410
399
411 var idx = path.lastIndexOf('/');
400 var idx = path.lastIndexOf('/');
412 if (idx === -1) {
401 if (idx === -1) {
413 return ['', path];
402 return ['', path];
414 } else {
403 } else {
415 return [ path.slice(0, idx), path.slice(idx + 1) ];
404 return [ path.slice(0, idx), path.slice(idx + 1) ];
416 }
405 }
417 };
406 };
418
407
419 var parse_url = function (url) {
408 var parse_url = function (url) {
420 /**
409 /**
421 * an `a` element with an href allows attr-access to the parsed segments of a URL
410 * an `a` element with an href allows attr-access to the parsed segments of a URL
422 * a = parse_url("http://localhost:8888/path/name#hash")
411 * a = parse_url("http://localhost:8888/path/name#hash")
423 * a.protocol = "http:"
412 * a.protocol = "http:"
424 * a.host = "localhost:8888"
413 * a.host = "localhost:8888"
425 * a.hostname = "localhost"
414 * a.hostname = "localhost"
426 * a.port = 8888
415 * a.port = 8888
427 * a.pathname = "/path/name"
416 * a.pathname = "/path/name"
428 * a.hash = "#hash"
417 * a.hash = "#hash"
429 */
418 */
430 var a = document.createElement("a");
419 var a = document.createElement("a");
431 a.href = url;
420 a.href = url;
432 return a;
421 return a;
433 };
422 };
434
423
435 var encode_uri_components = function (uri) {
424 var encode_uri_components = function (uri) {
436 /**
425 /**
437 * encode just the components of a multi-segment uri,
426 * encode just the components of a multi-segment uri,
438 * leaving '/' separators
427 * leaving '/' separators
439 */
428 */
440 return uri.split('/').map(encodeURIComponent).join('/');
429 return uri.split('/').map(encodeURIComponent).join('/');
441 };
430 };
442
431
443 var url_join_encode = function () {
432 var url_join_encode = function () {
444 /**
433 /**
445 * join a sequence of url components with '/',
434 * join a sequence of url components with '/',
446 * encoding each component with encodeURIComponent
435 * encoding each component with encodeURIComponent
447 */
436 */
448 return encode_uri_components(url_path_join.apply(null, arguments));
437 return encode_uri_components(url_path_join.apply(null, arguments));
449 };
438 };
450
439
451
440
452 var splitext = function (filename) {
441 var splitext = function (filename) {
453 /**
442 /**
454 * mimic Python os.path.splitext
443 * mimic Python os.path.splitext
455 * Returns ['base', '.ext']
444 * Returns ['base', '.ext']
456 */
445 */
457 var idx = filename.lastIndexOf('.');
446 var idx = filename.lastIndexOf('.');
458 if (idx > 0) {
447 if (idx > 0) {
459 return [filename.slice(0, idx), filename.slice(idx)];
448 return [filename.slice(0, idx), filename.slice(idx)];
460 } else {
449 } else {
461 return [filename, ''];
450 return [filename, ''];
462 }
451 }
463 };
452 };
464
453
465
454
466 var escape_html = function (text) {
455 var escape_html = function (text) {
467 /**
456 /**
468 * escape text to HTML
457 * escape text to HTML
469 */
458 */
470 return $("<div/>").text(text).html();
459 return $("<div/>").text(text).html();
471 };
460 };
472
461
473
462
474 var get_body_data = function(key) {
463 var get_body_data = function(key) {
475 /**
464 /**
476 * get a url-encoded item from body.data and decode it
465 * get a url-encoded item from body.data and decode it
477 * we should never have any encoded URLs anywhere else in code
466 * we should never have any encoded URLs anywhere else in code
478 * until we are building an actual request
467 * until we are building an actual request
479 */
468 */
480 return decodeURIComponent($('body').data(key));
469 return decodeURIComponent($('body').data(key));
481 };
470 };
482
471
483 var to_absolute_cursor_pos = function (cm, cursor) {
472 var to_absolute_cursor_pos = function (cm, cursor) {
484 /**
473 /**
485 * get the absolute cursor position from CodeMirror's col, ch
474 * get the absolute cursor position from CodeMirror's col, ch
486 */
475 */
487 if (!cursor) {
476 if (!cursor) {
488 cursor = cm.getCursor();
477 cursor = cm.getCursor();
489 }
478 }
490 var cursor_pos = cursor.ch;
479 var cursor_pos = cursor.ch;
491 for (var i = 0; i < cursor.line; i++) {
480 for (var i = 0; i < cursor.line; i++) {
492 cursor_pos += cm.getLine(i).length + 1;
481 cursor_pos += cm.getLine(i).length + 1;
493 }
482 }
494 return cursor_pos;
483 return cursor_pos;
495 };
484 };
496
485
497 var from_absolute_cursor_pos = function (cm, cursor_pos) {
486 var from_absolute_cursor_pos = function (cm, cursor_pos) {
498 /**
487 /**
499 * turn absolute cursor postion into CodeMirror col, ch cursor
488 * turn absolute cursor postion into CodeMirror col, ch cursor
500 */
489 */
501 var i, line;
490 var i, line;
502 var offset = 0;
491 var offset = 0;
503 for (i = 0, line=cm.getLine(i); line !== undefined; i++, line=cm.getLine(i)) {
492 for (i = 0, line=cm.getLine(i); line !== undefined; i++, line=cm.getLine(i)) {
504 if (offset + line.length < cursor_pos) {
493 if (offset + line.length < cursor_pos) {
505 offset += line.length + 1;
494 offset += line.length + 1;
506 } else {
495 } else {
507 return {
496 return {
508 line : i,
497 line : i,
509 ch : cursor_pos - offset,
498 ch : cursor_pos - offset,
510 };
499 };
511 }
500 }
512 }
501 }
513 // reached end, return endpoint
502 // reached end, return endpoint
514 return {
503 return {
515 ch : line.length - 1,
504 ch : line.length - 1,
516 line : i - 1,
505 line : i - 1,
517 };
506 };
518 };
507 };
519
508
520 // http://stackoverflow.com/questions/2400935/browser-detection-in-javascript
509 // http://stackoverflow.com/questions/2400935/browser-detection-in-javascript
521 var browser = (function() {
510 var browser = (function() {
522 if (typeof navigator === 'undefined') {
511 if (typeof navigator === 'undefined') {
523 // navigator undefined in node
512 // navigator undefined in node
524 return 'None';
513 return 'None';
525 }
514 }
526 var N= navigator.appName, ua= navigator.userAgent, tem;
515 var N= navigator.appName, ua= navigator.userAgent, tem;
527 var M= ua.match(/(opera|chrome|safari|firefox|msie)\/?\s*(\.?\d+(\.\d+)*)/i);
516 var M= ua.match(/(opera|chrome|safari|firefox|msie)\/?\s*(\.?\d+(\.\d+)*)/i);
528 if (M && (tem= ua.match(/version\/([\.\d]+)/i)) !== null) M[2]= tem[1];
517 if (M && (tem= ua.match(/version\/([\.\d]+)/i)) !== null) M[2]= tem[1];
529 M= M? [M[1], M[2]]: [N, navigator.appVersion,'-?'];
518 M= M? [M[1], M[2]]: [N, navigator.appVersion,'-?'];
530 return M;
519 return M;
531 })();
520 })();
532
521
533 // http://stackoverflow.com/questions/11219582/how-to-detect-my-browser-version-and-operating-system-using-javascript
522 // http://stackoverflow.com/questions/11219582/how-to-detect-my-browser-version-and-operating-system-using-javascript
534 var platform = (function () {
523 var platform = (function () {
535 if (typeof navigator === 'undefined') {
524 if (typeof navigator === 'undefined') {
536 // navigator undefined in node
525 // navigator undefined in node
537 return 'None';
526 return 'None';
538 }
527 }
539 var OSName="None";
528 var OSName="None";
540 if (navigator.appVersion.indexOf("Win")!=-1) OSName="Windows";
529 if (navigator.appVersion.indexOf("Win")!=-1) OSName="Windows";
541 if (navigator.appVersion.indexOf("Mac")!=-1) OSName="MacOS";
530 if (navigator.appVersion.indexOf("Mac")!=-1) OSName="MacOS";
542 if (navigator.appVersion.indexOf("X11")!=-1) OSName="UNIX";
531 if (navigator.appVersion.indexOf("X11")!=-1) OSName="UNIX";
543 if (navigator.appVersion.indexOf("Linux")!=-1) OSName="Linux";
532 if (navigator.appVersion.indexOf("Linux")!=-1) OSName="Linux";
544 return OSName;
533 return OSName;
545 })();
534 })();
546
535
547 var get_url_param = function (name) {
536 var get_url_param = function (name) {
548 // get a URL parameter. I cannot believe we actually need this.
537 // get a URL parameter. I cannot believe we actually need this.
549 // Based on http://stackoverflow.com/a/25359264/938949
538 // Based on http://stackoverflow.com/a/25359264/938949
550 var match = new RegExp('[\?&]' + name + '=([^&]*)').exec(window.location.search);
539 var match = new RegExp('[?&]' + name + '=([^&]*)').exec(window.location.search);
551 if (match){
540 if (match){
552 return decodeURIComponent(match[1] || '');
541 return decodeURIComponent(match[1] || '');
553 }
542 }
554 };
543 };
555
544
556 var is_or_has = function (a, b) {
545 var is_or_has = function (a, b) {
557 /**
546 /**
558 * Is b a child of a or a itself?
547 * Is b a child of a or a itself?
559 */
548 */
560 return a.has(b).length !==0 || a.is(b);
549 return a.has(b).length !==0 || a.is(b);
561 };
550 };
562
551
563 var is_focused = function (e) {
552 var is_focused = function (e) {
564 /**
553 /**
565 * Is element e, or one of its children focused?
554 * Is element e, or one of its children focused?
566 */
555 */
567 e = $(e);
556 e = $(e);
568 var target = $(document.activeElement);
557 var target = $(document.activeElement);
569 if (target.length > 0) {
558 if (target.length > 0) {
570 if (is_or_has(e, target)) {
559 if (is_or_has(e, target)) {
571 return true;
560 return true;
572 } else {
561 } else {
573 return false;
562 return false;
574 }
563 }
575 } else {
564 } else {
576 return false;
565 return false;
577 }
566 }
578 };
567 };
579
568
580 var mergeopt = function(_class, options, overwrite){
569 var mergeopt = function(_class, options, overwrite){
581 options = options || {};
570 options = options || {};
582 overwrite = overwrite || {};
571 overwrite = overwrite || {};
583 return $.extend(true, {}, _class.options_default, options, overwrite);
572 return $.extend(true, {}, _class.options_default, options, overwrite);
584 };
573 };
585
574
586 var ajax_error_msg = function (jqXHR) {
575 var ajax_error_msg = function (jqXHR) {
587 /**
576 /**
588 * Return a JSON error message if there is one,
577 * Return a JSON error message if there is one,
589 * otherwise the basic HTTP status text.
578 * otherwise the basic HTTP status text.
590 */
579 */
591 if (jqXHR.responseJSON && jqXHR.responseJSON.traceback) {
580 if (jqXHR.responseJSON && jqXHR.responseJSON.traceback) {
592 return jqXHR.responseJSON.traceback;
581 return jqXHR.responseJSON.traceback;
593 } else if (jqXHR.responseJSON && jqXHR.responseJSON.message) {
582 } else if (jqXHR.responseJSON && jqXHR.responseJSON.message) {
594 return jqXHR.responseJSON.message;
583 return jqXHR.responseJSON.message;
595 } else {
584 } else {
596 return jqXHR.statusText;
585 return jqXHR.statusText;
597 }
586 }
598 };
587 };
599 var log_ajax_error = function (jqXHR, status, error) {
588 var log_ajax_error = function (jqXHR, status, error) {
600 /**
589 /**
601 * log ajax failures with informative messages
590 * log ajax failures with informative messages
602 */
591 */
603 var msg = "API request failed (" + jqXHR.status + "): ";
592 var msg = "API request failed (" + jqXHR.status + "): ";
604 console.log(jqXHR);
593 console.log(jqXHR);
605 msg += ajax_error_msg(jqXHR);
594 msg += ajax_error_msg(jqXHR);
606 console.log(msg);
595 console.log(msg);
607 };
596 };
608
597
609 var requireCodeMirrorMode = function (mode, callback, errback) {
598 var requireCodeMirrorMode = function (mode, callback, errback) {
610 /**
599 /**
611 * find a predefined mode or detect from CM metadata then
600 * find a predefined mode or detect from CM metadata then
612 * require and callback with the resolveable mode string: mime or
601 * require and callback with the resolveable mode string: mime or
613 * custom name
602 * custom name
614 */
603 */
615
604
616 var modename = (typeof mode == "string") ? mode :
605 var modename = (typeof mode == "string") ? mode :
617 mode.mode || mode.name;
606 mode.mode || mode.name;
618
607
619 // simplest, cheapest check by mode name: mode may also have config
608 // simplest, cheapest check by mode name: mode may also have config
620 if (CodeMirror.modes.hasOwnProperty(modename)) {
609 if (CodeMirror.modes.hasOwnProperty(modename)) {
621 // return the full mode object, if it has a name
610 // return the full mode object, if it has a name
622 callback(mode.name ? mode : modename);
611 callback(mode.name ? mode : modename);
623 return;
612 return;
624 }
613 }
625
614
626 // *somehow* get back a CM.modeInfo-like object that has .mode and
615 // *somehow* get back a CM.modeInfo-like object that has .mode and
627 // .mime
616 // .mime
628 var info = (mode && mode.mode && mode.mime && mode) ||
617 var info = (mode && mode.mode && mode.mime && mode) ||
629 CodeMirror.findModeByName(modename) ||
618 CodeMirror.findModeByName(modename) ||
630 CodeMirror.findModeByExtension(modename.split(".").slice(-1)) ||
619 CodeMirror.findModeByExtension(modename.split(".").slice(-1)) ||
631 CodeMirror.findModeByMIME(modename) ||
620 CodeMirror.findModeByMIME(modename) ||
632 {mode: modename, mime: modename};
621 {mode: modename, mime: modename};
633
622
634 require([
623 require([
635 // might want to use CodeMirror.modeURL here
624 // might want to use CodeMirror.modeURL here
636 ['codemirror/mode', info.mode, info.mode].join('/'),
625 ['codemirror/mode', info.mode, info.mode].join('/'),
637 ], function() {
626 ], function() {
638 // return the original mode, as from a kernelspec on first load
627 // return the original mode, as from a kernelspec on first load
639 // or the mimetype, as for most highlighting
628 // or the mimetype, as for most highlighting
640 callback(mode.name ? mode : info.mime);
629 callback(mode.name ? mode : info.mime);
641 }, errback
630 }, errback
642 );
631 );
643 };
632 };
644
633
645 /** Error type for wrapped XHR errors. */
634 /** Error type for wrapped XHR errors. */
646 var XHR_ERROR = 'XhrError';
635 var XHR_ERROR = 'XhrError';
647
636
648 /**
637 /**
649 * Wraps an AJAX error as an Error object.
638 * Wraps an AJAX error as an Error object.
650 */
639 */
651 var wrap_ajax_error = function (jqXHR, status, error) {
640 var wrap_ajax_error = function (jqXHR, status, error) {
652 var wrapped_error = new Error(ajax_error_msg(jqXHR));
641 var wrapped_error = new Error(ajax_error_msg(jqXHR));
653 wrapped_error.name = XHR_ERROR;
642 wrapped_error.name = XHR_ERROR;
654 // provide xhr response
643 // provide xhr response
655 wrapped_error.xhr = jqXHR;
644 wrapped_error.xhr = jqXHR;
656 wrapped_error.xhr_status = status;
645 wrapped_error.xhr_status = status;
657 wrapped_error.xhr_error = error;
646 wrapped_error.xhr_error = error;
658 return wrapped_error;
647 return wrapped_error;
659 };
648 };
660
649
661 var promising_ajax = function(url, settings) {
650 var promising_ajax = function(url, settings) {
662 /**
651 /**
663 * Like $.ajax, but returning an ES6 promise. success and error settings
652 * Like $.ajax, but returning an ES6 promise. success and error settings
664 * will be ignored.
653 * will be ignored.
665 */
654 */
666 settings = settings || {};
655 settings = settings || {};
667 return new Promise(function(resolve, reject) {
656 return new Promise(function(resolve, reject) {
668 settings.success = function(data, status, jqXHR) {
657 settings.success = function(data, status, jqXHR) {
669 resolve(data);
658 resolve(data);
670 };
659 };
671 settings.error = function(jqXHR, status, error) {
660 settings.error = function(jqXHR, status, error) {
672 log_ajax_error(jqXHR, status, error);
661 log_ajax_error(jqXHR, status, error);
673 reject(wrap_ajax_error(jqXHR, status, error));
662 reject(wrap_ajax_error(jqXHR, status, error));
674 };
663 };
675 $.ajax(url, settings);
664 $.ajax(url, settings);
676 });
665 });
677 };
666 };
678
667
679 var WrappedError = function(message, error){
668 var WrappedError = function(message, error){
680 /**
669 /**
681 * Wrappable Error class
670 * Wrappable Error class
682 *
671 *
683 * The Error class doesn't actually act on `this`. Instead it always
672 * The Error class doesn't actually act on `this`. Instead it always
684 * returns a new instance of Error. Here we capture that instance so we
673 * returns a new instance of Error. Here we capture that instance so we
685 * can apply it's properties to `this`.
674 * can apply it's properties to `this`.
686 */
675 */
687 var tmp = Error.apply(this, [message]);
676 var tmp = Error.apply(this, [message]);
688
677
689 // Copy the properties of the error over to this.
678 // Copy the properties of the error over to this.
690 var properties = Object.getOwnPropertyNames(tmp);
679 var properties = Object.getOwnPropertyNames(tmp);
691 for (var i = 0; i < properties.length; i++) {
680 for (var i = 0; i < properties.length; i++) {
692 this[properties[i]] = tmp[properties[i]];
681 this[properties[i]] = tmp[properties[i]];
693 }
682 }
694
683
695 // Keep a stack of the original error messages.
684 // Keep a stack of the original error messages.
696 if (error instanceof WrappedError) {
685 if (error instanceof WrappedError) {
697 this.error_stack = error.error_stack;
686 this.error_stack = error.error_stack;
698 } else {
687 } else {
699 this.error_stack = [error];
688 this.error_stack = [error];
700 }
689 }
701 this.error_stack.push(tmp);
690 this.error_stack.push(tmp);
702
691
703 return this;
692 return this;
704 };
693 };
705
694
706 WrappedError.prototype = Object.create(Error.prototype, {});
695 WrappedError.prototype = Object.create(Error.prototype, {});
707
696
708
697
709 var load_class = function(class_name, module_name, registry) {
698 var load_class = function(class_name, module_name, registry) {
710 /**
699 /**
711 * Tries to load a class
700 * Tries to load a class
712 *
701 *
713 * Tries to load a class from a module using require.js, if a module
702 * Tries to load a class from a module using require.js, if a module
714 * is specified, otherwise tries to load a class from the global
703 * is specified, otherwise tries to load a class from the global
715 * registry, if the global registry is provided.
704 * registry, if the global registry is provided.
716 */
705 */
717 return new Promise(function(resolve, reject) {
706 return new Promise(function(resolve, reject) {
718
707
719 // Try loading the view module using require.js
708 // Try loading the view module using require.js
720 if (module_name) {
709 if (module_name) {
721 require([module_name], function(module) {
710 require([module_name], function(module) {
722 if (module[class_name] === undefined) {
711 if (module[class_name] === undefined) {
723 reject(new Error('Class '+class_name+' not found in module '+module_name));
712 reject(new Error('Class '+class_name+' not found in module '+module_name));
724 } else {
713 } else {
725 resolve(module[class_name]);
714 resolve(module[class_name]);
726 }
715 }
727 }, reject);
716 }, reject);
728 } else {
717 } else {
729 if (registry && registry[class_name]) {
718 if (registry && registry[class_name]) {
730 resolve(registry[class_name]);
719 resolve(registry[class_name]);
731 } else {
720 } else {
732 reject(new Error('Class '+class_name+' not found in registry '));
721 reject(new Error('Class '+class_name+' not found in registry '));
733 }
722 }
734 }
723 }
735 });
724 });
736 };
725 };
737
726
738 var resolve_promises_dict = function(d) {
727 var resolve_promises_dict = function(d) {
739 /**
728 /**
740 * Resolve a promiseful dictionary.
729 * Resolve a promiseful dictionary.
741 * Returns a single Promise.
730 * Returns a single Promise.
742 */
731 */
743 var keys = Object.keys(d);
732 var keys = Object.keys(d);
744 var values = [];
733 var values = [];
745 keys.forEach(function(key) {
734 keys.forEach(function(key) {
746 values.push(d[key]);
735 values.push(d[key]);
747 });
736 });
748 return Promise.all(values).then(function(v) {
737 return Promise.all(values).then(function(v) {
749 d = {};
738 d = {};
750 for(var i=0; i<keys.length; i++) {
739 for(var i=0; i<keys.length; i++) {
751 d[keys[i]] = v[i];
740 d[keys[i]] = v[i];
752 }
741 }
753 return d;
742 return d;
754 });
743 });
755 };
744 };
756
745
757 var WrappedError = function(message, error){
758 /**
759 * Wrappable Error class
760 *
761 * The Error class doesn't actually act on `this`. Instead it always
762 * returns a new instance of Error. Here we capture that instance so we
763 * can apply it's properties to `this`.
764 */
765 var tmp = Error.apply(this, [message]);
766
767 // Copy the properties of the error over to this.
768 var properties = Object.getOwnPropertyNames(tmp);
769 for (var i = 0; i < properties.length; i++) {
770 this[properties[i]] = tmp[properties[i]];
771 }
772
773 // Keep a stack of the original error messages.
774 if (error instanceof WrappedError) {
775 this.error_stack = error.error_stack;
776 } else {
777 this.error_stack = [error];
778 }
779 this.error_stack.push(tmp);
780
781 return this;
782 };
783
784 WrappedError.prototype = Object.create(Error.prototype, {});
785
786 var reject = function(message, log) {
746 var reject = function(message, log) {
787 /**
747 /**
788 * Creates a wrappable Promise rejection function.
748 * Creates a wrappable Promise rejection function.
789 *
749 *
790 * Creates a function that returns a Promise.reject with a new WrappedError
750 * Creates a function that returns a Promise.reject with a new WrappedError
791 * that has the provided message and wraps the original error that
751 * that has the provided message and wraps the original error that
792 * caused the promise to reject.
752 * caused the promise to reject.
793 */
753 */
794 return function(error) {
754 return function(error) {
795 var wrapped_error = new WrappedError(message, error);
755 var wrapped_error = new WrappedError(message, error);
796 if (log) console.error(wrapped_error);
756 if (log) console.error(wrapped_error);
797 return Promise.reject(wrapped_error);
757 return Promise.reject(wrapped_error);
798 };
758 };
799 };
759 };
800
760
801 var typeset = function(element, text) {
761 var typeset = function(element, text) {
802 /**
762 /**
803 * Apply MathJax rendering to an element, and optionally set its text
763 * Apply MathJax rendering to an element, and optionally set its text
804 *
764 *
805 * If MathJax is not available, make no changes.
765 * If MathJax is not available, make no changes.
806 *
766 *
807 * Returns the output any number of typeset elements, or undefined if
767 * Returns the output any number of typeset elements, or undefined if
808 * MathJax was not available.
768 * MathJax was not available.
809 *
769 *
810 * Parameters
770 * Parameters
811 * ----------
771 * ----------
812 * element: Node, NodeList, or jQuery selection
772 * element: Node, NodeList, or jQuery selection
813 * text: option string
773 * text: option string
814 */
774 */
815 if(!window.MathJax){
775 if(!window.MathJax){
816 return;
776 return;
817 }
777 }
818 var $el = element.jquery ? element : $(element);
778 var $el = element.jquery ? element : $(element);
819 if(arguments.length > 1){
779 if(arguments.length > 1){
820 $el.text(text);
780 $el.text(text);
821 }
781 }
822 return $el.map(function(){
782 return $el.map(function(){
823 // MathJax takes a DOM node: $.map makes `this` the context
783 // MathJax takes a DOM node: $.map makes `this` the context
824 return MathJax.Hub.Queue(["Typeset", MathJax.Hub, this]);
784 return MathJax.Hub.Queue(["Typeset", MathJax.Hub, this]);
825 });
785 });
826 };
786 };
827
787
828 var utils = {
788 var utils = {
829 regex_split : regex_split,
789 regex_split : regex_split,
830 uuid : uuid,
790 uuid : uuid,
831 fixConsole : fixConsole,
791 fixConsole : fixConsole,
832 fixCarriageReturn : fixCarriageReturn,
792 fixCarriageReturn : fixCarriageReturn,
833 autoLinkUrls : autoLinkUrls,
793 autoLinkUrls : autoLinkUrls,
834 points_to_pixels : points_to_pixels,
794 points_to_pixels : points_to_pixels,
835 get_body_data : get_body_data,
795 get_body_data : get_body_data,
836 parse_url : parse_url,
796 parse_url : parse_url,
837 url_path_split : url_path_split,
797 url_path_split : url_path_split,
838 url_path_join : url_path_join,
798 url_path_join : url_path_join,
839 url_join_encode : url_join_encode,
799 url_join_encode : url_join_encode,
840 encode_uri_components : encode_uri_components,
800 encode_uri_components : encode_uri_components,
841 splitext : splitext,
801 splitext : splitext,
842 escape_html : escape_html,
802 escape_html : escape_html,
843 always_new : always_new,
803 always_new : always_new,
844 to_absolute_cursor_pos : to_absolute_cursor_pos,
804 to_absolute_cursor_pos : to_absolute_cursor_pos,
845 from_absolute_cursor_pos : from_absolute_cursor_pos,
805 from_absolute_cursor_pos : from_absolute_cursor_pos,
846 browser : browser,
806 browser : browser,
847 platform: platform,
807 platform: platform,
848 get_url_param: get_url_param,
808 get_url_param: get_url_param,
849 is_or_has : is_or_has,
809 is_or_has : is_or_has,
850 is_focused : is_focused,
810 is_focused : is_focused,
851 mergeopt: mergeopt,
811 mergeopt: mergeopt,
852 ajax_error_msg : ajax_error_msg,
812 ajax_error_msg : ajax_error_msg,
853 log_ajax_error : log_ajax_error,
813 log_ajax_error : log_ajax_error,
854 requireCodeMirrorMode : requireCodeMirrorMode,
814 requireCodeMirrorMode : requireCodeMirrorMode,
855 XHR_ERROR : XHR_ERROR,
815 XHR_ERROR : XHR_ERROR,
856 wrap_ajax_error : wrap_ajax_error,
816 wrap_ajax_error : wrap_ajax_error,
857 promising_ajax : promising_ajax,
817 promising_ajax : promising_ajax,
858 WrappedError: WrappedError,
818 WrappedError: WrappedError,
859 load_class: load_class,
819 load_class: load_class,
860 resolve_promises_dict: resolve_promises_dict,
820 resolve_promises_dict: resolve_promises_dict,
861 reject: reject,
821 reject: reject,
862 typeset: typeset,
822 typeset: typeset,
863 };
823 };
864
824
865 // Backwards compatability.
825 // Backwards compatability.
866 IPython.utils = utils;
826 IPython.utils = utils;
867
827
868 return utils;
828 return utils;
869 });
829 });
General Comments 0
You need to be logged in to leave comments. Login now