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