##// END OF EJS Templates
Implemented module and namespace pattern in js notebook.
Brian E. Granger -
Show More
@@ -3,70 +3,78 b''
3 3 // Cell
4 4 //============================================================================
5 5
6 var IPython = (function (IPython) {
6 7
7 var Cell = function (notebook) {
8 this.notebook = notebook;
9 this.selected = false;
10 this.element;
11 this.create_element();
12 if (this.element !== undefined) {
13 this.element.data("cell", this);
14 this.bind_events();
15 }
16 this.cell_id = uuid();
17 };
18
19
20 Cell.prototype.grow = function(element) {
21 // Grow the cell by hand. This is used upon reloading from JSON, when the
22 // autogrow handler is not called.
23 var dom = element.get(0);
24 var lines_count = 0;
25 // modified split rule from
26 // http://stackoverflow.com/questions/2035910/how-to-get-the-number-of-lines-in-a-textarea/2036424#2036424
27 var lines = dom.value.split(/\r|\r\n|\n/);
28 lines_count = lines.length;
29 if (lines_count >= 1) {
30 dom.rows = lines_count;
31 } else {
32 dom.rows = 1;
33 }
34 };
35
36
37 Cell.prototype.select = function () {
38 this.element.addClass('ui-widget-content ui-corner-all');
39 this.selected = true;
40 // TODO: we need t test across browsers to see if both of these are needed.
41 // In the meantime, there should not be any harm in having them both.
42 this.element.find('textarea').trigger('focusin');
43 this.element.find('textarea').trigger('focus');
44 };
45
46
47 Cell.prototype.unselect = function () {
48 this.element.removeClass('ui-widget-content ui-corner-all');
49 this.selected = false;
50 };
51
52
53 Cell.prototype.bind_events = function () {
54 var that = this;
55 var nb = that.notebook
56 that.element.click(function (event) {
57 if (that.selected === false) {
58 nb.select(nb.find_cell_index(that));
59 };
60 });
61 that.element.focusin(function (event) {
62 if (that.selected === false) {
63 nb.select(nb.find_cell_index(that));
64 };
65 });
66 };
67
68
69 // Subclasses must implement create_element.
70 Cell.prototype.create_element = function () {};
8 var utils = IPython.utils;
71 9
10 var Cell = function (notebook) {
11 this.notebook = notebook;
12 this.selected = false;
13 this.element;
14 this.create_element();
15 if (this.element !== undefined) {
16 this.element.data("cell", this);
17 this.bind_events();
18 }
19 this.cell_id = utils.uuid();
20 };
21
22
23 Cell.prototype.grow = function(element) {
24 // Grow the cell by hand. This is used upon reloading from JSON, when the
25 // autogrow handler is not called.
26 var dom = element.get(0);
27 var lines_count = 0;
28 // modified split rule from
29 // http://stackoverflow.com/questions/2035910/how-to-get-the-number-of-lines-in-a-textarea/2036424#2036424
30 var lines = dom.value.split(/\r|\r\n|\n/);
31 lines_count = lines.length;
32 if (lines_count >= 1) {
33 dom.rows = lines_count;
34 } else {
35 dom.rows = 1;
36 }
37 };
38
39
40 Cell.prototype.select = function () {
41 this.element.addClass('ui-widget-content ui-corner-all');
42 this.selected = true;
43 // TODO: we need t test across browsers to see if both of these are needed.
44 // In the meantime, there should not be any harm in having them both.
45 this.element.find('textarea').trigger('focusin');
46 this.element.find('textarea').trigger('focus');
47 };
48
49
50 Cell.prototype.unselect = function () {
51 this.element.removeClass('ui-widget-content ui-corner-all');
52 this.selected = false;
53 };
54
55
56 Cell.prototype.bind_events = function () {
57 var that = this;
58 var nb = that.notebook
59 that.element.click(function (event) {
60 if (that.selected === false) {
61 nb.select(nb.find_cell_index(that));
62 };
63 });
64 that.element.focusin(function (event) {
65 if (that.selected === false) {
66 nb.select(nb.find_cell_index(that));
67 };
68 });
69 };
70
71
72 // Subclasses must implement create_element.
73 Cell.prototype.create_element = function () {};
74
75 IPython.Cell = Cell;
76
77 return IPython;
78
79 }(IPython));
72 80
@@ -3,193 +3,199 b''
3 3 // CodeCell
4 4 //============================================================================
5 5
6 var IPython = (function (IPython) {
6 7
7 var CodeCell = function (notebook) {
8 this.code_mirror = null;
9 this.input_prompt_number = ' ';
10 Cell.apply(this, arguments);
11 };
12
13
14 CodeCell.prototype = new Cell();
15
16
17 CodeCell.prototype.create_element = function () {
18 var cell = $('<div></div>').addClass('cell code_cell vbox border-box-sizing');
19 var input = $('<div></div>').addClass('input hbox border-box-sizing');
20 input.append($('<div/>').addClass('prompt input_prompt monospace-font'));
21 var input_area = $('<div/>').addClass('input_area box-flex1 border-box-sizing');
22 this.code_mirror = CodeMirror(input_area.get(0), {
23 indentUnit : 4,
24 enterMode : 'flat',
25 tabMode: 'shift'
26 });
27 input.append(input_area);
28 var output = $('<div></div>').addClass('output vbox border-box-sizing');
29 cell.append(input).append(output);
30 this.element = cell;
31 this.collapse()
32 };
33
34
35 CodeCell.prototype.select = function () {
36 Cell.prototype.select.apply(this);
37 this.code_mirror.focus();
38 };
39
40
41 CodeCell.prototype.append_pyout = function (data, n) {
42 var toinsert = $("<div/>").addClass("output_area output_pyout hbox monospace-font");
43 toinsert.append($('<div/>').
44 addClass('prompt output_prompt').
45 html('Out[' + n + ']:')
46 );
47 this.append_display_data(data, toinsert);
48 toinsert.children().last().addClass("box_flex1");
49 this.element.find("div.output").append(toinsert);
50 // If we just output latex, typeset it.
51 if (data["text/latex"] !== undefined) {
52 MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
53 };
54 };
55
56
57 CodeCell.prototype.append_pyerr = function (ename, evalue, tb) {
58 var s = '';
59 var len = tb.length;
60 for (var i=0; i<len; i++) {
61 s = s + tb[i] + '\n';
62 }
63 s = s + '\n';
64 this.append_stream(s);
65 };
66
67
68 CodeCell.prototype.append_display_data = function (data, element) {
69 console.log(data);
70 if (data["text/latex"] !== undefined) {
71 this.append_latex(data["text/latex"], element);
72 // If it is undefined, then we just appended to div.output, which
73 // makes the latex visible and we can typeset it. The typesetting
74 // has to be done after the latex is on the page.
75 if (element === undefined) {
8 var utils = IPython.utils;
9
10 var CodeCell = function (notebook) {
11 this.code_mirror = null;
12 this.input_prompt_number = ' ';
13 IPython.Cell.apply(this, arguments);
14 };
15
16
17 CodeCell.prototype = new IPython.Cell();
18
19
20 CodeCell.prototype.create_element = function () {
21 var cell = $('<div></div>').addClass('cell code_cell vbox border-box-sizing');
22 var input = $('<div></div>').addClass('input hbox border-box-sizing');
23 input.append($('<div/>').addClass('prompt input_prompt monospace-font'));
24 var input_area = $('<div/>').addClass('input_area box-flex1 border-box-sizing');
25 this.code_mirror = CodeMirror(input_area.get(0), {
26 indentUnit : 4,
27 enterMode : 'flat',
28 tabMode: 'shift'
29 });
30 input.append(input_area);
31 var output = $('<div></div>').addClass('output vbox border-box-sizing');
32 cell.append(input).append(output);
33 this.element = cell;
34 this.collapse()
35 };
36
37
38 CodeCell.prototype.select = function () {
39 IPython.Cell.prototype.select.apply(this);
40 this.code_mirror.focus();
41 };
42
43
44 CodeCell.prototype.append_pyout = function (data, n) {
45 var toinsert = $("<div/>").addClass("output_area output_pyout hbox monospace-font");
46 toinsert.append($('<div/>').
47 addClass('prompt output_prompt').
48 html('Out[' + n + ']:')
49 );
50 this.append_display_data(data, toinsert);
51 toinsert.children().last().addClass("box_flex1");
52 this.element.find("div.output").append(toinsert);
53 // If we just output latex, typeset it.
54 if (data["text/latex"] !== undefined) {
76 55 MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
77 56 };
78 } else if (data["image/svg+xml"] !== undefined) {
79 this.append_svg(data["image/svg+xml"], element);
80 } else if (data["image/png"] !== undefined) {
81 this.append_png(data["image/png"], element);
82 } else if (data["text/plain"] !== undefined) {
83 this.append_stream(data["text/plain"], element);
84 57 };
85 return element;
86 };
87 58
88 59
89 CodeCell.prototype.append_stream = function (data, element) {
90 element = element || this.element.find("div.output");
91 var toinsert = $("<div/>").addClass("output_area output_stream monospace-font");
92 toinsert.append($("<pre/>").addClass("monospace-font").html(fixConsole(data)));
93 element.append(toinsert);
94 return element;
95 };
60 CodeCell.prototype.append_pyerr = function (ename, evalue, tb) {
61 var s = '';
62 var len = tb.length;
63 for (var i=0; i<len; i++) {
64 s = s + tb[i] + '\n';
65 }
66 s = s + '\n';
67 this.append_stream(s);
68 };
96 69
97 70
98 CodeCell.prototype.append_svg = function (svg, element) {
99 element = element || this.element.find("div.output");
100 var toinsert = $("<div/>").addClass("output_area output_svg");
101 toinsert.append(svg);
102 element.append(toinsert);
103 return element;
104 };
71 CodeCell.prototype.append_display_data = function (data, element) {
72 if (data["text/latex"] !== undefined) {
73 this.append_latex(data["text/latex"], element);
74 // If it is undefined, then we just appended to div.output, which
75 // makes the latex visible and we can typeset it. The typesetting
76 // has to be done after the latex is on the page.
77 if (element === undefined) {
78 MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
79 };
80 } else if (data["image/svg+xml"] !== undefined) {
81 this.append_svg(data["image/svg+xml"], element);
82 } else if (data["image/png"] !== undefined) {
83 this.append_png(data["image/png"], element);
84 } else if (data["text/plain"] !== undefined) {
85 this.append_stream(data["text/plain"], element);
86 };
87 return element;
88 };
105 89
106 90
107 CodeCell.prototype.append_png = function (png, element) {
108 element = element || this.element.find("div.output");
109 var toinsert = $("<div/>").addClass("output_area output_png");
110 toinsert.append($("<img/>").attr('src','data:image/png;base64,'+png));
111 element.append(toinsert);
112 return element;
113 };
91 CodeCell.prototype.append_stream = function (data, element) {
92 element = element || this.element.find("div.output");
93 var toinsert = $("<div/>").addClass("output_area output_stream monospace-font");
94 toinsert.append($("<pre/>").addClass("monospace-font").html(utils.fixConsole(data)));
95 element.append(toinsert);
96 return element;
97 };
114 98
115 99
116 CodeCell.prototype.append_latex = function (latex, element) {
117 // This method cannot do the typesetting because the latex first has to
118 // be on the page.
119 element = element || this.element.find("div.output");
120 var toinsert = $("<div/>").addClass("output_area output_latex monospace-font");
121 toinsert.append(latex);
122 element.append(toinsert);
123 return element;
124 }
100 CodeCell.prototype.append_svg = function (svg, element) {
101 element = element || this.element.find("div.output");
102 var toinsert = $("<div/>").addClass("output_area output_svg");
103 toinsert.append(svg);
104 element.append(toinsert);
105 return element;
106 };
125 107
126 108
127 CodeCell.prototype.clear_output = function () {
128 this.element.find("div.output").html("");
129 };
109 CodeCell.prototype.append_png = function (png, element) {
110 element = element || this.element.find("div.output");
111 var toinsert = $("<div/>").addClass("output_area output_png");
112 toinsert.append($("<img/>").attr('src','data:image/png;base64,'+png));
113 element.append(toinsert);
114 return element;
115 };
130 116
131 117
132 CodeCell.prototype.collapse = function () {
133 this.element.find('div.output').hide();
134 };
118 CodeCell.prototype.append_latex = function (latex, element) {
119 // This method cannot do the typesetting because the latex first has to
120 // be on the page.
121 element = element || this.element.find("div.output");
122 var toinsert = $("<div/>").addClass("output_area output_latex monospace-font");
123 toinsert.append(latex);
124 element.append(toinsert);
125 return element;
126 }
135 127
136 128
137 CodeCell.prototype.expand = function () {
138 this.element.find('div.output').show();
139 };
129 CodeCell.prototype.clear_output = function () {
130 this.element.find("div.output").html("");
131 };
140 132
141 133
142 CodeCell.prototype.set_input_prompt = function (number) {
143 var n = number || ' ';
144 this.input_prompt_number = n
145 this.element.find('div.input_prompt').html('In&nbsp;[' + n + ']:');
146 };
134 CodeCell.prototype.collapse = function () {
135 this.element.find('div.output').hide();
136 };
147 137
148 138
149 CodeCell.prototype.get_code = function () {
150 return this.code_mirror.getValue();
151 };
139 CodeCell.prototype.expand = function () {
140 this.element.find('div.output').show();
141 };
152 142
153 143
154 CodeCell.prototype.set_code = function (code) {
155 return this.code_mirror.setValue(code);
156 };
144 CodeCell.prototype.set_input_prompt = function (number) {
145 var n = number || ' ';
146 this.input_prompt_number = n
147 this.element.find('div.input_prompt').html('In&nbsp;[' + n + ']:');
148 };
157 149
158 150
159 CodeCell.prototype.at_top = function () {
160 var cursor = this.code_mirror.getCursor();
161 if (cursor.line === 0) {
162 return true;
163 } else {
164 return false;
165 }
166 };
151 CodeCell.prototype.get_code = function () {
152 return this.code_mirror.getValue();
153 };
167 154
168 155
169 CodeCell.prototype.at_bottom = function () {
170 var cursor = this.code_mirror.getCursor();
171 if (cursor.line === (this.code_mirror.lineCount()-1)) {
172 return true;
173 } else {
174 return false;
175 }
176 };
156 CodeCell.prototype.set_code = function (code) {
157 return this.code_mirror.setValue(code);
158 };
177 159
178 160
179 CodeCell.prototype.fromJSON = function (data) {
180 if (data.cell_type === 'code') {
181 this.set_code(data.code);
182 this.set_input_prompt(data.prompt_number);
161 CodeCell.prototype.at_top = function () {
162 var cursor = this.code_mirror.getCursor();
163 if (cursor.line === 0) {
164 return true;
165 } else {
166 return false;
167 }
183 168 };
184 };
185 169
186 170
187 CodeCell.prototype.toJSON = function () {
188 return {
189 code : this.get_code(),
190 cell_type : 'code',
191 prompt_number : this.input_prompt_number
171 CodeCell.prototype.at_bottom = function () {
172 var cursor = this.code_mirror.getCursor();
173 if (cursor.line === (this.code_mirror.lineCount()-1)) {
174 return true;
175 } else {
176 return false;
177 }
192 178 };
193 };
194 179
195 180
181 CodeCell.prototype.fromJSON = function (data) {
182 if (data.cell_type === 'code') {
183 this.set_code(data.code);
184 this.set_input_prompt(data.prompt_number);
185 };
186 };
187
188
189 CodeCell.prototype.toJSON = function () {
190 return {
191 code : this.get_code(),
192 cell_type : 'code',
193 prompt_number : this.input_prompt_number
194 };
195 };
196
197 IPython.CodeCell = CodeCell;
198
199 return IPython;
200 }(IPython));
201
@@ -3,105 +3,113 b''
3 3 // Kernel
4 4 //============================================================================
5 5
6 var IPython = (function (IPython) {
6 7
7 var Kernel = function () {
8 this.kernel_id = null;
9 this.base_url = "/kernels";
10 this.kernel_url = null;
11 };
12
13
14 Kernel.prototype.get_msg = function (msg_type, content) {
15 var msg = {
16 header : {
17 msg_id : uuid(),
18 username : "bgranger",
19 session: this.session_id,
20 msg_type : msg_type
21 },
22 content : content,
23 parent_header : {}
8 var utils = IPython.utils;
9
10 var Kernel = function () {
11 this.kernel_id = null;
12 this.base_url = "/kernels";
13 this.kernel_url = null;
14 };
15
16
17 Kernel.prototype.get_msg = function (msg_type, content) {
18 var msg = {
19 header : {
20 msg_id : utils.uuid(),
21 username : "bgranger",
22 session: this.session_id,
23 msg_type : msg_type
24 },
25 content : content,
26 parent_header : {}
27 };
28 return msg;
29 }
30
31 Kernel.prototype.start_kernel = function (callback, context) {
32 var that = this;
33 $.post(this.base_url,
34 function (kernel_id) {
35 that._handle_start_kernel(kernel_id, callback, context);
36 },
37 'json'
38 );
39 };
40
41
42 Kernel.prototype._handle_start_kernel = function (kernel_id, callback, context) {
43 this.kernel_id = kernel_id;
44 this.kernel_url = this.base_url + "/" + this.kernel_id;
45 this._start_channels();
46 callback.call(context);
47 };
48
49
50 Kernel.prototype._start_channels = function () {
51 var ws_url = "ws://127.0.0.1:8888" + this.kernel_url;
52 this.shell_channel = new WebSocket(ws_url + "/shell");
53 this.iopub_channel = new WebSocket(ws_url + "/iopub");
54 }
55
56
57 Kernel.prototype.execute = function (code) {
58 var content = {
59 code : code,
60 silent : false,
61 user_variables : [],
62 user_expressions : {}
63 };
64 var msg = this.get_msg("execute_request", content);
65 this.shell_channel.send(JSON.stringify(msg));
66 return msg.header.msg_id;
67 }
68
69
70 Kernel.prototype.interrupt = function () {
71 $.post(this.kernel_url + "/interrupt");
24 72 };
25 return msg;
26 }
27
28 Kernel.prototype.start_kernel = function (callback, context) {
29 var that = this;
30 $.post(this.base_url,
31 function (kernel_id) {
32 that._handle_start_kernel(kernel_id, callback, context);
33 },
34 'json'
35 );
36 };
37
38
39 Kernel.prototype._handle_start_kernel = function (kernel_id, callback, context) {
40 this.kernel_id = kernel_id;
41 this.kernel_url = this.base_url + "/" + this.kernel_id;
42 this._start_channels();
43 callback.call(context);
44 };
45
46
47 Kernel.prototype._start_channels = function () {
48 var ws_url = "ws://127.0.0.1:8888" + this.kernel_url;
49 this.shell_channel = new WebSocket(ws_url + "/shell");
50 this.iopub_channel = new WebSocket(ws_url + "/iopub");
51 }
52
53
54 Kernel.prototype.execute = function (code) {
55 var content = {
56 code : code,
57 silent : false,
58 user_variables : [],
59 user_expressions : {}
73
74
75 Kernel.prototype.restart = function () {
76 this.status_restarting();
77 url = this.kernel_url + "/restart"
78 var that = this;
79 $.post(url, function (kernel_id) {
80 console.log("Kernel restarted: " + kernel_id);
81 that.kernel_id = kernel_id;
82 that.kernel_url = that.base_url + "/" + that.kernel_id;
83 that.status_idle();
84 }, 'json');
60 85 };
61 var msg = this.get_msg("execute_request", content);
62 this.shell_channel.send(JSON.stringify(msg));
63 return msg.header.msg_id;
64 }
65
66
67 Kernel.prototype.interrupt = function () {
68 $.post(this.kernel_url + "/interrupt");
69 };
70
71
72 Kernel.prototype.restart = function () {
73 this.status_restarting();
74 url = this.kernel_url + "/restart"
75 var that = this;
76 $.post(url, function (kernel_id) {
77 console.log("Kernel restarted: " + kernel_id);
78 that.kernel_id = kernel_id;
79 that.kernel_url = that.base_url + "/" + that.kernel_id;
80 that.status_idle();
81 }, 'json');
82 };
83
84
85 Kernel.prototype.status_busy = function () {
86 $("#kernel_status").removeClass("status_idle");
87 $("#kernel_status").removeClass("status_restarting");
88 $("#kernel_status").addClass("status_busy");
89 $("#kernel_status").text("Busy");
90 };
91
92
93 Kernel.prototype.status_idle = function () {
94 $("#kernel_status").removeClass("status_busy");
95 $("#kernel_status").removeClass("status_restarting");
96 $("#kernel_status").addClass("status_idle");
97 $("#kernel_status").text("Idle");
98 };
99
100 Kernel.prototype.status_restarting = function () {
101 $("#kernel_status").removeClass("status_busy");
102 $("#kernel_status").removeClass("status_idle");
103 $("#kernel_status").addClass("status_restarting");
104 $("#kernel_status").text("Restarting");
105 };
106 86
107 87
88 Kernel.prototype.status_busy = function () {
89 $("#kernel_status").removeClass("status_idle");
90 $("#kernel_status").removeClass("status_restarting");
91 $("#kernel_status").addClass("status_busy");
92 $("#kernel_status").text("Busy");
93 };
94
95
96 Kernel.prototype.status_idle = function () {
97 $("#kernel_status").removeClass("status_busy");
98 $("#kernel_status").removeClass("status_restarting");
99 $("#kernel_status").addClass("status_idle");
100 $("#kernel_status").text("Idle");
101 };
102
103 Kernel.prototype.status_restarting = function () {
104 $("#kernel_status").removeClass("status_busy");
105 $("#kernel_status").removeClass("status_idle");
106 $("#kernel_status").addClass("status_restarting");
107 $("#kernel_status").text("Restarting");
108 };
109
110 IPython.Kernel = Kernel;
111
112 return IPython;
113
114 }(IPython));
115
@@ -1,4 +1,23 b''
1 var IPYTHON = {};
1 var IPython = IPython || {};
2
3 IPython.namespace = function (ns_string) {
4 var parts = ns_string.split('.'),
5 parent = IPython,
6 i;
7
8 // String redundant leading global
9 if (parts[0] === "IPython") {
10 parts = parts.slice(1);
11 }
12
13 for (i=0; i<parts.length; i+=1) {
14 // Create property if it doesn't exist
15 if (typeof parent[parts[i]] === "undefined") {
16 parent[parts[i]] == {};
17 }
18 }
19 return parent;
20 };
2 21
3 22
4 23
This diff has been collapsed as it changes many lines, (853 lines changed) Show them Hide them
@@ -3,506 +3,513 b''
3 3 // Notebook
4 4 //============================================================================
5 5
6 var IPython = (function (IPython) {
7
8 var Notebook = function (selector) {
9 this.element = $(selector);
10 this.element.scroll();
11 this.element.data("notebook", this);
12 this.next_prompt_number = 1;
13 this.kernel = null;
14 this.msg_cell_map = {};
15 this.filename = null;
16 this.notebook_load_re = /%notebook load/
17 this.notebook_save_re = /%notebook save/
18 this.notebook_filename_re = /(\w)+.ipynb/
19 this.bind_events();
20 this.start_kernel();
21 };
6 22
7 var Notebook = function (selector) {
8 this.element = $(selector);
9 this.element.scroll();
10 this.element.data("notebook", this);
11 this.next_prompt_number = 1;
12 this.kernel = null;
13 this.msg_cell_map = {};
14 this.filename = null;
15 this.notebook_load_re = /%notebook load/
16 this.notebook_save_re = /%notebook save/
17 this.notebook_filename_re = /(\w)+.ipynb/
18 this.bind_events();
19 this.start_kernel();
20 };
21
22
23 Notebook.prototype.bind_events = function () {
24 var that = this;
25 $(document).keydown(function (event) {
26 // console.log(event);
27 if (event.which === 38) {
28 var cell = that.selected_cell();
29 if (cell.at_top()) {
30 event.preventDefault();
31 that.select_prev();
32 };
33 } else if (event.which === 40) {
34 var cell = that.selected_cell();
35 if (cell.at_bottom()) {
36 event.preventDefault();
37 that.select_next();
38 };
39 } else if (event.which === 13 && event.shiftKey) {
40 // The focus is not quite working here.
41 var cell = that.selected_cell();
42 var cell_index = that.find_cell_index(cell);
43 // TODO: the logic here needs to be moved into appropriate
44 // methods of Notebook.
45 if (cell instanceof CodeCell) {
46 event.preventDefault();
47 cell.clear_output();
48 var code = cell.get_code();
49 if (that.notebook_load_re.test(code)) {
50 var code_parts = code.split(' ');
51 if (code_parts.length === 3) {
52 that.load_notebook(code_parts[2]);
53 };
54 } else if (that.notebook_save_re.test(code)) {
55 var code_parts = code.split(' ');
56 if (code_parts.length === 3) {
57 that.save_notebook(code_parts[2]);
23
24 Notebook.prototype.bind_events = function () {
25 var that = this;
26 $(document).keydown(function (event) {
27 // console.log(event);
28 if (event.which === 38) {
29 var cell = that.selected_cell();
30 if (cell.at_top()) {
31 event.preventDefault();
32 that.select_prev();
33 };
34 } else if (event.which === 40) {
35 var cell = that.selected_cell();
36 if (cell.at_bottom()) {
37 event.preventDefault();
38 that.select_next();
39 };
40 } else if (event.which === 13 && event.shiftKey) {
41 // The focus is not quite working here.
42 var cell = that.selected_cell();
43 var cell_index = that.find_cell_index(cell);
44 // TODO: the logic here needs to be moved into appropriate
45 // methods of Notebook.
46 if (cell instanceof IPython.CodeCell) {
47 event.preventDefault();
48 cell.clear_output();
49 var code = cell.get_code();
50 if (that.notebook_load_re.test(code)) {
51 var code_parts = code.split(' ');
52 if (code_parts.length === 3) {
53 that.load_notebook(code_parts[2]);
54 };
55 } else if (that.notebook_save_re.test(code)) {
56 var code_parts = code.split(' ');
57 if (code_parts.length === 3) {
58 that.save_notebook(code_parts[2]);
59 } else {
60 that.save_notebook()
61 };
58 62 } else {
59 that.save_notebook()
63 var msg_id = that.kernel.execute(cell.get_code());
64 that.msg_cell_map[msg_id] = cell.cell_id;
60 65 };
66 } else if (cell instanceof IPython.TextCell) {
67 event.preventDefault();
68 cell.render();
69 }
70 if (cell_index === (that.ncells()-1)) {
71 that.insert_code_cell_after();
61 72 } else {
62 var msg_id = that.kernel.execute(cell.get_code());
63 that.msg_cell_map[msg_id] = cell.cell_id;
73 that.select(cell_index+1);
64 74 };
65 } else if (cell instanceof TextCell) {
66 event.preventDefault();
67 cell.render();
68 }
69 if (cell_index === (that.ncells()-1)) {
70 that.insert_code_cell_after();
71 } else {
72 that.select(cell_index+1);
73 75 };
74 };
75 });
76 };
76 });
77 };
77 78
78 79
79 // Cell indexing, retrieval, etc.
80 // Cell indexing, retrieval, etc.
80 81
81 82
82 Notebook.prototype.cell_elements = function () {
83 return this.element.children("div.cell");
84 }
83 Notebook.prototype.cell_elements = function () {
84 return this.element.children("div.cell");
85 }
85 86
86 87
87 Notebook.prototype.ncells = function (cell) {
88 return this.cell_elements().length;
89 }
88 Notebook.prototype.ncells = function (cell) {
89 return this.cell_elements().length;
90 }
90 91
91 92
92 // TODO: we are often calling cells as cells()[i], which we should optimize
93 // to cells(i) or a new method.
94 Notebook.prototype.cells = function () {
95 return this.cell_elements().toArray().map(function (e) {
96 return $(e).data("cell");
97 });
98 }
93 // TODO: we are often calling cells as cells()[i], which we should optimize
94 // to cells(i) or a new method.
95 Notebook.prototype.cells = function () {
96 return this.cell_elements().toArray().map(function (e) {
97 return $(e).data("cell");
98 });
99 }
99 100
100 101
101 Notebook.prototype.find_cell_index = function (cell) {
102 var result = null;
103 this.cell_elements().filter(function (index) {
104 if ($(this).data("cell") === cell) {
105 result = index;
106 };
107 });
108 return result;
109 };
102 Notebook.prototype.find_cell_index = function (cell) {
103 var result = null;
104 this.cell_elements().filter(function (index) {
105 if ($(this).data("cell") === cell) {
106 result = index;
107 };
108 });
109 return result;
110 };
110 111
111 112
112 Notebook.prototype.index_or_selected = function (index) {
113 return index || this.selected_index() || 0;
114 }
113 Notebook.prototype.index_or_selected = function (index) {
114 return index || this.selected_index() || 0;
115 }
115 116
116 117
117 Notebook.prototype.select = function (index) {
118 if (index !== undefined && index >= 0 && index < this.ncells()) {
119 if (this.selected_index() !== null) {
120 this.selected_cell().unselect();
118 Notebook.prototype.select = function (index) {
119 if (index !== undefined && index >= 0 && index < this.ncells()) {
120 if (this.selected_index() !== null) {
121 this.selected_cell().unselect();
122 };
123 this.cells()[index].select();
121 124 };
122 this.cells()[index].select();
123 };
124 return this;
125 };
126
127
128 Notebook.prototype.select_next = function () {
129 var index = this.selected_index();
130 if (index !== null && index >= 0 && (index+1) < this.ncells()) {
131 this.select(index+1);
125 return this;
132 126 };
133 return this;
134 };
135 127
136 128
137 Notebook.prototype.select_prev = function () {
138 var index = this.selected_index();
139 if (index !== null && index >= 0 && (index-1) < this.ncells()) {
140 this.select(index-1);
129 Notebook.prototype.select_next = function () {
130 var index = this.selected_index();
131 if (index !== null && index >= 0 && (index+1) < this.ncells()) {
132 this.select(index+1);
133 };
134 return this;
141 135 };
142 return this;
143 };
144 136
145 137
146 Notebook.prototype.selected_index = function () {
147 var result = null;
148 this.cell_elements().filter(function (index) {
149 if ($(this).data("cell").selected === true) {
150 result = index;
151 };
152 });
153 return result;
154 };
155
156
157 Notebook.prototype.cell_for_msg = function (msg_id) {
158 var cell_id = this.msg_cell_map[msg_id];
159 var result = null;
160 this.cell_elements().filter(function (index) {
161 cell = $(this).data("cell");
162 if (cell.cell_id === cell_id) {
163 result = cell;
138 Notebook.prototype.select_prev = function () {
139 var index = this.selected_index();
140 if (index !== null && index >= 0 && (index-1) < this.ncells()) {
141 this.select(index-1);
164 142 };
165 });
166 return result;
167 };
143 return this;
144 };
168 145
169 146
170 Notebook.prototype.selected_cell = function () {
171 return this.cell_elements().eq(this.selected_index()).data("cell");
172 }
147 Notebook.prototype.selected_index = function () {
148 var result = null;
149 this.cell_elements().filter(function (index) {
150 if ($(this).data("cell").selected === true) {
151 result = index;
152 };
153 });
154 return result;
155 };
173 156
174 157
175 // Cell insertion, deletion and moving.
158 Notebook.prototype.cell_for_msg = function (msg_id) {
159 var cell_id = this.msg_cell_map[msg_id];
160 var result = null;
161 this.cell_elements().filter(function (index) {
162 cell = $(this).data("cell");
163 if (cell.cell_id === cell_id) {
164 result = cell;
165 };
166 });
167 return result;
168 };
176 169
177 170
178 Notebook.prototype.delete_cell = function (index) {
179 var i = index || this.selected_index();
180 if (i !== null && i >= 0 && i < this.ncells()) {
181 this.cell_elements().eq(i).remove();
182 if (i === (this.ncells())) {
183 this.select(i-1);
184 } else {
185 this.select(i);
186 };
187 };
188 return this;
189 };
171 Notebook.prototype.selected_cell = function () {
172 return this.cell_elements().eq(this.selected_index()).data("cell");
173 }
190 174
191 175
192 Notebook.prototype.append_cell = function (cell) {
193 this.element.append(cell.element);
194 return this;
195 };
176 // Cell insertion, deletion and moving.
196 177
197 178
198 Notebook.prototype.insert_cell_after = function (cell, index) {
199 var ncells = this.ncells();
200 if (ncells === 0) {
201 this.append_cell(cell);
179 Notebook.prototype.delete_cell = function (index) {
180 var i = index || this.selected_index();
181 if (i !== null && i >= 0 && i < this.ncells()) {
182 this.cell_elements().eq(i).remove();
183 if (i === (this.ncells())) {
184 this.select(i-1);
185 } else {
186 this.select(i);
187 };
188 };
202 189 return this;
203 190 };
204 if (index >= 0 && index < ncells) {
205 this.cell_elements().eq(index).after(cell.element);
206 };
207 return this
208 };
209 191
210 192
211 Notebook.prototype.insert_cell_before = function (cell, index) {
212 var ncells = this.ncells();
213 if (ncells === 0) {
214 this.append_cell(cell);
193 Notebook.prototype.append_cell = function (cell) {
194 this.element.append(cell.element);
215 195 return this;
216 196 };
217 if (index >= 0 && index < ncells) {
218 this.cell_elements().eq(index).before(cell.element);
219 };
220 return this;
221 };
222
223
224 Notebook.prototype.move_cell_up = function (index) {
225 var i = index || this.selected_index();
226 if (i !== null && i < this.ncells() && i > 0) {
227 var pivot = this.cell_elements().eq(i-1);
228 var tomove = this.cell_elements().eq(i);
229 if (pivot !== null && tomove !== null) {
230 tomove.detach();
231 pivot.before(tomove);
232 this.select(i-1);
197
198
199 Notebook.prototype.insert_cell_after = function (cell, index) {
200 var ncells = this.ncells();
201 if (ncells === 0) {
202 this.append_cell(cell);
203 return this;
233 204 };
205 if (index >= 0 && index < ncells) {
206 this.cell_elements().eq(index).after(cell.element);
207 };
208 return this
234 209 };
235 return this;
236 }
237
238
239 Notebook.prototype.move_cell_down = function (index) {
240 var i = index || this.selected_index();
241 if (i !== null && i < (this.ncells()-1) && i >= 0) {
242 var pivot = this.cell_elements().eq(i+1)
243 var tomove = this.cell_elements().eq(i)
244 if (pivot !== null && tomove !== null) {
245 tomove.detach();
246 pivot.after(tomove);
247 this.select(i+1);
210
211
212 Notebook.prototype.insert_cell_before = function (cell, index) {
213 var ncells = this.ncells();
214 if (ncells === 0) {
215 this.append_cell(cell);
216 return this;
217 };
218 if (index >= 0 && index < ncells) {
219 this.cell_elements().eq(index).before(cell.element);
248 220 };
221 return this;
249 222 };
250 return this;
251 }
252
253
254 Notebook.prototype.sort_cells = function () {
255 var ncells = this.ncells();
256 var sindex = this.selected_index();
257 var swapped;
258 do {
259 swapped = false
260 for (var i=1; i<ncells; i++) {
261 current = this.cell_elements().eq(i).data("cell");
262 previous = this.cell_elements().eq(i-1).data("cell");
263 if (previous.input_prompt_number > current.input_prompt_number) {
264 this.move_cell_up(i);
265 swapped = true;
223
224
225 Notebook.prototype.move_cell_up = function (index) {
226 var i = index || this.selected_index();
227 if (i !== null && i < this.ncells() && i > 0) {
228 var pivot = this.cell_elements().eq(i-1);
229 var tomove = this.cell_elements().eq(i);
230 if (pivot !== null && tomove !== null) {
231 tomove.detach();
232 pivot.before(tomove);
233 this.select(i-1);
266 234 };
267 235 };
268 } while (swapped);
269 this.select(sindex);
270 return this;
271 };
272
273
274 Notebook.prototype.insert_code_cell_before = function (index) {
275 // TODO: Bounds check for i
276 var i = this.index_or_selected(index);
277 var cell = new CodeCell(this);
278 cell.set_input_prompt(this.next_prompt_number);
279 this.next_prompt_number = this.next_prompt_number + 1;
280 this.insert_cell_before(cell, i);
281 this.select(this.find_cell_index(cell));
282 return this;
283 }
284
285
286 Notebook.prototype.insert_code_cell_after = function (index) {
287 // TODO: Bounds check for i
288 var i = this.index_or_selected(index);
289 var cell = new CodeCell(this);
290 cell.set_input_prompt(this.next_prompt_number);
291 this.next_prompt_number = this.next_prompt_number + 1;
292 this.insert_cell_after(cell, i);
293 this.select(this.find_cell_index(cell));
294 return this;
295 }
296
297
298 Notebook.prototype.insert_text_cell_before = function (index) {
299 // TODO: Bounds check for i
300 var i = this.index_or_selected(index);
301 var cell = new TextCell(this);
302 cell.config_mathjax();
303 this.insert_cell_before(cell, i);
304 this.select(this.find_cell_index(cell));
305 return this;
306 }
307
308
309 Notebook.prototype.insert_text_cell_after = function (index) {
310 // TODO: Bounds check for i
311 var i = this.index_or_selected(index);
312 var cell = new TextCell(this);
313 cell.config_mathjax();
314 this.insert_cell_after(cell, i);
315 this.select(this.find_cell_index(cell));
316 return this;
317 }
318
319
320 Notebook.prototype.text_to_code = function (index) {
321 // TODO: Bounds check for i
322 var i = this.index_or_selected(index);
323 var source_element = this.cell_elements().eq(i);
324 var source_cell = source_element.data("cell");
325 if (source_cell instanceof TextCell) {
326 this.insert_code_cell_after(i);
327 var target_cell = this.cells()[i+1];
328 target_cell.set_code(source_cell.get_text());
329 source_element.remove();
330 };
331 };
332
333
334 Notebook.prototype.code_to_text = function (index) {
335 // TODO: Bounds check for i
336 var i = this.index_or_selected(index);
337 var source_element = this.cell_elements().eq(i);
338 var source_cell = source_element.data("cell");
339 if (source_cell instanceof CodeCell) {
340 this.insert_text_cell_after(i);
341 var target_cell = this.cells()[i+1];
342 var text = source_cell.get_code();
343 if (text === "") {text = target_cell.placeholder;};
344 target_cell.set_text(text);
345 source_element.remove();
346 target_cell.edit();
236 return this;
237 }
238
239
240 Notebook.prototype.move_cell_down = function (index) {
241 var i = index || this.selected_index();
242 if (i !== null && i < (this.ncells()-1) && i >= 0) {
243 var pivot = this.cell_elements().eq(i+1)
244 var tomove = this.cell_elements().eq(i)
245 if (pivot !== null && tomove !== null) {
246 tomove.detach();
247 pivot.after(tomove);
248 this.select(i+1);
249 };
250 };
251 return this;
252 }
253
254
255 Notebook.prototype.sort_cells = function () {
256 var ncells = this.ncells();
257 var sindex = this.selected_index();
258 var swapped;
259 do {
260 swapped = false
261 for (var i=1; i<ncells; i++) {
262 current = this.cell_elements().eq(i).data("cell");
263 previous = this.cell_elements().eq(i-1).data("cell");
264 if (previous.input_prompt_number > current.input_prompt_number) {
265 this.move_cell_up(i);
266 swapped = true;
267 };
268 };
269 } while (swapped);
270 this.select(sindex);
271 return this;
347 272 };
348 };
349 273
350 274
351 // Cell collapsing
275 Notebook.prototype.insert_code_cell_before = function (index) {
276 // TODO: Bounds check for i
277 var i = this.index_or_selected(index);
278 var cell = new IPython.CodeCell(this);
279 cell.set_input_prompt(this.next_prompt_number);
280 this.next_prompt_number = this.next_prompt_number + 1;
281 this.insert_cell_before(cell, i);
282 this.select(this.find_cell_index(cell));
283 return this;
284 }
352 285
353 Notebook.prototype.collapse = function (index) {
354 var i = this.index_or_selected(index);
355 this.cells()[i].collapse();
356 };
357 286
287 Notebook.prototype.insert_code_cell_after = function (index) {
288 // TODO: Bounds check for i
289 var i = this.index_or_selected(index);
290 var cell = new IPython.CodeCell(this);
291 cell.set_input_prompt(this.next_prompt_number);
292 this.next_prompt_number = this.next_prompt_number + 1;
293 this.insert_cell_after(cell, i);
294 this.select(this.find_cell_index(cell));
295 return this;
296 }
358 297
359 Notebook.prototype.expand = function (index) {
360 var i = this.index_or_selected(index);
361 this.cells()[i].expand();
362 };
363 298
299 Notebook.prototype.insert_text_cell_before = function (index) {
300 // TODO: Bounds check for i
301 var i = this.index_or_selected(index);
302 var cell = new IPython.TextCell(this);
303 cell.config_mathjax();
304 this.insert_cell_before(cell, i);
305 this.select(this.find_cell_index(cell));
306 return this;
307 }
364 308
365 // Kernel related things
366 309
367 Notebook.prototype.start_kernel = function () {
368 this.kernel = new Kernel();
369 this.kernel.start_kernel(this._kernel_started, this);
370 };
310 Notebook.prototype.insert_text_cell_after = function (index) {
311 // TODO: Bounds check for i
312 var i = this.index_or_selected(index);
313 var cell = new IPython.TextCell(this);
314 cell.config_mathjax();
315 this.insert_cell_after(cell, i);
316 this.select(this.find_cell_index(cell));
317 return this;
318 }
371 319
372 320
373 Notebook.prototype._kernel_started = function () {
374 console.log("Kernel started: ", this.kernel.kernel_id);
375 var that = this;
321 Notebook.prototype.text_to_code = function (index) {
322 // TODO: Bounds check for i
323 var i = this.index_or_selected(index);
324 var source_element = this.cell_elements().eq(i);
325 var source_cell = source_element.data("cell");
326 if (source_cell instanceof IPython.TextCell) {
327 this.insert_code_cell_after(i);
328 var target_cell = this.cells()[i+1];
329 target_cell.set_code(source_cell.get_text());
330 source_element.remove();
331 };
332 };
376 333
377 this.kernel.shell_channel.onmessage = function (e) {
378 reply = $.parseJSON(e.data);
379 // console.log(reply);
380 var msg_type = reply.header.msg_type;
381 var cell = that.cell_for_msg(reply.parent_header.msg_id);
382 if (msg_type === "execute_reply") {
383 cell.set_input_prompt(reply.content.execution_count);
334
335 Notebook.prototype.code_to_text = function (index) {
336 // TODO: Bounds check for i
337 var i = this.index_or_selected(index);
338 var source_element = this.cell_elements().eq(i);
339 var source_cell = source_element.data("cell");
340 if (source_cell instanceof IPython.CodeCell) {
341 this.insert_text_cell_after(i);
342 var target_cell = this.cells()[i+1];
343 var text = source_cell.get_code();
344 if (text === "") {text = target_cell.placeholder;};
345 target_cell.set_text(text);
346 source_element.remove();
347 target_cell.edit();
384 348 };
385 349 };
386 350
387 this.kernel.iopub_channel.onmessage = function (e) {
388 reply = $.parseJSON(e.data);
389 var content = reply.content;
390 console.log(reply);
391 var msg_type = reply.header.msg_type;
392 var cell = that.cell_for_msg(reply.parent_header.msg_id);
393 if (msg_type === "stream") {
394 cell.expand();
395 cell.append_stream(content.data + "\n");
396 } else if (msg_type === "display_data") {
397 cell.expand();
398 cell.append_display_data(content.data);
399 } else if (msg_type === "pyout") {
400 cell.expand();
401 cell.append_pyout(content.data, content.execution_count)
402 } else if (msg_type === "pyerr") {
403 cell.expand();
404 cell.append_pyerr(content.ename, content.evalue, content.traceback);
405 } else if (msg_type === "status") {
406 if (content.execution_state === "busy") {
407 that.kernel.status_busy();
408 } else if (content.execution_state === "idle") {
409 that.kernel.status_idle();
410 };
411 }
351
352 // Cell collapsing
353
354 Notebook.prototype.collapse = function (index) {
355 var i = this.index_or_selected(index);
356 this.cells()[i].collapse();
412 357 };
413 };
414 358
415 359
416 // Persistance and loading
360 Notebook.prototype.expand = function (index) {
361 var i = this.index_or_selected(index);
362 this.cells()[i].expand();
363 };
364
417 365
366 // Kernel related things
418 367
419 Notebook.prototype.fromJSON = function (data) {
420 var ncells = this.ncells();
421 for (var i=0; i<ncells; i++) {
422 // Always delete cell 0 as they get renumbered as they are deleted.
423 this.delete_cell(0);
368 Notebook.prototype.start_kernel = function () {
369 this.kernel = new IPython.Kernel();
370 this.kernel.start_kernel(this._kernel_started, this);
424 371 };
425 var new_cells = data.cells;
426 ncells = new_cells.length;
427 var cell_data = null;
428 for (var i=0; i<ncells; i++) {
429 cell_data = new_cells[i];
430 if (cell_data.cell_type == 'code') {
431 this.insert_code_cell_after();
432 this.selected_cell().fromJSON(cell_data);
433 } else if (cell_data.cell_type === 'text') {
434 this.insert_text_cell_after();
435 this.selected_cell().fromJSON(cell_data);
372
373
374 Notebook.prototype._kernel_started = function () {
375 console.log("Kernel started: ", this.kernel.kernel_id);
376 var that = this;
377
378 this.kernel.shell_channel.onmessage = function (e) {
379 reply = $.parseJSON(e.data);
380 // console.log(reply);
381 var msg_type = reply.header.msg_type;
382 var cell = that.cell_for_msg(reply.parent_header.msg_id);
383 if (msg_type === "execute_reply") {
384 cell.set_input_prompt(reply.content.execution_count);
385 };
386 };
387
388 this.kernel.iopub_channel.onmessage = function (e) {
389 reply = $.parseJSON(e.data);
390 var content = reply.content;
391 // console.log(reply);
392 var msg_type = reply.header.msg_type;
393 var cell = that.cell_for_msg(reply.parent_header.msg_id);
394 if (msg_type === "stream") {
395 cell.expand();
396 cell.append_stream(content.data + "\n");
397 } else if (msg_type === "display_data") {
398 cell.expand();
399 cell.append_display_data(content.data);
400 } else if (msg_type === "pyout") {
401 cell.expand();
402 cell.append_pyout(content.data, content.execution_count)
403 } else if (msg_type === "pyerr") {
404 cell.expand();
405 cell.append_pyerr(content.ename, content.evalue, content.traceback);
406 } else if (msg_type === "status") {
407 if (content.execution_state === "busy") {
408 that.kernel.status_busy();
409 } else if (content.execution_state === "idle") {
410 that.kernel.status_idle();
411 };
412 }
436 413 };
437 414 };
438 };
439 415
440 416
441 Notebook.prototype.toJSON = function () {
442 var cells = this.cells();
443 var ncells = cells.length;
444 cell_array = new Array(ncells);
445 for (var i=0; i<ncells; i++) {
446 cell_array[i] = cells[i].toJSON();
447 };
448 json = {
449 cells : cell_array
417 // Persistance and loading
418
419
420 Notebook.prototype.fromJSON = function (data) {
421 var ncells = this.ncells();
422 for (var i=0; i<ncells; i++) {
423 // Always delete cell 0 as they get renumbered as they are deleted.
424 this.delete_cell(0);
425 };
426 var new_cells = data.cells;
427 ncells = new_cells.length;
428 var cell_data = null;
429 for (var i=0; i<ncells; i++) {
430 cell_data = new_cells[i];
431 if (cell_data.cell_type == 'code') {
432 this.insert_code_cell_after();
433 this.selected_cell().fromJSON(cell_data);
434 } else if (cell_data.cell_type === 'text') {
435 this.insert_text_cell_after();
436 this.selected_cell().fromJSON(cell_data);
437 };
438 };
450 439 };
451 return json
452 };
453
454
455 Notebook.prototype.test_filename = function (filename) {
456 if (this.notebook_filename_re.test(filename)) {
457 return true;
458 } else {
459 var bad_filename = $('<div/>');
460 bad_filename.html(
461 "The filename you entered (" + filename + ") is not valid. Notebook filenames must have the following form: foo.ipynb"
462 );
463 bad_filename.dialog({title: 'Invalid filename', modal: true});
464 return false;
440
441
442 Notebook.prototype.toJSON = function () {
443 var cells = this.cells();
444 var ncells = cells.length;
445 cell_array = new Array(ncells);
446 for (var i=0; i<ncells; i++) {
447 cell_array[i] = cells[i].toJSON();
448 };
449 json = {
450 cells : cell_array
451 };
452 return json
465 453 };
466 };
467
468 Notebook.prototype.save_notebook = function (filename) {
469 this.filename = filename || this.filename || '';
470 if (this.filename === '') {
471 var no_filename = $('<div/>');
472 no_filename.html(
473 "This notebook has no filename, please specify a filename of the form: foo.ipynb"
474 );
475 no_filename.dialog({title: 'Missing filename', modal: true});
476 return;
477 }
478 if (!this.test_filename(this.filename)) {return;}
479 var thedata = this.toJSON();
480 var settings = {
481 processData : false,
482 cache : false,
483 type : "PUT",
484 data : JSON.stringify(thedata),
485 success : function (data, status, xhr) {console.log(data);}
454
455
456 Notebook.prototype.test_filename = function (filename) {
457 if (this.notebook_filename_re.test(filename)) {
458 return true;
459 } else {
460 var bad_filename = $('<div/>');
461 bad_filename.html(
462 "The filename you entered (" + filename + ") is not valid. Notebook filenames must have the following form: foo.ipynb"
463 );
464 bad_filename.dialog({title: 'Invalid filename', modal: true});
465 return false;
466 };
486 467 };
487 $.ajax("/notebooks/" + this.filename, settings);
488 };
489
490
491 Notebook.prototype.load_notebook = function (filename) {
492 if (!this.test_filename(filename)) {return;}
493 var that = this;
494 // We do the call with settings so we can set cache to false.
495 var settings = {
496 processData : false,
497 cache : false,
498 type : "GET",
499 dataType : "json",
500 success : function (data, status, xhr) {
501 that.fromJSON(data);
502 that.filename = filename;
503 that.kernel.restart();
504 }
468
469 Notebook.prototype.save_notebook = function (filename) {
470 this.filename = filename || this.filename || '';
471 if (this.filename === '') {
472 var no_filename = $('<div/>');
473 no_filename.html(
474 "This notebook has no filename, please specify a filename of the form: foo.ipynb"
475 );
476 no_filename.dialog({title: 'Missing filename', modal: true});
477 return;
478 }
479 if (!this.test_filename(this.filename)) {return;}
480 var thedata = this.toJSON();
481 var settings = {
482 processData : false,
483 cache : false,
484 type : "PUT",
485 data : JSON.stringify(thedata),
486 success : function (data, status, xhr) {console.log(data);}
487 };
488 $.ajax("/notebooks/" + this.filename, settings);
505 489 };
506 $.ajax("/notebooks/" + filename, settings);
507 }
490
491
492 Notebook.prototype.load_notebook = function (filename) {
493 if (!this.test_filename(filename)) {return;}
494 var that = this;
495 // We do the call with settings so we can set cache to false.
496 var settings = {
497 processData : false,
498 cache : false,
499 type : "GET",
500 dataType : "json",
501 success : function (data, status, xhr) {
502 that.fromJSON(data);
503 that.filename = filename;
504 that.kernel.restart();
505 }
506 };
507 $.ajax("/notebooks/" + filename, settings);
508 }
509
510 IPython.Notebook = Notebook;
511
512 return IPython;
513
514 }(IPython));
508 515
@@ -20,43 +20,43 b' $(document).ready(function () {'
20 20 }
21 21 });
22 22
23 IPYTHON.notebook = new Notebook('div.notebook');
24 IPYTHON.notebook.insert_code_cell_after();
23 IPython.notebook = new IPython.Notebook('div.notebook');
24 IPython.notebook.insert_code_cell_after();
25 25
26 26 $("#menu_tabs").tabs();
27 27
28 28 $("#help_toolbar").buttonset();
29 29
30 30 $("#kernel_toolbar").buttonset();
31 $("#interrupt_kernel").click(function () {IPYTHON.notebook.kernel.interrupt();});
32 $("#restart_kernel").click(function () {IPYTHON.notebook.kernel.restart();});
31 $("#interrupt_kernel").click(function () {IPython.notebook.kernel.interrupt();});
32 $("#restart_kernel").click(function () {IPython.notebook.kernel.restart();});
33 33 $("#kernel_status").addClass("status_idle");
34 34
35 35 $("#move_cell").buttonset();
36 36 $("#move_up").button("option", "icons", {primary:"ui-icon-arrowthick-1-n"});
37 37 $("#move_up").button("option", "text", false);
38 $("#move_up").click(function () {IPYTHON.notebook.move_cell_up();});
38 $("#move_up").click(function () {IPython.notebook.move_cell_up();});
39 39 $("#move_down").button("option", "icons", {primary:"ui-icon-arrowthick-1-s"});
40 40 $("#move_down").button("option", "text", false);
41 $("#move_down").click(function () {IPYTHON.notebook.move_cell_down();});
41 $("#move_down").click(function () {IPython.notebook.move_cell_down();});
42 42
43 43 $("#insert_delete").buttonset();
44 $("#insert_cell_before").click(function () {IPYTHON.notebook.insert_code_cell_before();});
45 $("#insert_cell_after").click(function () {IPYTHON.notebook.insert_code_cell_after();});
44 $("#insert_cell_before").click(function () {IPython.notebook.insert_code_cell_before();});
45 $("#insert_cell_after").click(function () {IPython.notebook.insert_code_cell_after();});
46 46 $("#delete_cell").button("option", "icons", {primary:"ui-icon-closethick"});
47 47 $("#delete_cell").button("option", "text", false);
48 $("#delete_cell").click(function () {IPYTHON.notebook.delete_cell();});
48 $("#delete_cell").click(function () {IPython.notebook.delete_cell();});
49 49
50 50 $("#cell_type").buttonset();
51 $("#to_code").click(function () {IPYTHON.notebook.text_to_code();});
52 $("#to_text").click(function () {IPYTHON.notebook.code_to_text();});
51 $("#to_code").click(function () {IPython.notebook.text_to_code();});
52 $("#to_text").click(function () {IPython.notebook.code_to_text();});
53 53
54 54 $("#sort").buttonset();
55 $("#sort_cells").click(function () {IPYTHON.notebook.sort_cells();});
55 $("#sort_cells").click(function () {IPython.notebook.sort_cells();});
56 56
57 57 $("#toggle").buttonset();
58 $("#collapse").click(function () {IPYTHON.notebook.collapse();});
59 $("#expand").click(function () {IPYTHON.notebook.expand();});
58 $("#collapse").click(function () {IPython.notebook.collapse();});
59 $("#expand").click(function () {IPython.notebook.expand();});
60 60
61 61 });
62 62
@@ -3,142 +3,148 b''
3 3 // TextCell
4 4 //============================================================================
5 5
6 var IPython = (function (IPython) {
6 7
7 var TextCell = function (notebook) {
8 Cell.apply(this, arguments);
9 this.placeholder = "Type <strong>HTML</strong> and LaTeX: $\\alpha^2$"
10 this.rendered = false;
11 };
12
13
14 TextCell.prototype = new Cell();
15
16
17 TextCell.prototype.create_element = function () {
18 var cell = $("<div>").addClass('cell text_cell').
19 append(
20 $("<textarea>" + this.placeholder + "</textarea>").
21 addClass('text_cell_input monospace-font').
22 attr('rows',1).
23 attr('cols',80).
24 autogrow()
25 ).append(
26 // The tabindex=-1 makes this div focusable.
27 $('<div></div>').addClass('text_cell_render').attr('tabindex','-1')
28 )
29 this.element = cell;
30 };
31
32
33 TextCell.prototype.bind_events = function () {
34 Cell.prototype.bind_events.apply(this);
35 var that = this;
36 this.element.keydown(function (event) {
37 if (event.which === 13) {
38 if (that.rendered) {
39 that.edit();
40 event.preventDefault();
8 var TextCell = function (notebook) {
9 IPython.Cell.apply(this, arguments);
10 this.placeholder = "Type <strong>HTML</strong> and LaTeX: $\\alpha^2$"
11 this.rendered = false;
12 };
13
14
15 TextCell.prototype = new IPython.Cell();
16
17
18 TextCell.prototype.create_element = function () {
19 var cell = $("<div>").addClass('cell text_cell').
20 append(
21 $("<textarea>" + this.placeholder + "</textarea>").
22 addClass('text_cell_input monospace-font').
23 attr('rows',1).
24 attr('cols',80).
25 autogrow()
26 ).append(
27 // The tabindex=-1 makes this div focusable.
28 $('<div></div>').addClass('text_cell_render').attr('tabindex','-1')
29 )
30 this.element = cell;
31 };
32
33
34 TextCell.prototype.bind_events = function () {
35 IPython.Cell.prototype.bind_events.apply(this);
36 var that = this;
37 this.element.keydown(function (event) {
38 if (event.which === 13) {
39 if (that.rendered) {
40 that.edit();
41 event.preventDefault();
42 };
41 43 };
42 };
43 });
44 };
44 });
45 };
45 46
46 47
47 TextCell.prototype.select = function () {
48 Cell.prototype.select.apply(this);
49 var output = this.element.find("div.text_cell_render");
50 output.trigger('focus');
51 };
48 TextCell.prototype.select = function () {
49 IPython.Cell.prototype.select.apply(this);
50 var output = this.element.find("div.text_cell_render");
51 output.trigger('focus');
52 };
52 53
53 54
54 TextCell.prototype.edit = function () {
55 if (this.rendered === true) {
56 var text_cell = this.element;
57 var input = text_cell.find("textarea.text_cell_input");
58 var output = text_cell.find("div.text_cell_render");
59 output.hide();
60 input.show().trigger('focus');
61 this.rendered = false;
55 TextCell.prototype.edit = function () {
56 if (this.rendered === true) {
57 var text_cell = this.element;
58 var input = text_cell.find("textarea.text_cell_input");
59 var output = text_cell.find("div.text_cell_render");
60 output.hide();
61 input.show().trigger('focus');
62 this.rendered = false;
63 };
62 64 };
63 };
64 65
65 66
66 TextCell.prototype.render = function () {
67 if (this.rendered === false) {
68 var text_cell = this.element;
69 var input = text_cell.find("textarea.text_cell_input");
70 var output = text_cell.find("div.text_cell_render");
71 var text = input.val();
72 if (text === "") {
73 text = this.placeholder;
74 input.val(text);
67 TextCell.prototype.render = function () {
68 if (this.rendered === false) {
69 var text_cell = this.element;
70 var input = text_cell.find("textarea.text_cell_input");
71 var output = text_cell.find("div.text_cell_render");
72 var text = input.val();
73 if (text === "") {
74 text = this.placeholder;
75 input.val(text);
76 };
77 output.html(text)
78 input.html(text);
79 MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
80 input.hide();
81 output.show();
82 this.rendered = true;
75 83 };
76 output.html(text)
77 input.html(text);
78 MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
79 input.hide();
80 output.show();
81 this.rendered = true;
82 84 };
83 };
84 85
85 86
86 TextCell.prototype.config_mathjax = function () {
87 var text_cell = this.element;
88 var that = this;
89 text_cell.click(function () {
90 that.edit();
91 }).focusout(function () {
92 that.render();
93 });
94
95 text_cell.trigger("focusout");
96 };
87 TextCell.prototype.config_mathjax = function () {
88 var text_cell = this.element;
89 var that = this;
90 text_cell.click(function () {
91 that.edit();
92 }).focusout(function () {
93 that.render();
94 });
95
96 text_cell.trigger("focusout");
97 };
97 98
98 99
99 TextCell.prototype.get_text = function() {
100 return this.element.find("textarea.text_cell_input").val();
101 };
100 TextCell.prototype.get_text = function() {
101 return this.element.find("textarea.text_cell_input").val();
102 };
102 103
103 104
104 TextCell.prototype.set_text = function(text) {
105 this.element.find("textarea.text_cell_input").val(text);
106 this.element.find("textarea.text_cell_input").html(text);
107 this.element.find("div.text_cell_render").html(text);
108 };
105 TextCell.prototype.set_text = function(text) {
106 this.element.find("textarea.text_cell_input").val(text);
107 this.element.find("textarea.text_cell_input").html(text);
108 this.element.find("div.text_cell_render").html(text);
109 };
109 110
110 111
111 TextCell.prototype.at_top = function () {
112 if (this.rendered) {
113 return true;
114 } else {
115 return false;
116 }
117 };
112 TextCell.prototype.at_top = function () {
113 if (this.rendered) {
114 return true;
115 } else {
116 return false;
117 }
118 };
119
120
121 TextCell.prototype.at_bottom = function () {
122 if (this.rendered) {
123 return true;
124 } else {
125 return false;
126 }
127 };
118 128
119 129
120 TextCell.prototype.at_bottom = function () {
121 if (this.rendered) {
122 return true;
123 } else {
124 return false;
130 TextCell.prototype.fromJSON = function (data) {
131 if (data.cell_type === 'text') {
132 this.set_text(data.text);
133 this.grow(this.element.find("textarea.text_cell_input"));
134 };
125 135 }
126 };
127 136
128 137
129 TextCell.prototype.fromJSON = function (data) {
130 if (data.cell_type === 'text') {
131 this.set_text(data.text);
132 this.grow(this.element.find("textarea.text_cell_input"));
138 TextCell.prototype.toJSON = function () {
139 return {
140 cell_type : 'text',
141 text : this.get_text(),
142 };
133 143 };
134 }
135 144
145 IPython.TextCell = TextCell;
136 146
137 TextCell.prototype.toJSON = function () {
138 return {
139 cell_type : 'text',
140 text : this.get_text(),
141 };
142 };
147 return IPython;
143 148
149 }(IPython));
144 150
@@ -3,60 +3,70 b''
3 3 // Utilities
4 4 //============================================================================
5 5
6 IPython.namespace('IPython.utils')
6 7
7 var uuid = function () {
8 // http://www.ietf.org/rfc/rfc4122.txt
9 var s = [];
10 var hexDigits = "0123456789ABCDEF";
11 for (var i = 0; i < 32; i++) {
12 s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
8 IPython.utils = (function (IPython) {
9
10 var uuid = function () {
11 // http://www.ietf.org/rfc/rfc4122.txt
12 var s = [];
13 var hexDigits = "0123456789ABCDEF";
14 for (var i = 0; i < 32; i++) {
15 s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
16 }
17 s[12] = "4"; // bits 12-15 of the time_hi_and_version field to 0010
18 s[16] = hexDigits.substr((s[16] & 0x3) | 0x8, 1); // bits 6-7 of the clock_seq_hi_and_reserved to 01
19
20 var uuid = s.join("");
21 return uuid;
22 };
23
24
25 //Fix raw text to parse correctly in crazy XML
26 function xmlencode(string) {
27 return string.replace(/\&/g,'&'+'amp;')
28 .replace(/</g,'&'+'lt;')
29 .replace(/>/g,'&'+'gt;')
30 .replace(/\'/g,'&'+'apos;')
31 .replace(/\"/g,'&'+'quot;')
32 .replace(/`/g,'&'+'#96;')
13 33 }
14 s[12] = "4"; // bits 12-15 of the time_hi_and_version field to 0010
15 s[16] = hexDigits.substr((s[16] & 0x3) | 0x8, 1); // bits 6-7 of the clock_seq_hi_and_reserved to 01
16
17 var uuid = s.join("");
18 return uuid;
19 };
20
21
22 //Fix raw text to parse correctly in crazy XML
23 function xmlencode(string) {
24 return string.replace(/\&/g,'&'+'amp;')
25 .replace(/</g,'&'+'lt;')
26 .replace(/>/g,'&'+'gt;')
27 .replace(/\'/g,'&'+'apos;')
28 .replace(/\"/g,'&'+'quot;')
29 .replace(/`/g,'&'+'#96;')
30 }
31
32 //Map from terminal commands to CSS classes
33 attrib = {
34 "30":"cblack", "31":"cred",
35 "32":"cgreen", "33":"cyellow",
36 "34":"cblue", "36":"ccyan",
37 "37":"cwhite", "01":"cbold"}
38
39 //Fixes escaped console commands, IE colors. Turns them into HTML
40 function fixConsole(txt) {
41 txt = xmlencode(txt)
42 var re = /\033\[([\d;]*?)m/
43 var opened = false
44 var cmds = []
45 var opener = ""
46 var closer = ""
47
48 while (re.test(txt)) {
49 var cmds = txt.match(re)[1].split(";")
50 closer = opened?"</span>":""
51 opened = cmds.length > 1 || cmds[0] != 0
52 var rep = []
53 for (var i in cmds)
54 if (typeof(attrib[cmds[i]]) != "undefined")
55 rep.push(attrib[cmds[i]])
56 opener = rep.length > 0?"<span class=\""+rep.join(" ")+"\">":""
57 txt = txt.replace(re, closer + opener)
34
35 //Map from terminal commands to CSS classes
36 attrib = {
37 "30":"cblack", "31":"cred",
38 "32":"cgreen", "33":"cyellow",
39 "34":"cblue", "36":"ccyan",
40 "37":"cwhite", "01":"cbold"}
41
42 //Fixes escaped console commands, IE colors. Turns them into HTML
43 function fixConsole(txt) {
44 txt = xmlencode(txt)
45 var re = /\033\[([\d;]*?)m/
46 var opened = false
47 var cmds = []
48 var opener = ""
49 var closer = ""
50
51 while (re.test(txt)) {
52 var cmds = txt.match(re)[1].split(";")
53 closer = opened?"</span>":""
54 opened = cmds.length > 1 || cmds[0] != 0
55 var rep = []
56 for (var i in cmds)
57 if (typeof(attrib[cmds[i]]) != "undefined")
58 rep.push(attrib[cmds[i]])
59 opener = rep.length > 0?"<span class=\""+rep.join(" ")+"\">":""
60 txt = txt.replace(re, closer + opener)
61 }
62 if (opened) txt += "</span>"
63 return txt.trim()
64 }
65
66 return {
67 uuid : uuid,
68 fixConsole : fixConsole
58 69 }
59 if (opened) txt += "</span>"
60 return txt.trim()
61 }
70
71 }(IPython));
62 72
General Comments 0
You need to be logged in to leave comments. Login now