##// END OF EJS Templates
fix regular expression for detecting links in stdout...
MinRK -
Show More
@@ -1,558 +1,557 b''
1 //----------------------------------------------------------------------------
1 //----------------------------------------------------------------------------
2 // Copyright (C) 2008-2011 The IPython Development Team
2 // Copyright (C) 2008-2011 The IPython Development Team
3 //
3 //
4 // Distributed under the terms of the BSD License. The full license is in
4 // Distributed under the terms of the BSD License. The full license is in
5 // the file COPYING, distributed as part of this software.
5 // the file COPYING, distributed as part of this software.
6 //----------------------------------------------------------------------------
6 //----------------------------------------------------------------------------
7
7
8 //============================================================================
8 //============================================================================
9 // OutputArea
9 // OutputArea
10 //============================================================================
10 //============================================================================
11
11
12 var IPython = (function (IPython) {
12 var IPython = (function (IPython) {
13 "use strict";
13 "use strict";
14
14
15 var utils = IPython.utils;
15 var utils = IPython.utils;
16
16
17 var OutputArea = function (selector, prompt_area) {
17 var OutputArea = function (selector, prompt_area) {
18 this.selector = selector;
18 this.selector = selector;
19 this.wrapper = $(selector);
19 this.wrapper = $(selector);
20 this.outputs = [];
20 this.outputs = [];
21 this.collapsed = false;
21 this.collapsed = false;
22 this.scrolled = false;
22 this.scrolled = false;
23 this.clear_out_timeout = null;
23 this.clear_out_timeout = null;
24 if (prompt_area === undefined) {
24 if (prompt_area === undefined) {
25 this.prompt_area = true;
25 this.prompt_area = true;
26 } else {
26 } else {
27 this.prompt_area = prompt_area;
27 this.prompt_area = prompt_area;
28 }
28 }
29 this.create_elements();
29 this.create_elements();
30 this.style();
30 this.style();
31 this.bind_events();
31 this.bind_events();
32 };
32 };
33
33
34 OutputArea.prototype.create_elements = function () {
34 OutputArea.prototype.create_elements = function () {
35 this.element = $("<div/>");
35 this.element = $("<div/>");
36 this.collapse_button = $("<div/>");
36 this.collapse_button = $("<div/>");
37 this.prompt_overlay = $("<div/>");
37 this.prompt_overlay = $("<div/>");
38 this.wrapper.append(this.prompt_overlay);
38 this.wrapper.append(this.prompt_overlay);
39 this.wrapper.append(this.element);
39 this.wrapper.append(this.element);
40 this.wrapper.append(this.collapse_button);
40 this.wrapper.append(this.collapse_button);
41 };
41 };
42
42
43
43
44 OutputArea.prototype.style = function () {
44 OutputArea.prototype.style = function () {
45 this.collapse_button.hide();
45 this.collapse_button.hide();
46 this.prompt_overlay.hide();
46 this.prompt_overlay.hide();
47
47
48 this.wrapper.addClass('output_wrapper');
48 this.wrapper.addClass('output_wrapper');
49 this.element.addClass('output vbox');
49 this.element.addClass('output vbox');
50
50
51 this.collapse_button.button();
51 this.collapse_button.button();
52 this.collapse_button.addClass('output_collapsed vbox');
52 this.collapse_button.addClass('output_collapsed vbox');
53 this.collapse_button.attr('title', 'click to expand output');
53 this.collapse_button.attr('title', 'click to expand output');
54 this.collapse_button.html('. . .');
54 this.collapse_button.html('. . .');
55
55
56 this.prompt_overlay.addClass('out_prompt_overlay prompt');
56 this.prompt_overlay.addClass('out_prompt_overlay prompt');
57 this.prompt_overlay.attr('title', 'click to expand output; double click to hide output');
57 this.prompt_overlay.attr('title', 'click to expand output; double click to hide output');
58
58
59 this.collapse();
59 this.collapse();
60 };
60 };
61
61
62
62
63 OutputArea.prototype._should_scroll = function (lines) {
63 OutputArea.prototype._should_scroll = function (lines) {
64 if (!lines) {
64 if (!lines) {
65 lines = 100;
65 lines = 100;
66 }
66 }
67 // line-height from http://stackoverflow.com/questions/1185151
67 // line-height from http://stackoverflow.com/questions/1185151
68 var fontSize = this.element.css('font-size');
68 var fontSize = this.element.css('font-size');
69 var lineHeight = Math.floor(parseInt(fontSize.replace('px','')) * 1.5);
69 var lineHeight = Math.floor(parseInt(fontSize.replace('px','')) * 1.5);
70
70
71 return (this.element.height() > lines * lineHeight);
71 return (this.element.height() > lines * lineHeight);
72 };
72 };
73
73
74
74
75 OutputArea.prototype.bind_events = function () {
75 OutputArea.prototype.bind_events = function () {
76 var that = this;
76 var that = this;
77 this.prompt_overlay.dblclick(function () { that.toggle_output(); });
77 this.prompt_overlay.dblclick(function () { that.toggle_output(); });
78 this.prompt_overlay.click(function () { that.toggle_scroll(); });
78 this.prompt_overlay.click(function () { that.toggle_scroll(); });
79
79
80 this.element.resize(function () {
80 this.element.resize(function () {
81 // FIXME: Firefox on Linux misbehaves, so automatic scrolling is disabled
81 // FIXME: Firefox on Linux misbehaves, so automatic scrolling is disabled
82 if ( IPython.utils.browser[0] === "Firefox" ) {
82 if ( IPython.utils.browser[0] === "Firefox" ) {
83 return;
83 return;
84 }
84 }
85 // maybe scroll output,
85 // maybe scroll output,
86 // if it's grown large enough and hasn't already been scrolled.
86 // if it's grown large enough and hasn't already been scrolled.
87 if ( !that.scrolled && that._should_scroll()) {
87 if ( !that.scrolled && that._should_scroll()) {
88 that.scroll_area();
88 that.scroll_area();
89 }
89 }
90 });
90 });
91 this.collapse_button.click(function () {
91 this.collapse_button.click(function () {
92 that.expand();
92 that.expand();
93 });
93 });
94 this.collapse_button.hover(function () {
94 this.collapse_button.hover(function () {
95 $(this).addClass("ui-state-hover");
95 $(this).addClass("ui-state-hover");
96 }, function () {
96 }, function () {
97 $(this).removeClass("ui-state-hover");
97 $(this).removeClass("ui-state-hover");
98 });
98 });
99 };
99 };
100
100
101
101
102 OutputArea.prototype.collapse = function () {
102 OutputArea.prototype.collapse = function () {
103 if (!this.collapsed) {
103 if (!this.collapsed) {
104 this.element.hide();
104 this.element.hide();
105 this.prompt_overlay.hide();
105 this.prompt_overlay.hide();
106 if (this.element.html()){
106 if (this.element.html()){
107 this.collapse_button.show();
107 this.collapse_button.show();
108 }
108 }
109 this.collapsed = true;
109 this.collapsed = true;
110 }
110 }
111 };
111 };
112
112
113
113
114 OutputArea.prototype.expand = function () {
114 OutputArea.prototype.expand = function () {
115 if (this.collapsed) {
115 if (this.collapsed) {
116 this.collapse_button.hide();
116 this.collapse_button.hide();
117 this.element.show();
117 this.element.show();
118 this.prompt_overlay.show();
118 this.prompt_overlay.show();
119 this.collapsed = false;
119 this.collapsed = false;
120 }
120 }
121 };
121 };
122
122
123
123
124 OutputArea.prototype.toggle_output = function () {
124 OutputArea.prototype.toggle_output = function () {
125 if (this.collapsed) {
125 if (this.collapsed) {
126 this.expand();
126 this.expand();
127 } else {
127 } else {
128 this.collapse();
128 this.collapse();
129 }
129 }
130 };
130 };
131
131
132
132
133 OutputArea.prototype.scroll_area = function () {
133 OutputArea.prototype.scroll_area = function () {
134 this.element.addClass('output_scroll');
134 this.element.addClass('output_scroll');
135 this.prompt_overlay.attr('title', 'click to unscroll output; double click to hide');
135 this.prompt_overlay.attr('title', 'click to unscroll output; double click to hide');
136 this.scrolled = true;
136 this.scrolled = true;
137 };
137 };
138
138
139
139
140 OutputArea.prototype.unscroll_area = function () {
140 OutputArea.prototype.unscroll_area = function () {
141 this.element.removeClass('output_scroll');
141 this.element.removeClass('output_scroll');
142 this.prompt_overlay.attr('title', 'click to scroll output; double click to hide');
142 this.prompt_overlay.attr('title', 'click to scroll output; double click to hide');
143 this.scrolled = false;
143 this.scrolled = false;
144 };
144 };
145
145
146
146
147 OutputArea.prototype.scroll_if_long = function (lines) {
147 OutputArea.prototype.scroll_if_long = function (lines) {
148 if (this._should_scroll(lines)) {
148 if (this._should_scroll(lines)) {
149 // only allow scrolling long-enough output
149 // only allow scrolling long-enough output
150 this.scroll_area();
150 this.scroll_area();
151 }
151 }
152 };
152 };
153
153
154
154
155 OutputArea.prototype.toggle_scroll = function () {
155 OutputArea.prototype.toggle_scroll = function () {
156 if (this.scrolled) {
156 if (this.scrolled) {
157 this.unscroll_area();
157 this.unscroll_area();
158 } else {
158 } else {
159 // only allow scrolling long-enough output
159 // only allow scrolling long-enough output
160 this.scroll_if_long(20);
160 this.scroll_if_long(20);
161 }
161 }
162 };
162 };
163
163
164
164
165 // typeset with MathJax if MathJax is available
165 // typeset with MathJax if MathJax is available
166 OutputArea.prototype.typeset = function () {
166 OutputArea.prototype.typeset = function () {
167 if (window.MathJax){
167 if (window.MathJax){
168 MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
168 MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
169 }
169 }
170 };
170 };
171
171
172
172
173 OutputArea.prototype.handle_output = function (msg_type, content) {
173 OutputArea.prototype.handle_output = function (msg_type, content) {
174 var json = {};
174 var json = {};
175 json.output_type = msg_type;
175 json.output_type = msg_type;
176 if (msg_type === "stream") {
176 if (msg_type === "stream") {
177 json.text = content.data;
177 json.text = content.data;
178 json.stream = content.name;
178 json.stream = content.name;
179 } else if (msg_type === "display_data") {
179 } else if (msg_type === "display_data") {
180 json = this.convert_mime_types(json, content.data);
180 json = this.convert_mime_types(json, content.data);
181 } else if (msg_type === "pyout") {
181 } else if (msg_type === "pyout") {
182 json.prompt_number = content.execution_count;
182 json.prompt_number = content.execution_count;
183 json = this.convert_mime_types(json, content.data);
183 json = this.convert_mime_types(json, content.data);
184 } else if (msg_type === "pyerr") {
184 } else if (msg_type === "pyerr") {
185 json.ename = content.ename;
185 json.ename = content.ename;
186 json.evalue = content.evalue;
186 json.evalue = content.evalue;
187 json.traceback = content.traceback;
187 json.traceback = content.traceback;
188 }
188 }
189 // append with dynamic=true
189 // append with dynamic=true
190 this.append_output(json, true);
190 this.append_output(json, true);
191 };
191 };
192
192
193
193
194 OutputArea.prototype.convert_mime_types = function (json, data) {
194 OutputArea.prototype.convert_mime_types = function (json, data) {
195 if (data['text/plain'] !== undefined) {
195 if (data['text/plain'] !== undefined) {
196 json.text = data['text/plain'];
196 json.text = data['text/plain'];
197 }
197 }
198 if (data['text/html'] !== undefined) {
198 if (data['text/html'] !== undefined) {
199 json.html = data['text/html'];
199 json.html = data['text/html'];
200 }
200 }
201 if (data['image/svg+xml'] !== undefined) {
201 if (data['image/svg+xml'] !== undefined) {
202 json.svg = data['image/svg+xml'];
202 json.svg = data['image/svg+xml'];
203 }
203 }
204 if (data['image/png'] !== undefined) {
204 if (data['image/png'] !== undefined) {
205 json.png = data['image/png'];
205 json.png = data['image/png'];
206 }
206 }
207 if (data['image/jpeg'] !== undefined) {
207 if (data['image/jpeg'] !== undefined) {
208 json.jpeg = data['image/jpeg'];
208 json.jpeg = data['image/jpeg'];
209 }
209 }
210 if (data['text/latex'] !== undefined) {
210 if (data['text/latex'] !== undefined) {
211 json.latex = data['text/latex'];
211 json.latex = data['text/latex'];
212 }
212 }
213 if (data['application/json'] !== undefined) {
213 if (data['application/json'] !== undefined) {
214 json.json = data['application/json'];
214 json.json = data['application/json'];
215 }
215 }
216 if (data['application/javascript'] !== undefined) {
216 if (data['application/javascript'] !== undefined) {
217 json.javascript = data['application/javascript'];
217 json.javascript = data['application/javascript'];
218 }
218 }
219 return json;
219 return json;
220 };
220 };
221
221
222
222
223 OutputArea.prototype.append_output = function (json, dynamic) {
223 OutputArea.prototype.append_output = function (json, dynamic) {
224 // If dynamic is true, javascript output will be eval'd.
224 // If dynamic is true, javascript output will be eval'd.
225 this.expand();
225 this.expand();
226 this.flush_clear_timeout();
226 this.flush_clear_timeout();
227 if (json.output_type === 'pyout') {
227 if (json.output_type === 'pyout') {
228 this.append_pyout(json, dynamic);
228 this.append_pyout(json, dynamic);
229 } else if (json.output_type === 'pyerr') {
229 } else if (json.output_type === 'pyerr') {
230 this.append_pyerr(json);
230 this.append_pyerr(json);
231 } else if (json.output_type === 'display_data') {
231 } else if (json.output_type === 'display_data') {
232 this.append_display_data(json, dynamic);
232 this.append_display_data(json, dynamic);
233 } else if (json.output_type === 'stream') {
233 } else if (json.output_type === 'stream') {
234 this.append_stream(json);
234 this.append_stream(json);
235 }
235 }
236 this.outputs.push(json);
236 this.outputs.push(json);
237 var that = this;
237 var that = this;
238 setTimeout(function(){that.element.trigger('resize');}, 100);
238 setTimeout(function(){that.element.trigger('resize');}, 100);
239 };
239 };
240
240
241
241
242 OutputArea.prototype.create_output_area = function () {
242 OutputArea.prototype.create_output_area = function () {
243 var oa = $("<div/>").addClass("hbox output_area");
243 var oa = $("<div/>").addClass("hbox output_area");
244 if (this.prompt_area) {
244 if (this.prompt_area) {
245 oa.append($('<div/>').addClass('prompt'));
245 oa.append($('<div/>').addClass('prompt'));
246 }
246 }
247 return oa;
247 return oa;
248 };
248 };
249
249
250
250
251 OutputArea.prototype.append_pyout = function (json, dynamic) {
251 OutputArea.prototype.append_pyout = function (json, dynamic) {
252 var n = json.prompt_number || ' ';
252 var n = json.prompt_number || ' ';
253 var toinsert = this.create_output_area();
253 var toinsert = this.create_output_area();
254 if (this.prompt_area) {
254 if (this.prompt_area) {
255 toinsert.find('div.prompt').addClass('output_prompt').html('Out[' + n + ']:');
255 toinsert.find('div.prompt').addClass('output_prompt').html('Out[' + n + ']:');
256 }
256 }
257 this.append_mime_type(json, toinsert, dynamic);
257 this.append_mime_type(json, toinsert, dynamic);
258 this.element.append(toinsert);
258 this.element.append(toinsert);
259 // If we just output latex, typeset it.
259 // If we just output latex, typeset it.
260 if ((json.latex !== undefined) || (json.html !== undefined)) {
260 if ((json.latex !== undefined) || (json.html !== undefined)) {
261 this.typeset();
261 this.typeset();
262 }
262 }
263 };
263 };
264
264
265
265
266 OutputArea.prototype.append_pyerr = function (json) {
266 OutputArea.prototype.append_pyerr = function (json) {
267 var tb = json.traceback;
267 var tb = json.traceback;
268 if (tb !== undefined && tb.length > 0) {
268 if (tb !== undefined && tb.length > 0) {
269 var s = '';
269 var s = '';
270 var len = tb.length;
270 var len = tb.length;
271 for (var i=0; i<len; i++) {
271 for (var i=0; i<len; i++) {
272 s = s + tb[i] + '\n';
272 s = s + tb[i] + '\n';
273 }
273 }
274 s = s + '\n';
274 s = s + '\n';
275 var toinsert = this.create_output_area();
275 var toinsert = this.create_output_area();
276 this.append_text(s, toinsert);
276 this.append_text(s, toinsert);
277 this.element.append(toinsert);
277 this.element.append(toinsert);
278 }
278 }
279 };
279 };
280
280
281
281
282 OutputArea.prototype.append_stream = function (json) {
282 OutputArea.prototype.append_stream = function (json) {
283 // temporary fix: if stream undefined (json file written prior to this patch),
283 // temporary fix: if stream undefined (json file written prior to this patch),
284 // default to most likely stdout:
284 // default to most likely stdout:
285 if (json.stream == undefined){
285 if (json.stream == undefined){
286 json.stream = 'stdout';
286 json.stream = 'stdout';
287 }
287 }
288 var text = json.text;
288 var text = json.text;
289 var subclass = "output_"+json.stream;
289 var subclass = "output_"+json.stream;
290 if (this.outputs.length > 0){
290 if (this.outputs.length > 0){
291 // have at least one output to consider
291 // have at least one output to consider
292 var last = this.outputs[this.outputs.length-1];
292 var last = this.outputs[this.outputs.length-1];
293 if (last.output_type == 'stream' && json.stream == last.stream){
293 if (last.output_type == 'stream' && json.stream == last.stream){
294 // latest output was in the same stream,
294 // latest output was in the same stream,
295 // so append directly into its pre tag
295 // so append directly into its pre tag
296 // escape ANSI & HTML specials:
296 // escape ANSI & HTML specials:
297 var pre = this.element.find('div.'+subclass).last().find('pre');
297 var pre = this.element.find('div.'+subclass).last().find('pre');
298 var html = utils.fixCarriageReturn(
298 var html = utils.fixCarriageReturn(
299 pre.html() + utils.fixConsole(text));
299 pre.html() + utils.fixConsole(text));
300 pre.html(html);
300 pre.html(html);
301 return;
301 return;
302 }
302 }
303 }
303 }
304
304
305 if (!text.replace("\r", "")) {
305 if (!text.replace("\r", "")) {
306 // text is nothing (empty string, \r, etc.)
306 // text is nothing (empty string, \r, etc.)
307 // so don't append any elements, which might add undesirable space
307 // so don't append any elements, which might add undesirable space
308 return;
308 return;
309 }
309 }
310
310
311 // If we got here, attach a new div
311 // If we got here, attach a new div
312 var toinsert = this.create_output_area();
312 var toinsert = this.create_output_area();
313 this.append_text(text, toinsert, "output_stream "+subclass);
313 this.append_text(text, toinsert, "output_stream "+subclass);
314 this.element.append(toinsert);
314 this.element.append(toinsert);
315 };
315 };
316
316
317
317
318 OutputArea.prototype.append_display_data = function (json, dynamic) {
318 OutputArea.prototype.append_display_data = function (json, dynamic) {
319 var toinsert = this.create_output_area();
319 var toinsert = this.create_output_area();
320 this.append_mime_type(json, toinsert, dynamic);
320 this.append_mime_type(json, toinsert, dynamic);
321 this.element.append(toinsert);
321 this.element.append(toinsert);
322 // If we just output latex, typeset it.
322 // If we just output latex, typeset it.
323 if ( (json.latex !== undefined) || (json.html !== undefined) ) {
323 if ( (json.latex !== undefined) || (json.html !== undefined) ) {
324 this.typeset();
324 this.typeset();
325 }
325 }
326 };
326 };
327
327
328 OutputArea.display_order = ['javascript','html','latex','svg','png','jpeg','text'];
328 OutputArea.display_order = ['javascript','html','latex','svg','png','jpeg','text'];
329
329
330 OutputArea.prototype.append_mime_type = function (json, element, dynamic) {
330 OutputArea.prototype.append_mime_type = function (json, element, dynamic) {
331 for(var type_i in OutputArea.display_order){
331 for(var type_i in OutputArea.display_order){
332 var type = OutputArea.display_order[type_i];
332 var type = OutputArea.display_order[type_i];
333 if(json[type] != undefined ){
333 if(json[type] != undefined ){
334 if(type == 'javascript'){
334 if(type == 'javascript'){
335 if (dynamic) {
335 if (dynamic) {
336 this.append_javascript(json.javascript, element, dynamic);
336 this.append_javascript(json.javascript, element, dynamic);
337 }
337 }
338 } else {
338 } else {
339 this['append_'+type](json[type], element);
339 this['append_'+type](json[type], element);
340 }
340 }
341 return;
341 return;
342 }
342 }
343 }
343 }
344 };
344 };
345
345
346
346
347 OutputArea.prototype.append_html = function (html, element) {
347 OutputArea.prototype.append_html = function (html, element) {
348 var toinsert = $("<div/>").addClass("box-flex1 output_subarea output_html rendered_html");
348 var toinsert = $("<div/>").addClass("box-flex1 output_subarea output_html rendered_html");
349 toinsert.append(html);
349 toinsert.append(html);
350 element.append(toinsert);
350 element.append(toinsert);
351 };
351 };
352
352
353
353
354 OutputArea.prototype.append_javascript = function (js, container) {
354 OutputArea.prototype.append_javascript = function (js, container) {
355 // We just eval the JS code, element appears in the local scope.
355 // We just eval the JS code, element appears in the local scope.
356 var element = $("<div/>").addClass("box-flex1 output_subarea");
356 var element = $("<div/>").addClass("box-flex1 output_subarea");
357 container.append(element);
357 container.append(element);
358 // Div for js shouldn't be drawn, as it will add empty height to the area.
358 // Div for js shouldn't be drawn, as it will add empty height to the area.
359 container.hide();
359 container.hide();
360 // If the Javascript appends content to `element` that should be drawn, then
360 // If the Javascript appends content to `element` that should be drawn, then
361 // it must also call `container.show()`.
361 // it must also call `container.show()`.
362 try {
362 try {
363 eval(js);
363 eval(js);
364 } catch(err) {
364 } catch(err) {
365 console.log('Error in Javascript!');
365 console.log('Error in Javascript!');
366 console.log(err);
366 console.log(err);
367 container.show();
367 container.show();
368 element.append($('<div/>')
368 element.append($('<div/>')
369 .html("Error in Javascript !<br/>"+
369 .html("Error in Javascript !<br/>"+
370 err.toString()+
370 err.toString()+
371 '<br/>See your browser Javascript console for more details.')
371 '<br/>See your browser Javascript console for more details.')
372 .addClass('js-error')
372 .addClass('js-error')
373 );
373 );
374 }
374 }
375 };
375 };
376
376
377
377
378 OutputArea.prototype.append_text = function (data, element, extra_class) {
378 OutputArea.prototype.append_text = function (data, element, extra_class) {
379 var toinsert = $("<div/>").addClass("box-flex1 output_subarea output_text");
379 var toinsert = $("<div/>").addClass("box-flex1 output_subarea output_text");
380 // escape ANSI & HTML specials in plaintext:
380 // escape ANSI & HTML specials in plaintext:
381 data = utils.wrapUrls(data);
382 data = utils.fixConsole(data);
381 data = utils.fixConsole(data);
383 data = utils.fixCarriageReturn(data);
382 data = utils.fixCarriageReturn(data);
384 data = utils.autoLinkUrls(data);
383 data = utils.autoLinkUrls(data);
385 if (extra_class){
384 if (extra_class){
386 toinsert.addClass(extra_class);
385 toinsert.addClass(extra_class);
387 }
386 }
388 toinsert.append($("<pre/>").html(data));
387 toinsert.append($("<pre/>").html(data));
389 element.append(toinsert);
388 element.append(toinsert);
390 };
389 };
391
390
392
391
393 OutputArea.prototype.append_svg = function (svg, element) {
392 OutputArea.prototype.append_svg = function (svg, element) {
394 var toinsert = $("<div/>").addClass("box-flex1 output_subarea output_svg");
393 var toinsert = $("<div/>").addClass("box-flex1 output_subarea output_svg");
395 toinsert.append(svg);
394 toinsert.append(svg);
396 element.append(toinsert);
395 element.append(toinsert);
397 };
396 };
398
397
399
398
400 OutputArea.prototype._dblclick_to_reset_size = function (img) {
399 OutputArea.prototype._dblclick_to_reset_size = function (img) {
401 // schedule wrapping image in resizable after a delay,
400 // schedule wrapping image in resizable after a delay,
402 // so we don't end up calling resize on a zero-size object
401 // so we don't end up calling resize on a zero-size object
403 var that = this;
402 var that = this;
404 setTimeout(function () {
403 setTimeout(function () {
405 var h0 = img.height();
404 var h0 = img.height();
406 var w0 = img.width();
405 var w0 = img.width();
407 if (!(h0 && w0)) {
406 if (!(h0 && w0)) {
408 // zero size, schedule another timeout
407 // zero size, schedule another timeout
409 that._dblclick_to_reset_size(img);
408 that._dblclick_to_reset_size(img);
410 return;
409 return;
411 }
410 }
412 img.resizable({
411 img.resizable({
413 aspectRatio: true,
412 aspectRatio: true,
414 autoHide: true
413 autoHide: true
415 });
414 });
416 img.dblclick(function () {
415 img.dblclick(function () {
417 // resize wrapper & image together for some reason:
416 // resize wrapper & image together for some reason:
418 img.parent().height(h0);
417 img.parent().height(h0);
419 img.height(h0);
418 img.height(h0);
420 img.parent().width(w0);
419 img.parent().width(w0);
421 img.width(w0);
420 img.width(w0);
422 });
421 });
423 }, 250);
422 }, 250);
424 };
423 };
425
424
426
425
427 OutputArea.prototype.append_png = function (png, element) {
426 OutputArea.prototype.append_png = function (png, element) {
428 var toinsert = $("<div/>").addClass("box-flex1 output_subarea output_png");
427 var toinsert = $("<div/>").addClass("box-flex1 output_subarea output_png");
429 var img = $("<img/>").attr('src','data:image/png;base64,'+png);
428 var img = $("<img/>").attr('src','data:image/png;base64,'+png);
430 this._dblclick_to_reset_size(img);
429 this._dblclick_to_reset_size(img);
431 toinsert.append(img);
430 toinsert.append(img);
432 element.append(toinsert);
431 element.append(toinsert);
433 };
432 };
434
433
435
434
436 OutputArea.prototype.append_jpeg = function (jpeg, element) {
435 OutputArea.prototype.append_jpeg = function (jpeg, element) {
437 var toinsert = $("<div/>").addClass("box-flex1 output_subarea output_jpeg");
436 var toinsert = $("<div/>").addClass("box-flex1 output_subarea output_jpeg");
438 var img = $("<img/>").attr('src','data:image/jpeg;base64,'+jpeg);
437 var img = $("<img/>").attr('src','data:image/jpeg;base64,'+jpeg);
439 this._dblclick_to_reset_size(img);
438 this._dblclick_to_reset_size(img);
440 toinsert.append(img);
439 toinsert.append(img);
441 element.append(toinsert);
440 element.append(toinsert);
442 };
441 };
443
442
444
443
445 OutputArea.prototype.append_latex = function (latex, element) {
444 OutputArea.prototype.append_latex = function (latex, element) {
446 // This method cannot do the typesetting because the latex first has to
445 // This method cannot do the typesetting because the latex first has to
447 // be on the page.
446 // be on the page.
448 var toinsert = $("<div/>").addClass("box-flex1 output_subarea output_latex");
447 var toinsert = $("<div/>").addClass("box-flex1 output_subarea output_latex");
449 toinsert.append(latex);
448 toinsert.append(latex);
450 element.append(toinsert);
449 element.append(toinsert);
451 };
450 };
452
451
453
452
454 OutputArea.prototype.handle_clear_output = function (content) {
453 OutputArea.prototype.handle_clear_output = function (content) {
455 this.clear_output(content.stdout, content.stderr, content.other);
454 this.clear_output(content.stdout, content.stderr, content.other);
456 };
455 };
457
456
458
457
459 OutputArea.prototype.clear_output = function (stdout, stderr, other) {
458 OutputArea.prototype.clear_output = function (stdout, stderr, other) {
460 var that = this;
459 var that = this;
461 if (this.clear_out_timeout != null){
460 if (this.clear_out_timeout != null){
462 // fire previous pending clear *immediately*
461 // fire previous pending clear *immediately*
463 clearTimeout(this.clear_out_timeout);
462 clearTimeout(this.clear_out_timeout);
464 this.clear_out_timeout = null;
463 this.clear_out_timeout = null;
465 this.clear_output_callback(this._clear_stdout, this._clear_stderr, this._clear_other);
464 this.clear_output_callback(this._clear_stdout, this._clear_stderr, this._clear_other);
466 }
465 }
467 // store flags for flushing the timeout
466 // store flags for flushing the timeout
468 this._clear_stdout = stdout;
467 this._clear_stdout = stdout;
469 this._clear_stderr = stderr;
468 this._clear_stderr = stderr;
470 this._clear_other = other;
469 this._clear_other = other;
471 this.clear_out_timeout = setTimeout(function() {
470 this.clear_out_timeout = setTimeout(function() {
472 // really clear timeout only after a short delay
471 // really clear timeout only after a short delay
473 // this reduces flicker in 'clear_output; print' cases
472 // this reduces flicker in 'clear_output; print' cases
474 that.clear_out_timeout = null;
473 that.clear_out_timeout = null;
475 that._clear_stdout = that._clear_stderr = that._clear_other = null;
474 that._clear_stdout = that._clear_stderr = that._clear_other = null;
476 that.clear_output_callback(stdout, stderr, other);
475 that.clear_output_callback(stdout, stderr, other);
477 }, 500
476 }, 500
478 );
477 );
479 };
478 };
480
479
481
480
482 OutputArea.prototype.clear_output_callback = function (stdout, stderr, other) {
481 OutputArea.prototype.clear_output_callback = function (stdout, stderr, other) {
483 var output_div = this.element;
482 var output_div = this.element;
484
483
485 if (stdout && stderr && other){
484 if (stdout && stderr && other){
486 // clear all, no need for logic
485 // clear all, no need for logic
487 output_div.html("");
486 output_div.html("");
488 this.outputs = [];
487 this.outputs = [];
489 this.unscroll_area();
488 this.unscroll_area();
490 return;
489 return;
491 }
490 }
492 // remove html output
491 // remove html output
493 // each output_subarea that has an identifying class is in an output_area
492 // each output_subarea that has an identifying class is in an output_area
494 // which is the element to be removed.
493 // which is the element to be removed.
495 if (stdout) {
494 if (stdout) {
496 output_div.find("div.output_stdout").parent().remove();
495 output_div.find("div.output_stdout").parent().remove();
497 }
496 }
498 if (stderr) {
497 if (stderr) {
499 output_div.find("div.output_stderr").parent().remove();
498 output_div.find("div.output_stderr").parent().remove();
500 }
499 }
501 if (other) {
500 if (other) {
502 output_div.find("div.output_subarea").not("div.output_stderr").not("div.output_stdout").parent().remove();
501 output_div.find("div.output_subarea").not("div.output_stderr").not("div.output_stdout").parent().remove();
503 }
502 }
504 this.unscroll_area();
503 this.unscroll_area();
505
504
506 // remove cleared outputs from JSON list:
505 // remove cleared outputs from JSON list:
507 for (var i = this.outputs.length - 1; i >= 0; i--) {
506 for (var i = this.outputs.length - 1; i >= 0; i--) {
508 var out = this.outputs[i];
507 var out = this.outputs[i];
509 var output_type = out.output_type;
508 var output_type = out.output_type;
510 if (output_type == "display_data" && other) {
509 if (output_type == "display_data" && other) {
511 this.outputs.splice(i,1);
510 this.outputs.splice(i,1);
512 } else if (output_type == "stream") {
511 } else if (output_type == "stream") {
513 if (stdout && out.stream == "stdout") {
512 if (stdout && out.stream == "stdout") {
514 this.outputs.splice(i,1);
513 this.outputs.splice(i,1);
515 } else if (stderr && out.stream == "stderr") {
514 } else if (stderr && out.stream == "stderr") {
516 this.outputs.splice(i,1);
515 this.outputs.splice(i,1);
517 }
516 }
518 }
517 }
519 }
518 }
520 };
519 };
521
520
522
521
523 OutputArea.prototype.flush_clear_timeout = function() {
522 OutputArea.prototype.flush_clear_timeout = function() {
524 var output_div = this.element;
523 var output_div = this.element;
525 if (this.clear_out_timeout){
524 if (this.clear_out_timeout){
526 clearTimeout(this.clear_out_timeout);
525 clearTimeout(this.clear_out_timeout);
527 this.clear_out_timeout = null;
526 this.clear_out_timeout = null;
528 this.clear_output_callback(this._clear_stdout, this._clear_stderr, this._clear_other);
527 this.clear_output_callback(this._clear_stdout, this._clear_stderr, this._clear_other);
529 }
528 }
530 };
529 };
531
530
532
531
533 // JSON serialization
532 // JSON serialization
534
533
535 OutputArea.prototype.fromJSON = function (outputs) {
534 OutputArea.prototype.fromJSON = function (outputs) {
536 var len = outputs.length;
535 var len = outputs.length;
537 for (var i=0; i<len; i++) {
536 for (var i=0; i<len; i++) {
538 // append with dynamic=false.
537 // append with dynamic=false.
539 this.append_output(outputs[i], false);
538 this.append_output(outputs[i], false);
540 }
539 }
541 };
540 };
542
541
543
542
544 OutputArea.prototype.toJSON = function () {
543 OutputArea.prototype.toJSON = function () {
545 var outputs = [];
544 var outputs = [];
546 var len = this.outputs.length;
545 var len = this.outputs.length;
547 for (var i=0; i<len; i++) {
546 for (var i=0; i<len; i++) {
548 outputs[i] = this.outputs[i];
547 outputs[i] = this.outputs[i];
549 }
548 }
550 return outputs;
549 return outputs;
551 };
550 };
552
551
553
552
554 IPython.OutputArea = OutputArea;
553 IPython.OutputArea = OutputArea;
555
554
556 return IPython;
555 return IPython;
557
556
558 }(IPython));
557 }(IPython));
@@ -1,299 +1,286 b''
1 //----------------------------------------------------------------------------
1 //----------------------------------------------------------------------------
2 // Copyright (C) 2008-2012 The IPython Development Team
2 // Copyright (C) 2008-2012 The IPython Development Team
3 //
3 //
4 // Distributed under the terms of the BSD License. The full license is in
4 // Distributed under the terms of the BSD License. The full license is in
5 // the file COPYING, distributed as part of this software.
5 // the file COPYING, distributed as part of this software.
6 //----------------------------------------------------------------------------
6 //----------------------------------------------------------------------------
7
7
8 //============================================================================
8 //============================================================================
9 // Utilities
9 // Utilities
10 //============================================================================
10 //============================================================================
11
11
12 IPython.namespace('IPython.utils');
12 IPython.namespace('IPython.utils');
13
13
14 IPython.utils = (function (IPython) {
14 IPython.utils = (function (IPython) {
15
15
16 //============================================================================
16 //============================================================================
17 // Cross-browser RegEx Split
17 // Cross-browser RegEx Split
18 //============================================================================
18 //============================================================================
19
19
20 // This code has been MODIFIED from the code licensed below to not replace the
20 // This code has been MODIFIED from the code licensed below to not replace the
21 // default browser split. The license is reproduced here.
21 // default browser split. The license is reproduced here.
22
22
23 // see http://blog.stevenlevithan.com/archives/cross-browser-split for more info:
23 // see http://blog.stevenlevithan.com/archives/cross-browser-split for more info:
24 /*!
24 /*!
25 * Cross-Browser Split 1.1.1
25 * Cross-Browser Split 1.1.1
26 * Copyright 2007-2012 Steven Levithan <stevenlevithan.com>
26 * Copyright 2007-2012 Steven Levithan <stevenlevithan.com>
27 * Available under the MIT License
27 * Available under the MIT License
28 * ECMAScript compliant, uniform cross-browser split method
28 * ECMAScript compliant, uniform cross-browser split method
29 */
29 */
30
30
31 /**
31 /**
32 * Splits a string into an array of strings using a regex or string
32 * Splits a string into an array of strings using a regex or string
33 * separator. Matches of the separator are not included in the result array.
33 * separator. Matches of the separator are not included in the result array.
34 * However, if `separator` is a regex that contains capturing groups,
34 * However, if `separator` is a regex that contains capturing groups,
35 * backreferences are spliced into the result each time `separator` is
35 * backreferences are spliced into the result each time `separator` is
36 * matched. Fixes browser bugs compared to the native
36 * matched. Fixes browser bugs compared to the native
37 * `String.prototype.split` and can be used reliably cross-browser.
37 * `String.prototype.split` and can be used reliably cross-browser.
38 * @param {String} str String to split.
38 * @param {String} str String to split.
39 * @param {RegExp|String} separator Regex or string to use for separating
39 * @param {RegExp|String} separator Regex or string to use for separating
40 * the string.
40 * the string.
41 * @param {Number} [limit] Maximum number of items to include in the result
41 * @param {Number} [limit] Maximum number of items to include in the result
42 * array.
42 * array.
43 * @returns {Array} Array of substrings.
43 * @returns {Array} Array of substrings.
44 * @example
44 * @example
45 *
45 *
46 * // Basic use
46 * // Basic use
47 * regex_split('a b c d', ' ');
47 * regex_split('a b c d', ' ');
48 * // -> ['a', 'b', 'c', 'd']
48 * // -> ['a', 'b', 'c', 'd']
49 *
49 *
50 * // With limit
50 * // With limit
51 * regex_split('a b c d', ' ', 2);
51 * regex_split('a b c d', ' ', 2);
52 * // -> ['a', 'b']
52 * // -> ['a', 'b']
53 *
53 *
54 * // Backreferences in result array
54 * // Backreferences in result array
55 * regex_split('..word1 word2..', /([a-z]+)(\d+)/i);
55 * regex_split('..word1 word2..', /([a-z]+)(\d+)/i);
56 * // -> ['..', 'word', '1', ' ', 'word', '2', '..']
56 * // -> ['..', 'word', '1', ' ', 'word', '2', '..']
57 */
57 */
58 var regex_split = function (str, separator, limit) {
58 var regex_split = function (str, separator, limit) {
59 // If `separator` is not a regex, use `split`
59 // If `separator` is not a regex, use `split`
60 if (Object.prototype.toString.call(separator) !== "[object RegExp]") {
60 if (Object.prototype.toString.call(separator) !== "[object RegExp]") {
61 return split.call(str, separator, limit);
61 return split.call(str, separator, limit);
62 }
62 }
63 var output = [],
63 var output = [],
64 flags = (separator.ignoreCase ? "i" : "") +
64 flags = (separator.ignoreCase ? "i" : "") +
65 (separator.multiline ? "m" : "") +
65 (separator.multiline ? "m" : "") +
66 (separator.extended ? "x" : "") + // Proposed for ES6
66 (separator.extended ? "x" : "") + // Proposed for ES6
67 (separator.sticky ? "y" : ""), // Firefox 3+
67 (separator.sticky ? "y" : ""), // Firefox 3+
68 lastLastIndex = 0,
68 lastLastIndex = 0,
69 // Make `global` and avoid `lastIndex` issues by working with a copy
69 // Make `global` and avoid `lastIndex` issues by working with a copy
70 separator = new RegExp(separator.source, flags + "g"),
70 separator = new RegExp(separator.source, flags + "g"),
71 separator2, match, lastIndex, lastLength;
71 separator2, match, lastIndex, lastLength;
72 str += ""; // Type-convert
72 str += ""; // Type-convert
73
73
74 var compliantExecNpcg = typeof(/()??/.exec("")[1]) === "undefined"
74 var compliantExecNpcg = typeof(/()??/.exec("")[1]) === "undefined"
75 if (!compliantExecNpcg) {
75 if (!compliantExecNpcg) {
76 // Doesn't need flags gy, but they don't hurt
76 // Doesn't need flags gy, but they don't hurt
77 separator2 = new RegExp("^" + separator.source + "$(?!\\s)", flags);
77 separator2 = new RegExp("^" + separator.source + "$(?!\\s)", flags);
78 }
78 }
79 /* Values for `limit`, per the spec:
79 /* Values for `limit`, per the spec:
80 * If undefined: 4294967295 // Math.pow(2, 32) - 1
80 * If undefined: 4294967295 // Math.pow(2, 32) - 1
81 * If 0, Infinity, or NaN: 0
81 * If 0, Infinity, or NaN: 0
82 * If positive number: limit = Math.floor(limit); if (limit > 4294967295) limit -= 4294967296;
82 * If positive number: limit = Math.floor(limit); if (limit > 4294967295) limit -= 4294967296;
83 * If negative number: 4294967296 - Math.floor(Math.abs(limit))
83 * If negative number: 4294967296 - Math.floor(Math.abs(limit))
84 * If other: Type-convert, then use the above rules
84 * If other: Type-convert, then use the above rules
85 */
85 */
86 limit = typeof(limit) === "undefined" ?
86 limit = typeof(limit) === "undefined" ?
87 -1 >>> 0 : // Math.pow(2, 32) - 1
87 -1 >>> 0 : // Math.pow(2, 32) - 1
88 limit >>> 0; // ToUint32(limit)
88 limit >>> 0; // ToUint32(limit)
89 while (match = separator.exec(str)) {
89 while (match = separator.exec(str)) {
90 // `separator.lastIndex` is not reliable cross-browser
90 // `separator.lastIndex` is not reliable cross-browser
91 lastIndex = match.index + match[0].length;
91 lastIndex = match.index + match[0].length;
92 if (lastIndex > lastLastIndex) {
92 if (lastIndex > lastLastIndex) {
93 output.push(str.slice(lastLastIndex, match.index));
93 output.push(str.slice(lastLastIndex, match.index));
94 // Fix browsers whose `exec` methods don't consistently return `undefined` for
94 // Fix browsers whose `exec` methods don't consistently return `undefined` for
95 // nonparticipating capturing groups
95 // nonparticipating capturing groups
96 if (!compliantExecNpcg && match.length > 1) {
96 if (!compliantExecNpcg && match.length > 1) {
97 match[0].replace(separator2, function () {
97 match[0].replace(separator2, function () {
98 for (var i = 1; i < arguments.length - 2; i++) {
98 for (var i = 1; i < arguments.length - 2; i++) {
99 if (typeof(arguments[i]) === "undefined") {
99 if (typeof(arguments[i]) === "undefined") {
100 match[i] = undefined;
100 match[i] = undefined;
101 }
101 }
102 }
102 }
103 });
103 });
104 }
104 }
105 if (match.length > 1 && match.index < str.length) {
105 if (match.length > 1 && match.index < str.length) {
106 Array.prototype.push.apply(output, match.slice(1));
106 Array.prototype.push.apply(output, match.slice(1));
107 }
107 }
108 lastLength = match[0].length;
108 lastLength = match[0].length;
109 lastLastIndex = lastIndex;
109 lastLastIndex = lastIndex;
110 if (output.length >= limit) {
110 if (output.length >= limit) {
111 break;
111 break;
112 }
112 }
113 }
113 }
114 if (separator.lastIndex === match.index) {
114 if (separator.lastIndex === match.index) {
115 separator.lastIndex++; // Avoid an infinite loop
115 separator.lastIndex++; // Avoid an infinite loop
116 }
116 }
117 }
117 }
118 if (lastLastIndex === str.length) {
118 if (lastLastIndex === str.length) {
119 if (lastLength || !separator.test("")) {
119 if (lastLength || !separator.test("")) {
120 output.push("");
120 output.push("");
121 }
121 }
122 } else {
122 } else {
123 output.push(str.slice(lastLastIndex));
123 output.push(str.slice(lastLastIndex));
124 }
124 }
125 return output.length > limit ? output.slice(0, limit) : output;
125 return output.length > limit ? output.slice(0, limit) : output;
126 };
126 };
127
127
128 //============================================================================
128 //============================================================================
129 // End contributed Cross-browser RegEx Split
129 // End contributed Cross-browser RegEx Split
130 //============================================================================
130 //============================================================================
131
131
132
132
133 var uuid = function () {
133 var uuid = function () {
134 // http://www.ietf.org/rfc/rfc4122.txt
134 // http://www.ietf.org/rfc/rfc4122.txt
135 var s = [];
135 var s = [];
136 var hexDigits = "0123456789ABCDEF";
136 var hexDigits = "0123456789ABCDEF";
137 for (var i = 0; i < 32; i++) {
137 for (var i = 0; i < 32; i++) {
138 s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
138 s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
139 }
139 }
140 s[12] = "4"; // bits 12-15 of the time_hi_and_version field to 0010
140 s[12] = "4"; // bits 12-15 of the time_hi_and_version field to 0010
141 s[16] = hexDigits.substr((s[16] & 0x3) | 0x8, 1); // bits 6-7 of the clock_seq_hi_and_reserved to 01
141 s[16] = hexDigits.substr((s[16] & 0x3) | 0x8, 1); // bits 6-7 of the clock_seq_hi_and_reserved to 01
142
142
143 var uuid = s.join("");
143 var uuid = s.join("");
144 return uuid;
144 return uuid;
145 };
145 };
146
146
147
147
148 //Fix raw text to parse correctly in crazy XML
148 //Fix raw text to parse correctly in crazy XML
149 function xmlencode(string) {
149 function xmlencode(string) {
150 return string.replace(/\&/g,'&'+'amp;')
150 return string.replace(/\&/g,'&'+'amp;')
151 .replace(/</g,'&'+'lt;')
151 .replace(/</g,'&'+'lt;')
152 .replace(/>/g,'&'+'gt;')
152 .replace(/>/g,'&'+'gt;')
153 .replace(/\'/g,'&'+'apos;')
153 .replace(/\'/g,'&'+'apos;')
154 .replace(/\"/g,'&'+'quot;')
154 .replace(/\"/g,'&'+'quot;')
155 .replace(/`/g,'&'+'#96;');
155 .replace(/`/g,'&'+'#96;');
156 }
156 }
157
157
158
158
159 //Map from terminal commands to CSS classes
159 //Map from terminal commands to CSS classes
160 var ansi_colormap = {
160 var ansi_colormap = {
161 "30":"ansiblack", "31":"ansired",
161 "30":"ansiblack", "31":"ansired",
162 "32":"ansigreen", "33":"ansiyellow",
162 "32":"ansigreen", "33":"ansiyellow",
163 "34":"ansiblue", "35":"ansipurple","36":"ansicyan",
163 "34":"ansiblue", "35":"ansipurple","36":"ansicyan",
164 "37":"ansigrey", "01":"ansibold"
164 "37":"ansigrey", "01":"ansibold"
165 };
165 };
166
166
167 // Transform ANSI color escape codes into HTML <span> tags with css
167 // Transform ANSI color escape codes into HTML <span> tags with css
168 // classes listed in the above ansi_colormap object. The actual color used
168 // classes listed in the above ansi_colormap object. The actual color used
169 // are set in the css file.
169 // are set in the css file.
170 function fixConsole(txt) {
170 function fixConsole(txt) {
171 txt = xmlencode(txt);
171 txt = xmlencode(txt);
172 var re = /\033\[([\dA-Fa-f;]*?)m/;
172 var re = /\033\[([\dA-Fa-f;]*?)m/;
173 var opened = false;
173 var opened = false;
174 var cmds = [];
174 var cmds = [];
175 var opener = "";
175 var opener = "";
176 var closer = "";
176 var closer = "";
177 while (re.test(txt)) {
177 while (re.test(txt)) {
178 var cmds = txt.match(re)[1].split(";");
178 var cmds = txt.match(re)[1].split(";");
179 closer = opened?"</span>":"";
179 closer = opened?"</span>":"";
180 opened = cmds.length > 1 || cmds[0] != 0;
180 opened = cmds.length > 1 || cmds[0] != 0;
181 var rep = [];
181 var rep = [];
182 for (var i in cmds)
182 for (var i in cmds)
183 if (typeof(ansi_colormap[cmds[i]]) != "undefined")
183 if (typeof(ansi_colormap[cmds[i]]) != "undefined")
184 rep.push(ansi_colormap[cmds[i]]);
184 rep.push(ansi_colormap[cmds[i]]);
185 opener = rep.length > 0?"<span class=\""+rep.join(" ")+"\">":"";
185 opener = rep.length > 0?"<span class=\""+rep.join(" ")+"\">":"";
186 txt = txt.replace(re, closer + opener);
186 txt = txt.replace(re, closer + opener);
187 }
187 }
188 if (opened) txt += "</span>";
188 if (opened) txt += "</span>";
189 return txt;
189 return txt;
190 }
190 }
191
191
192 // Remove chunks that should be overridden by the effect of
192 // Remove chunks that should be overridden by the effect of
193 // carriage return characters
193 // carriage return characters
194 function fixCarriageReturn(txt) {
194 function fixCarriageReturn(txt) {
195 var tmp = txt;
195 var tmp = txt;
196 do {
196 do {
197 txt = tmp;
197 txt = tmp;
198 tmp = txt.replace(/\r+\n/gm, '\n'); // \r followed by \n --> newline
198 tmp = txt.replace(/\r+\n/gm, '\n'); // \r followed by \n --> newline
199 tmp = tmp.replace(/^.*\r+/gm, ''); // Other \r --> clear line
199 tmp = tmp.replace(/^.*\r+/gm, ''); // Other \r --> clear line
200 } while (tmp.length < txt.length);
200 } while (tmp.length < txt.length);
201 return txt;
201 return txt;
202 }
202 }
203
203
204 // Locate URLs in plain text and wrap them in spaces so that they can be
204 // Locate any URLs and convert them to a anchor tag
205 // better picked out by autoLinkUrls even after the text has been
206 // converted to HTML
207 function wrapUrls(txt) {
208 // Note this regexp is a modified version of one from
209 // Markdown.Converter For now it only supports http(s) and ftp URLs,
210 // but could easily support others (though file:// should maybe be
211 // avoided)
212 var url_re = /(^|\W)(https?|ftp)(:\/\/[-A-Z0-9+&@#\/%?=~_|\[\]\(\)!:,\.;]*[-A-Z0-9+&@#\/%=~_|\[\]])($|\W)/gi;
213 return txt.replace(url_re, "$1 $2$3 $4");
214 }
215
216 // Locate a URL with spaces around it and convert that to a anchor tag
217 function autoLinkUrls(txt) {
205 function autoLinkUrls(txt) {
218 return txt.replace(/ ((https?|ftp):[^'">\s]+) /gi,
206 return txt.replace(/(^|\s)(https?|ftp)(:[^'">\s]+)/gi,
219 "<a target=\"_blank\" href=\"$1\">$1</a>");
207 "$1<a target=\"_blank\" href=\"$2$3\">$2$3</a>");
220 }
208 }
221
209
222 grow = function(element) {
210 grow = function(element) {
223 // Grow the cell by hand. This is used upon reloading from JSON, when the
211 // Grow the cell by hand. This is used upon reloading from JSON, when the
224 // autogrow handler is not called.
212 // autogrow handler is not called.
225 var dom = element.get(0);
213 var dom = element.get(0);
226 var lines_count = 0;
214 var lines_count = 0;
227 // modified split rule from
215 // modified split rule from
228 // http://stackoverflow.com/questions/2035910/how-to-get-the-number-of-lines-in-a-textarea/2036424#2036424
216 // http://stackoverflow.com/questions/2035910/how-to-get-the-number-of-lines-in-a-textarea/2036424#2036424
229 var lines = dom.value.split(/\r|\r\n|\n/);
217 var lines = dom.value.split(/\r|\r\n|\n/);
230 lines_count = lines.length;
218 lines_count = lines.length;
231 if (lines_count >= 1) {
219 if (lines_count >= 1) {
232 dom.rows = lines_count;
220 dom.rows = lines_count;
233 } else {
221 } else {
234 dom.rows = 1;
222 dom.rows = 1;
235 }
223 }
236 };
224 };
237
225
238 // some keycodes that seem to be platform/browser independant
226 // some keycodes that seem to be platform/browser independant
239 var keycodes ={
227 var keycodes ={
240 BACKSPACE: 8,
228 BACKSPACE: 8,
241 TAB : 9,
229 TAB : 9,
242 ENTER : 13,
230 ENTER : 13,
243 SHIFT : 16,
231 SHIFT : 16,
244 CTRL : 17,
232 CTRL : 17,
245 CONTROL : 17,
233 CONTROL : 17,
246 ALT : 18,
234 ALT : 18,
247 ESC : 27,
235 ESC : 27,
248 SPACE : 32,
236 SPACE : 32,
249 PGUP : 33,
237 PGUP : 33,
250 PGDOWN : 34,
238 PGDOWN : 34,
251 LEFT_ARROW: 37,
239 LEFT_ARROW: 37,
252 LEFTARROW: 37,
240 LEFTARROW: 37,
253 LEFT : 37,
241 LEFT : 37,
254 UP_ARROW : 38,
242 UP_ARROW : 38,
255 UPARROW : 38,
243 UPARROW : 38,
256 UP : 38,
244 UP : 38,
257 RIGHT_ARROW:39,
245 RIGHT_ARROW:39,
258 RIGHTARROW:39,
246 RIGHTARROW:39,
259 RIGHT : 39,
247 RIGHT : 39,
260 DOWN_ARROW: 40,
248 DOWN_ARROW: 40,
261 DOWNARROW: 40,
249 DOWNARROW: 40,
262 DOWN : 40,
250 DOWN : 40,
263 };
251 };
264
252
265
253
266 var points_to_pixels = function (points) {
254 var points_to_pixels = function (points) {
267 // A reasonably good way of converting between points and pixels.
255 // A reasonably good way of converting between points and pixels.
268 var test = $('<div style="display: none; width: 10000pt; padding:0; border:0;"></div>');
256 var test = $('<div style="display: none; width: 10000pt; padding:0; border:0;"></div>');
269 $(body).append(test);
257 $(body).append(test);
270 var pixel_per_point = test.width()/10000;
258 var pixel_per_point = test.width()/10000;
271 test.remove();
259 test.remove();
272 return Math.floor(points*pixel_per_point);
260 return Math.floor(points*pixel_per_point);
273 };
261 };
274
262
275 // http://stackoverflow.com/questions/2400935/browser-detection-in-javascript
263 // http://stackoverflow.com/questions/2400935/browser-detection-in-javascript
276 browser = (function() {
264 browser = (function() {
277 var N= navigator.appName, ua= navigator.userAgent, tem;
265 var N= navigator.appName, ua= navigator.userAgent, tem;
278 var M= ua.match(/(opera|chrome|safari|firefox|msie)\/?\s*(\.?\d+(\.\d+)*)/i);
266 var M= ua.match(/(opera|chrome|safari|firefox|msie)\/?\s*(\.?\d+(\.\d+)*)/i);
279 if (M && (tem= ua.match(/version\/([\.\d]+)/i))!= null) M[2]= tem[1];
267 if (M && (tem= ua.match(/version\/([\.\d]+)/i))!= null) M[2]= tem[1];
280 M= M? [M[1], M[2]]: [N, navigator.appVersion,'-?'];
268 M= M? [M[1], M[2]]: [N, navigator.appVersion,'-?'];
281 return M;
269 return M;
282 })();
270 })();
283
271
284
272
285 return {
273 return {
286 regex_split : regex_split,
274 regex_split : regex_split,
287 uuid : uuid,
275 uuid : uuid,
288 fixConsole : fixConsole,
276 fixConsole : fixConsole,
289 keycodes : keycodes,
277 keycodes : keycodes,
290 grow : grow,
278 grow : grow,
291 fixCarriageReturn : fixCarriageReturn,
279 fixCarriageReturn : fixCarriageReturn,
292 wrapUrls : wrapUrls,
293 autoLinkUrls : autoLinkUrls,
280 autoLinkUrls : autoLinkUrls,
294 points_to_pixels : points_to_pixels,
281 points_to_pixels : points_to_pixels,
295 browser : browser
282 browser : browser
296 };
283 };
297
284
298 }(IPython));
285 }(IPython));
299
286
General Comments 0
You need to be logged in to leave comments. Login now