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