##// END OF EJS Templates
implement the completer in a separate class...
Matthias BUSSONNIER -
Show More
@@ -0,0 +1,233
1 // function completer.
2 //
3 // completer should be a class that take an editor instance, and a list of
4 // function to call to get the list of completion.
5 //
6 // the function that send back the list of completion should received the
7 // editor handle as sole argument, and should return a json object with the
8 // following structure
9
10 // {list: clist, # list of n string containing the completions
11 // type : rp, # list of n string containingtype/ origin of the completion
12 // # (will be set as the class of the <option> to be able to style
13 // # them according to the origin of the completion)
14 // from: {line: cur.line, ch: token.start},
15 // to: {line: cur.line, ch: token.end}
16 // };
17 //
18
19 var IPython = (function(IPython ) {
20 // that will prevent us froom missspelling
21 "use strict";
22
23 // easyier key mapping
24 var key = { tab:9,
25 esc:27,
26 backspace:8,
27 space:32,
28 shift:16,
29 enter:13,
30 upArrow:38, // check with keyDown..
31 downArrow :40 // check with keyUp
32 };
33
34 // what is the common start of all completions
35 function sharedStart(B){
36 if(B.length == 1){return B[0]}
37 var A = new Array()
38 for(i=0; i< B.length; i++)
39 {
40 A.push(B[i].str);
41 }
42 if(A.length > 1 ){
43 var tem1, tem2, s, A = A.slice(0).sort();
44 tem1 = A[0];
45 s = tem1.length;
46 tem2 = A.pop();
47 while(s && tem2.indexOf(tem1) == -1){
48 tem1 = tem1.substring(0, --s);
49 }
50 return { str : tem1,
51 type : "computed",
52 from : B[0].from,
53 to : B[0].to
54 };
55 }
56 return null;
57 }
58
59 // user to nsert the given completion
60 var Completer = function(getHints) {
61
62 this.hintfunc = getHints;
63 // if last caractere before cursor is not in this, we stop completing
64 this.reg = /[A-Za-z.]/;
65 }
66
67 Completer.prototype.startCompletionFor = function(ed)
68 {
69 // call for a 'first' completion, that will set the editor and do some
70 // special behaviour like autopicking if only one completion availlable
71 //
72 this.editor = ed;
73 if (this.editor.somethingSelected()) return;
74 this.done = false;
75 // use to get focus back on opera
76 this.carryOnCompletion(true);
77 }
78
79 Completer.prototype.carryOnCompletion = function(ff)
80 {
81 // pass true as parameter if you want the commpleter to autopick
82 // when only one completion
83 // as this function is auto;atically reinvoked at each keystroke with
84 // ff = false
85 var cur = this.editor.getCursor();
86 var pre_cursor = this.editor.getRange({line:cur.line,ch:cur.ch-1},cur);
87
88 // we nned to check that we are still on a word boundary
89 // because while typing the completer is still reinvoking itself
90 if(!this.reg.test(pre_cursor)){ this.close(); return;}
91
92 this.autopick = false;
93 if( ff != 'undefined' && ff==true)
94 {
95 this.autopick=true;
96 }
97 // We want a single cursor position.
98 if (this.editor.somethingSelected()) return;
99
100 // there we will need to gather the results for all the function (and merge them ?)
101 // lets assume for now only one source
102 //
103 var that = this;
104 this.hintfunc(this.editor,function(result){that._resume_completion(result)});
105 }
106 Completer.prototype._resume_completion = function(results)
107 {
108 this.raw_result = results;
109
110 // if empty result return
111 if (!this.raw_result || !this.raw_result.length) return;
112
113
114
115 // When there is only one completion, use it directly.
116 if (this.autopick == true && this.raw_result.length == 1)
117 {
118 this.insert(this.raw_result[0]);
119 return true;
120 }
121
122 if (this.raw_result.length == 1)
123 {
124 // test if first and only completion totally matches
125 // what is typed, in this case dismiss
126 var str = this.raw_result[0].str
127 var cur = this.editor.getCursor();
128 var pre_cursor = this.editor.getRange({line:cur.line,ch:cur.ch-str.length},cur);
129 if(pre_cursor == str){
130 this.close();
131 return ;
132 }
133 }
134
135 this.complete = $('<div/>').addClass('completions');
136 this.complete.attr('id','complete');
137
138 this.sel = $('<select/>').attr('multiple','true');
139 var pos = this.editor.cursorCoords();
140
141 // TODO: I propose to remove enough horizontal pixel
142 // to align the text later
143 this.complete.css('left',pos.x+'px');
144 this.complete.css('top',pos.yBot+'px');
145 this.complete.append(this.sel);
146
147 $('body').append(this.complete);
148 //build the container
149 var that = this;
150 this.sel.dblclick(function(){that.pick()});
151 this.sel.blur(this.close);
152 this.sel.keydown(function(event){that.keydown(event)});
153
154 this.build_gui_list(this.raw_result);
155 var that=this;
156 //CodeMirror.connect(that.sel, "dblclick", function(){that.pick()});
157
158 this.sel.focus();
159 // Opera sometimes ignores focusing a freshly created node
160 if (window.opera) setTimeout(function(){if (!this.done) this.sel.focus();}, 100);
161 // why do we return true ?
162 return true;
163 }
164
165 Completer.prototype.insert = function(completion) {
166 this.editor.replaceRange(completion.str, completion.from, completion.to);
167 }
168
169 Completer.prototype.build_gui_list = function(completions){
170 // Need to clear the all list
171 for (var i = 0; i < completions.length; ++i) {
172 var opt = $('<option/>')
173 .text(completions[i].str)
174 .addClass(completions[i].type);
175 this.sel.append(opt);
176 }
177 this.sel.children().first().attr('selected','true');
178
179 //sel.size = Math.min(10, completions.length);
180 // Hack to hide the scrollbar.
181 //if (completions.length <= 10)
182 //this.complete.style.width = (this.sel.clientWidth - 1) + "px";
183 }
184
185 Completer.prototype.close = function() {
186 if (this.done) return;
187 this.done = true;
188 $('.completions').remove();
189 }
190
191 Completer.prototype.pick = function(){
192 this.insert(this.raw_result[this.sel[0].selectedIndex]);
193 this.close();
194 var that = this;
195 setTimeout(function(){that.editor.focus();}, 50);
196 }
197
198
199 Completer.prototype.keydown = function(event) {
200 var code = event.keyCode;
201 // Enter
202 if (code == key.enter) {CodeMirror.e_stop(event); this.pick();}
203 // Escape or backspace
204 else if (code == key.esc ) {CodeMirror.e_stop(event); this.close(); this.editor.focus();}
205 else if (code == key.space || code == key.backspace) {this.close(); this.editor.focus();}
206 else if (code == key.tab){
207 //all the fastforwarding operation,
208 this.insert(sharedStart(this.raw_result));
209 this.close();
210 CodeMirror.e_stop(event);
211 this.editor.focus();
212 //reinvoke self
213 var that = this;
214 setTimeout(function(){that.carryOnCompletion();}, 50);
215 }
216 else if (code == key.upArrow || code == key.downArrow) {
217 // need to do that to be able to move the arrow
218 // when on the first or last line ofo a code cell
219 event.stopPropagation();
220 }
221 else if (code != key.upArrow && code != key.downArrow) {
222 this.close(); this.editor.focus();
223 //we give focus to the editor immediately and call sell in 50 ms
224 var that = this;
225 setTimeout(function(){that.carryOnCompletion();}, 50);
226 }
227 }
228
229
230 IPython.Completer = Completer;
231
232 return IPython;
233 }(IPython));
@@ -0,0 +1,89
1 // highly adapted for codemiror jshint
2
3 (function () {
4 function forEach(arr, f) {
5 for (var i = 0, e = arr.length; i < e; ++i) f(arr[i]);
6 }
7
8 function arrayContains(arr, item) {
9 if (!Array.prototype.indexOf) {
10 var i = arr.length;
11 while (i--) {
12 if (arr[i] === item) {
13 return true;
14 }
15 }
16 return false;
17 }
18 return arr.indexOf(item) != -1;
19 }
20
21 CodeMirror.contextHint = function(editor) {
22 // Find the token at the cursor
23 var cur = editor.getCursor(), token = editor.getTokenAt(cur), tprop = token;
24 // If it's not a 'word-style' token, ignore the token.
25 // If it is a property, find out what it is a property of.
26
27 var list = new Array();
28 var clist = getCompletions(token,editor) ;
29 for( var i = 0 ; i < clist.length ; i++)
30 {
31 list.push(
32 {
33 str : clist[i],
34 type : "context",
35 from : {line: cur.line, ch: token.start},
36 to : {line: cur.line, ch: token.end}
37 }
38 )
39
40 }
41 return list;
42 }
43
44 // find all 'words' of current cell
45 function getAllTokens(editor)
46 {
47 var found = [];
48 // get all text remove and split it before dot and at space
49 // keep the dot for completing token that also start with dot
50 var candidates = editor.getValue()
51 .replace(/[. ]/g,"\n")
52 .split('\n');
53 // append to arry if not already (the function)
54 function maybeAdd(str) {
55 if (!arrayContains(found, str)) found.push(str);
56 }
57
58 // append to arry if not already
59 // (here we do it )
60 for( c in candidates )
61 {
62 if(candidates[c].length >= 1){
63 maybeAdd(candidates[c]);}
64 }
65 return found;
66
67 }
68
69 function getCompletions(token,editor)
70 {
71 var candidates = getAllTokens(editor);
72 // filter all token that have a common start (but nox exactly) the lenght of the current token
73 var prependchar ='';
74 if(token.string.indexOf('.') == 0)
75 {
76 prependchar = '.'
77 }
78 var lambda = function(x){
79 x = prependchar+x;
80 return (x.indexOf(token.string)==0 && x != token.string)};
81 var filterd = candidates.filter(lambda);
82 for( var i in filterd)
83 {
84 // take care of reappending '.' at the beginning
85 filterd[i] = prependchar+filterd[i];
86 }
87 return filterd;
88 }
89 })();
@@ -1,372 +1,379
1 /**
1 /**
2 * Primary styles
2 * Primary styles
3 *
3 *
4 * Author: IPython Development Team
4 * Author: IPython Development Team
5 */
5 */
6
6
7
7
8 body {
8 body {
9 overflow: hidden;
9 overflow: hidden;
10 }
10 }
11
11
12 span#save_widget {
12 span#save_widget {
13 padding: 5px;
13 padding: 5px;
14 margin: 0px 0px 0px 300px;
14 margin: 0px 0px 0px 300px;
15 display:inline-block;
15 display:inline-block;
16 }
16 }
17
17
18 span#notebook_name {
18 span#notebook_name {
19 height: 1em;
19 height: 1em;
20 line-height: 1em;
20 line-height: 1em;
21 padding: 3px;
21 padding: 3px;
22 border: none;
22 border: none;
23 font-size: 146.5%;
23 font-size: 146.5%;
24 }
24 }
25
25
26 .ui-menubar-item .ui-button .ui-button-text {
26 .ui-menubar-item .ui-button .ui-button-text {
27 padding: 0.4em 1.0em;
27 padding: 0.4em 1.0em;
28 font-size: 100%;
28 font-size: 100%;
29 }
29 }
30
30
31 .ui-menu {
31 .ui-menu {
32 -moz-box-shadow: 0px 6px 10px -1px #adadad;
32 -moz-box-shadow: 0px 6px 10px -1px #adadad;
33 -webkit-box-shadow: 0px 6px 10px -1px #adadad;
33 -webkit-box-shadow: 0px 6px 10px -1px #adadad;
34 box-shadow: 0px 6px 10px -1px #adadad;
34 box-shadow: 0px 6px 10px -1px #adadad;
35 }
35 }
36
36
37 .ui-menu .ui-menu-item a {
37 .ui-menu .ui-menu-item a {
38 padding: 2px 1.6em;
38 padding: 2px 1.6em;
39 }
39 }
40
40
41 .ui-menu hr {
41 .ui-menu hr {
42 margin: 0.3em 0;
42 margin: 0.3em 0;
43 }
43 }
44
44
45 #menubar_container {
45 #menubar_container {
46 position: relative;
46 position: relative;
47 }
47 }
48
48
49 #notification {
49 #notification {
50 position: absolute;
50 position: absolute;
51 right: 3px;
51 right: 3px;
52 top: 3px;
52 top: 3px;
53 height: 25px;
53 height: 25px;
54 padding: 3px 6px;
54 padding: 3px 6px;
55 z-index: 10;
55 z-index: 10;
56 }
56 }
57
57
58 #toolbar {
58 #toolbar {
59 padding: 3px 15px;
59 padding: 3px 15px;
60 }
60 }
61
61
62 #cell_type {
62 #cell_type {
63 font-size: 85%;
63 font-size: 85%;
64 }
64 }
65
65
66
66
67 div#main_app {
67 div#main_app {
68 width: 100%;
68 width: 100%;
69 position: relative;
69 position: relative;
70 }
70 }
71
71
72 span#quick_help_area {
72 span#quick_help_area {
73 position: static;
73 position: static;
74 padding: 5px 0px;
74 padding: 5px 0px;
75 margin: 0px 0px 0px 0px;
75 margin: 0px 0px 0px 0px;
76 }
76 }
77
77
78 .help_string {
78 .help_string {
79 float: right;
79 float: right;
80 width: 170px;
80 width: 170px;
81 padding: 0px 5px;
81 padding: 0px 5px;
82 text-align: left;
82 text-align: left;
83 font-size: 85%;
83 font-size: 85%;
84 }
84 }
85
85
86 .help_string_label {
86 .help_string_label {
87 float: right;
87 float: right;
88 font-size: 85%;
88 font-size: 85%;
89 }
89 }
90
90
91 div#notebook_panel {
91 div#notebook_panel {
92 margin: 0px 0px 0px 0px;
92 margin: 0px 0px 0px 0px;
93 padding: 0px;
93 padding: 0px;
94 }
94 }
95
95
96 div#notebook {
96 div#notebook {
97 overflow-y: scroll;
97 overflow-y: scroll;
98 overflow-x: auto;
98 overflow-x: auto;
99 width: 100%;
99 width: 100%;
100 /* This spaces the cell away from the edge of the notebook area */
100 /* This spaces the cell away from the edge of the notebook area */
101 padding: 5px 5px 15px 5px;
101 padding: 5px 5px 15px 5px;
102 margin: 0px
102 margin: 0px
103 background-color: white;
103 background-color: white;
104 }
104 }
105
105
106 div#pager_splitter {
106 div#pager_splitter {
107 height: 8px;
107 height: 8px;
108 }
108 }
109
109
110 div#pager {
110 div#pager {
111 padding: 15px;
111 padding: 15px;
112 overflow: auto;
112 overflow: auto;
113 display: none;
113 display: none;
114 }
114 }
115
115
116 div.cell {
116 div.cell {
117 width: 100%;
117 width: 100%;
118 padding: 5px 5px 5px 0px;
118 padding: 5px 5px 5px 0px;
119 /* This acts as a spacer between cells, that is outside the border */
119 /* This acts as a spacer between cells, that is outside the border */
120 margin: 2px 0px 2px 0px;
120 margin: 2px 0px 2px 0px;
121 }
121 }
122
122
123 div.code_cell {
123 div.code_cell {
124 background-color: white;
124 background-color: white;
125 }
125 }
126 /* any special styling for code cells that are currently running goes here */
126 /* any special styling for code cells that are currently running goes here */
127 div.code_cell.running {
127 div.code_cell.running {
128 }
128 }
129
129
130 div.prompt {
130 div.prompt {
131 /* This needs to be wide enough for 3 digit prompt numbers: In[100]: */
131 /* This needs to be wide enough for 3 digit prompt numbers: In[100]: */
132 width: 11ex;
132 width: 11ex;
133 /* This 0.4em is tuned to match the padding on the CodeMirror editor. */
133 /* This 0.4em is tuned to match the padding on the CodeMirror editor. */
134 padding: 0.4em;
134 padding: 0.4em;
135 margin: 0px;
135 margin: 0px;
136 font-family: monospace;
136 font-family: monospace;
137 text-align:right;
137 text-align:right;
138 }
138 }
139
139
140 div.input {
140 div.input {
141 page-break-inside: avoid;
141 page-break-inside: avoid;
142 }
142 }
143
143
144 /* input_area and input_prompt must match in top border and margin for alignment */
144 /* input_area and input_prompt must match in top border and margin for alignment */
145 div.input_area {
145 div.input_area {
146 color: black;
146 color: black;
147 border: 1px solid #ddd;
147 border: 1px solid #ddd;
148 border-radius: 3px;
148 border-radius: 3px;
149 background: #f7f7f7;
149 background: #f7f7f7;
150 }
150 }
151
151
152 div.input_prompt {
152 div.input_prompt {
153 color: navy;
153 color: navy;
154 border-top: 1px solid transparent;
154 border-top: 1px solid transparent;
155 }
155 }
156
156
157 div.output {
157 div.output {
158 /* This is a spacer between the input and output of each cell */
158 /* This is a spacer between the input and output of each cell */
159 margin-top: 5px;
159 margin-top: 5px;
160 }
160 }
161
161
162 div.output_prompt {
162 div.output_prompt {
163 color: darkred;
163 color: darkred;
164 }
164 }
165
165
166 /* This class is the outer container of all output sections. */
166 /* This class is the outer container of all output sections. */
167 div.output_area {
167 div.output_area {
168 padding: 0px;
168 padding: 0px;
169 page-break-inside: avoid;
169 page-break-inside: avoid;
170 }
170 }
171
171
172 /* This class is for the output subarea inside the output_area and after
172 /* This class is for the output subarea inside the output_area and after
173 the prompt div. */
173 the prompt div. */
174 div.output_subarea {
174 div.output_subarea {
175 padding: 0.4em 6.1em 0.4em 0.4em;
175 padding: 0.4em 6.1em 0.4em 0.4em;
176 }
176 }
177
177
178 /* The rest of the output_* classes are for special styling of the different
178 /* The rest of the output_* classes are for special styling of the different
179 output types */
179 output types */
180
180
181 /* all text output has this class: */
181 /* all text output has this class: */
182 div.output_text {
182 div.output_text {
183 text-align: left;
183 text-align: left;
184 color: black;
184 color: black;
185 font-family: monospace;
185 font-family: monospace;
186 }
186 }
187
187
188 /* stdout/stderr are 'text' as well as 'stream', but pyout/pyerr are *not* streams */
188 /* stdout/stderr are 'text' as well as 'stream', but pyout/pyerr are *not* streams */
189 div.output_stream {
189 div.output_stream {
190 padding-top: 0.0em;
190 padding-top: 0.0em;
191 padding-bottom: 0.0em;
191 padding-bottom: 0.0em;
192 }
192 }
193 div.output_stdout {
193 div.output_stdout {
194 }
194 }
195 div.output_stderr {
195 div.output_stderr {
196 background: #fdd; /* very light red background for stderr */
196 background: #fdd; /* very light red background for stderr */
197 }
197 }
198
198
199 div.output_latex {
199 div.output_latex {
200 text-align: left;
200 text-align: left;
201 color: black;
201 color: black;
202 }
202 }
203
203
204 div.output_html {
204 div.output_html {
205 }
205 }
206
206
207 div.output_png {
207 div.output_png {
208 }
208 }
209
209
210 div.output_jpeg {
210 div.output_jpeg {
211 }
211 }
212
212
213 div.text_cell {
213 div.text_cell {
214 background-color: white;
214 background-color: white;
215 padding: 5px 5px 5px 5px;
215 padding: 5px 5px 5px 5px;
216 }
216 }
217
217
218 div.text_cell_input {
218 div.text_cell_input {
219 color: black;
219 color: black;
220 border: 1px solid #ddd;
220 border: 1px solid #ddd;
221 border-radius: 3px;
221 border-radius: 3px;
222 background: #f7f7f7;
222 background: #f7f7f7;
223 }
223 }
224
224
225 div.text_cell_render {
225 div.text_cell_render {
226 font-family: "Helvetica Neue", Arial, Helvetica, Geneva, sans-serif;
226 font-family: "Helvetica Neue", Arial, Helvetica, Geneva, sans-serif;
227 outline: none;
227 outline: none;
228 resize: none;
228 resize: none;
229 width: inherit;
229 width: inherit;
230 border-style: none;
230 border-style: none;
231 padding: 5px;
231 padding: 5px;
232 color: black;
232 color: black;
233 }
233 }
234
234
235 .CodeMirror {
235 .CodeMirror {
236 line-height: 1.231; /* Changed from 1em to our global default */
236 line-height: 1.231; /* Changed from 1em to our global default */
237 }
237 }
238
238
239 .CodeMirror-scroll {
239 .CodeMirror-scroll {
240 height: auto; /* Changed to auto to autogrow */
240 height: auto; /* Changed to auto to autogrow */
241 /* The CodeMirror docs are a bit fuzzy on if overflow-y should be hidden or visible.*/
241 /* The CodeMirror docs are a bit fuzzy on if overflow-y should be hidden or visible.*/
242 /* We have found that if it is visible, vertical scrollbars appear with font size changes.*/
242 /* We have found that if it is visible, vertical scrollbars appear with font size changes.*/
243 overflow-y: hidden;
243 overflow-y: hidden;
244 overflow-x: auto; /* Changed from auto to remove scrollbar */
244 overflow-x: auto; /* Changed from auto to remove scrollbar */
245 }
245 }
246
246
247 /* CSS font colors for translated ANSI colors. */
247 /* CSS font colors for translated ANSI colors. */
248
248
249
249
250 .ansiblack {color: black;}
250 .ansiblack {color: black;}
251 .ansired {color: darkred;}
251 .ansired {color: darkred;}
252 .ansigreen {color: darkgreen;}
252 .ansigreen {color: darkgreen;}
253 .ansiyellow {color: brown;}
253 .ansiyellow {color: brown;}
254 .ansiblue {color: darkblue;}
254 .ansiblue {color: darkblue;}
255 .ansipurple {color: darkviolet;}
255 .ansipurple {color: darkviolet;}
256 .ansicyan {color: steelblue;}
256 .ansicyan {color: steelblue;}
257 .ansigrey {color: grey;}
257 .ansigrey {color: grey;}
258 .ansibold {font-weight: bold;}
258 .ansibold {font-weight: bold;}
259
259
260 .completions , .tooltip {
260 .completions , .tooltip {
261 position: absolute;
261 position: absolute;
262 z-index: 10;
262 z-index: 10;
263 overflow: auto;
263 overflow: auto;
264 border: 1px solid black;
264 border: 1px solid black;
265 }
265 }
266
266
267 .completions select {
267 .completions select {
268 background: white;
268 background: white;
269 outline: none;
269 outline: none;
270 border: none;
270 border: none;
271 padding: 0px;
271 padding: 0px;
272 margin: 0px;
272 margin: 0px;
273 font-family: monospace;
273 font-family: monospace;
274 }
274 }
275
275
276 option.context {
277 background-color: #DEF7FF;
278 }
279 option.introspection {
280 background-color: #EBF4EB;
281 }
282
276 @-moz-keyframes fadeIn {
283 @-moz-keyframes fadeIn {
277 from {opacity:0;}
284 from {opacity:0;}
278 to {opacity:1;}
285 to {opacity:1;}
279 }
286 }
280
287
281 @-webkit-keyframes fadeIn {
288 @-webkit-keyframes fadeIn {
282 from {opacity:0;}
289 from {opacity:0;}
283 to {opacity:1;}
290 to {opacity:1;}
284 }
291 }
285
292
286 @keyframes fadeIn {
293 @keyframes fadeIn {
287 from {opacity:0;}
294 from {opacity:0;}
288 to {opacity:1;}
295 to {opacity:1;}
289 }
296 }
290
297
291 /*"close" "expand" and "Open in pager button" of
298 /*"close" "expand" and "Open in pager button" of
292 /* the tooltip*/
299 /* the tooltip*/
293 .tooltip a {
300 .tooltip a {
294 float:right;
301 float:right;
295 }
302 }
296
303
297 /*properties of tooltip after "expand"*/
304 /*properties of tooltip after "expand"*/
298 .bigtooltip {
305 .bigtooltip {
299 height:30%;
306 height:30%;
300 }
307 }
301
308
302 /*properties of tooltip before "expand"*/
309 /*properties of tooltip before "expand"*/
303 .smalltooltip {
310 .smalltooltip {
304 text-overflow: ellipsis;
311 text-overflow: ellipsis;
305 overflow: hidden;
312 overflow: hidden;
306 height:15%;
313 height:15%;
307 }
314 }
308
315
309 .tooltip {
316 .tooltip {
310 /*transition when "expand"ing tooltip */
317 /*transition when "expand"ing tooltip */
311 -webkit-transition-property: height;
318 -webkit-transition-property: height;
312 -webkit-transition-duration: 1s;
319 -webkit-transition-duration: 1s;
313 -moz-transition-property: height;
320 -moz-transition-property: height;
314 -moz-transition-duration: 1s;
321 -moz-transition-duration: 1s;
315 transition-property: height;
322 transition-property: height;
316 transition-duration: 1s;
323 transition-duration: 1s;
317 max-width:700px;
324 max-width:700px;
318 border-radius: 0px 10px 10px 10px;
325 border-radius: 0px 10px 10px 10px;
319 box-shadow: 3px 3px 5px #999;
326 box-shadow: 3px 3px 5px #999;
320 /*fade-in animation when inserted*/
327 /*fade-in animation when inserted*/
321 -webkit-animation: fadeIn 200ms;
328 -webkit-animation: fadeIn 200ms;
322 -moz-animation: fadeIn 200ms;
329 -moz-animation: fadeIn 200ms;
323 animation: fadeIn 200ms;
330 animation: fadeIn 200ms;
324 vertical-align: middle;
331 vertical-align: middle;
325 background: #FDFDD8;
332 background: #FDFDD8;
326 outline: none;
333 outline: none;
327 padding: 3px;
334 padding: 3px;
328 margin: 0px;
335 margin: 0px;
329 font-family: monospace;
336 font-family: monospace;
330 min-height:50px;
337 min-height:50px;
331 }
338 }
332
339
333 /*fixed part of the completion*/
340 /*fixed part of the completion*/
334 .completions p b {
341 .completions p b {
335 font-weight:bold;
342 font-weight:bold;
336 }
343 }
337
344
338 .completions p {
345 .completions p {
339 background: #DDF;
346 background: #DDF;
340 /*outline: none;
347 /*outline: none;
341 padding: 0px;*/
348 padding: 0px;*/
342 border-bottom: black solid 1px;
349 border-bottom: black solid 1px;
343 padding: 1px;
350 padding: 1px;
344 font-family: monospace;
351 font-family: monospace;
345 }
352 }
346
353
347 pre.dialog {
354 pre.dialog {
348 background-color: #f7f7f7;
355 background-color: #f7f7f7;
349 border: 1px solid #ddd;
356 border: 1px solid #ddd;
350 border-radius: 3px;
357 border-radius: 3px;
351 padding: 0.4em;
358 padding: 0.4em;
352 padding-left: 2em;
359 padding-left: 2em;
353 }
360 }
354
361
355 p.dialog {
362 p.dialog {
356 padding : 0.2em;
363 padding : 0.2em;
357 }
364 }
358
365
359 .shortcut_key {
366 .shortcut_key {
360 display: inline-block;
367 display: inline-block;
361 width: 15ex;
368 width: 15ex;
362 text-align: right;
369 text-align: right;
363 font-family: monospace;
370 font-family: monospace;
364 }
371 }
365
372
366 .shortcut_descr {
373 .shortcut_descr {
367 }
374 }
368
375
369 /* Word-wrap output correctly. This is the CSS3 spelling, though Firefox seems
376 /* Word-wrap output correctly. This is the CSS3 spelling, though Firefox seems
370 to not honor it correctly. Webkit browsers (Chrome, rekonq, Safari) do.
377 to not honor it correctly. Webkit browsers (Chrome, rekonq, Safari) do.
371 */
378 */
372 pre, code, kbd, samp { white-space: pre-wrap; }
379 pre, code, kbd, samp { white-space: pre-wrap; }
@@ -1,927 +1,681
1 //----------------------------------------------------------------------------
1 //----------------------------------------------------------------------------
2 // Copyright (C) 2008-2011 The IPython Development Team
2 // Copyright (C) 2008-2011 The IPython Development Team
3 //
3 //
4 // Distributed under the terms of the BSD License. The full license is in
4 // Distributed under the terms of the BSD License. The full license is in
5 // the file COPYING, distributed as part of this software.
5 // the file COPYING, distributed as part of this software.
6 //----------------------------------------------------------------------------
6 //----------------------------------------------------------------------------
7
7
8 //============================================================================
8 //============================================================================
9 // CodeCell
9 // CodeCell
10 //============================================================================
10 //============================================================================
11
11
12 var IPython = (function (IPython) {
12 var IPython = (function (IPython) {
13
14 var utils = IPython.utils;
13 var utils = IPython.utils;
15
14
16 var CodeCell = function (notebook) {
15 var CodeCell = function (notebook) {
17 this.code_mirror = null;
16 this.code_mirror = null;
18 this.input_prompt_number = null;
17 this.input_prompt_number = null;
19 this.is_completing = false;
18 this.is_completing = false;
20 this.completion_cursor = null;
19 this.completion_cursor = null;
21 this.outputs = [];
20 this.outputs = [];
22 this.collapsed = false;
21 this.collapsed = false;
23 this.tooltip_timeout = null;
22 this.tooltip_timeout = null;
24 this.clear_out_timeout = null;
23 this.clear_out_timeout = null;
25 IPython.Cell.apply(this, arguments);
24 IPython.Cell.apply(this, arguments);
25 var that = this;
26 this.ccc = new IPython.Completer(function(ed, callback){that.requestCompletion(ed, callback)});
26 };
27 };
27
28
28
29
29 CodeCell.prototype = new IPython.Cell();
30 CodeCell.prototype = new IPython.Cell();
30
31
31
32
32 CodeCell.prototype.create_element = function () {
33 CodeCell.prototype.create_element = function () {
33 var cell = $('<div></div>').addClass('cell border-box-sizing code_cell vbox');
34 var cell = $('<div></div>').addClass('cell border-box-sizing code_cell vbox');
34 cell.attr('tabindex','2');
35 cell.attr('tabindex','2');
35 var input = $('<div></div>').addClass('input hbox');
36 var input = $('<div></div>').addClass('input hbox');
36 input.append($('<div/>').addClass('prompt input_prompt'));
37 input.append($('<div/>').addClass('prompt input_prompt'));
37 var input_area = $('<div/>').addClass('input_area box-flex1');
38 var input_area = $('<div/>').addClass('input_area box-flex1');
38 this.code_mirror = CodeMirror(input_area.get(0), {
39 this.code_mirror = CodeMirror(input_area.get(0), {
39 indentUnit : 4,
40 indentUnit : 4,
40 mode: 'python',
41 mode: 'python',
41 theme: 'ipython',
42 theme: 'ipython',
42 readOnly: this.read_only,
43 readOnly: this.read_only,
43 onKeyEvent: $.proxy(this.handle_codemirror_keyevent,this)
44 onKeyEvent: $.proxy(this.handle_codemirror_keyevent,this),
44 });
45 });
46 var that = this;
47 ccm = this.code_mirror;
48 ccc = this.ccc;
45 input.append(input_area);
49 input.append(input_area);
46 var output = $('<div></div>').addClass('output vbox');
50 var output = $('<div></div>').addClass('output vbox');
47 cell.append(input).append(output);
51 cell.append(input).append(output);
48 this.element = cell;
52 this.element = cell;
49 this.collapse();
53 this.collapse();
50 };
54 };
51
55
52 //TODO, try to diminish the number of parameters.
56 //TODO, try to diminish the number of parameters.
53 CodeCell.prototype.request_tooltip_after_time = function (pre_cursor,time){
57 CodeCell.prototype.request_tooltip_after_time = function (pre_cursor,time){
54 var that = this;
58 var that = this;
55 if (pre_cursor === "" || pre_cursor === "(" ) {
59 if (pre_cursor === "" || pre_cursor === "(" ) {
56 // don't do anything if line beggin with '(' or is empty
60 // don't do anything if line beggin with '(' or is empty
57 } else {
61 } else {
58 // Will set a timer to request tooltip in `time`
62 // Will set a timer to request tooltip in `time`
59 that.tooltip_timeout = setTimeout(function(){
63 that.tooltip_timeout = setTimeout(function(){
60 IPython.notebook.request_tool_tip(that, pre_cursor)
64 IPython.notebook.request_tool_tip(that, pre_cursor)
61 },time);
65 },time);
62 }
66 }
63 };
67 };
64
68
65 CodeCell.prototype.handle_codemirror_keyevent = function (editor, event) {
69 CodeCell.prototype.handle_codemirror_keyevent = function (editor, event) {
66 // This method gets called in CodeMirror's onKeyDown/onKeyPress
70 // This method gets called in CodeMirror's onKeyDown/onKeyPress
67 // handlers and is used to provide custom key handling. Its return
71 // handlers and is used to provide custom key handling. Its return
68 // value is used to determine if CodeMirror should ignore the event:
72 // value is used to determine if CodeMirror should ignore the event:
69 // true = ignore, false = don't ignore.
73 // true = ignore, false = don't ignore.
70
74
71 if (this.read_only){
75 if (this.read_only){
72 return false;
76 return false;
73 }
77 }
74
78
75 // note that we are comparing and setting the time to wait at each key press.
79 // note that we are comparing and setting the time to wait at each key press.
76 // a better wqy might be to generate a new function on each time change and
80 // a better wqy might be to generate a new function on each time change and
77 // assign it to CodeCell.prototype.request_tooltip_after_time
81 // assign it to CodeCell.prototype.request_tooltip_after_time
78 tooltip_wait_time = this.notebook.time_before_tooltip;
82 tooltip_wait_time = this.notebook.time_before_tooltip;
79 tooltip_on_tab = this.notebook.tooltip_on_tab;
83 tooltip_on_tab = this.notebook.tooltip_on_tab;
80 var that = this;
84 var that = this;
81 // whatever key is pressed, first, cancel the tooltip request before
85 // whatever key is pressed, first, cancel the tooltip request before
82 // they are sent, and remove tooltip if any
86 // they are sent, and remove tooltip if any
83 if(event.type === 'keydown' ) {
87 if(event.type === 'keydown' ) {
84 that.remove_and_cancel_tooltip();
88 that.remove_and_cancel_tooltip();
85 };
89 };
86
90
87
91
88 if (event.keyCode === 13 && (event.shiftKey || event.ctrlKey)) {
92 if (event.keyCode === 13 && (event.shiftKey || event.ctrlKey)) {
89 // Always ignore shift-enter in CodeMirror as we handle it.
93 // Always ignore shift-enter in CodeMirror as we handle it.
90 return true;
94 return true;
91 } else if (event.which === 40 && event.type === 'keypress' && tooltip_wait_time >= 0) {
95 } else if (event.which === 40 && event.type === 'keypress' && tooltip_wait_time >= 0) {
92 // triger aon keypress (!) otherwise inconsistent event.which depending on plateform
96 // triger aon keypress (!) otherwise inconsistent event.which depending on plateform
93 // browser and keyboard layout !
97 // browser and keyboard layout !
94 // Pressing '(' , request tooltip, don't forget to reappend it
98 // Pressing '(' , request tooltip, don't forget to reappend it
95 var cursor = editor.getCursor();
99 var cursor = editor.getCursor();
96 var pre_cursor = editor.getRange({line:cursor.line,ch:0},cursor).trim()+'(';
100 var pre_cursor = editor.getRange({line:cursor.line,ch:0},cursor).trim()+'(';
97 that.request_tooltip_after_time(pre_cursor,tooltip_wait_time);
101 that.request_tooltip_after_time(pre_cursor,tooltip_wait_time);
98 } else if (event.which === 38) {
102 } else if (event.which === 38) {
99 // If we are not at the top, let CM handle the up arrow and
103 // If we are not at the top, let CM handle the up arrow and
100 // prevent the global keydown handler from handling it.
104 // prevent the global keydown handler from handling it.
101 if (!that.at_top()) {
105 if (!that.at_top()) {
102 event.stop();
106 event.stop();
103 return false;
107 return false;
104 } else {
108 } else {
105 return true;
109 return true;
106 };
110 };
107 } else if (event.which === 40) {
111 } else if (event.which === 40) {
108 // If we are not at the bottom, let CM handle the down arrow and
112 // If we are not at the bottom, let CM handle the down arrow and
109 // prevent the global keydown handler from handling it.
113 // prevent the global keydown handler from handling it.
110 if (!that.at_bottom()) {
114 if (!that.at_bottom()) {
111 event.stop();
115 event.stop();
112 return false;
116 return false;
113 } else {
117 } else {
114 return true;
118 return true;
115 };
119 };
116 } else if (event.keyCode === 9 && event.type == 'keydown') {
120 } else if (event.keyCode === 9 && event.type == 'keydown') {
117 // Tab completion.
121 // Tab completion.
118 var cur = editor.getCursor();
122 var cur = editor.getCursor();
119 //Do not trim here because of tooltip
123 //Do not trim here because of tooltip
120 var pre_cursor = editor.getRange({line:cur.line,ch:0},cur);
124 var pre_cursor = editor.getRange({line:cur.line,ch:0},cur);
121 if (pre_cursor.trim() === "") {
125 if (pre_cursor.trim() === "") {
122 // Don't autocomplete if the part of the line before the cursor
126 // Don't autocomplete if the part of the line before the cursor
123 // is empty. In this case, let CodeMirror handle indentation.
127 // is empty. In this case, let CodeMirror handle indentation.
124 return false;
128 return false;
125 } else if ((pre_cursor.substr(-1) === "("|| pre_cursor.substr(-1) === " ") && tooltip_on_tab ) {
129 } else if ((pre_cursor.substr(-1) === "("|| pre_cursor.substr(-1) === " ") && tooltip_on_tab ) {
126 that.request_tooltip_after_time(pre_cursor,0);
130 that.request_tooltip_after_time(pre_cursor,0);
127 // Prevent the event from bubbling up.
131 // Prevent the event from bubbling up.
128 event.stop();
132 event.stop();
129 // Prevent CodeMirror from handling the tab.
133 // Prevent CodeMirror from handling the tab.
130 return true;
134 return true;
131 } else {
135 } else {
132 pre_cursor.trim();
133 // Autocomplete the current line.
134 event.stop();
136 event.stop();
135 var line = editor.getLine(cur.line);
137 this.ccc.startCompletionFor(this.code_mirror);
136 this.is_completing = true;
138
137 this.completion_cursor = cur;
138 IPython.notebook.complete_cell(this, line, cur.ch);
139 return true;
139 return true;
140 };
140 };
141 } else if (event.keyCode === 8 && event.type == 'keydown') {
141 } else if (event.keyCode === 8 && event.type == 'keydown') {
142 // If backspace and the line ends with 4 spaces, remove them.
142 // If backspace and the line ends with 4 spaces, remove them.
143 var cur = editor.getCursor();
143 var cur = editor.getCursor();
144 var line = editor.getLine(cur.line);
144 var line = editor.getLine(cur.line);
145 var ending = line.slice(-4);
145 var ending = line.slice(-4);
146 if (ending === ' ') {
146 if (ending === ' ') {
147 editor.replaceRange('',
147 editor.replaceRange('',
148 {line: cur.line, ch: cur.ch-4},
148 {line: cur.line, ch: cur.ch-4},
149 {line: cur.line, ch: cur.ch}
149 {line: cur.line, ch: cur.ch}
150 );
150 );
151 event.stop();
151 event.stop();
152 return true;
152 return true;
153 } else {
153 } else {
154 return false;
154 return false;
155 };
155 };
156 } else {
156 } else {
157 // keypress/keyup also trigger on TAB press, and we don't want to
157 // keypress/keyup also trigger on TAB press, and we don't want to
158 // use those to disable tab completion.
158 // use those to disable tab completion.
159 if (this.is_completing && event.keyCode !== 9) {
159 if (this.is_completing && event.keyCode !== 9) {
160 var ed_cur = editor.getCursor();
160 var ed_cur = editor.getCursor();
161 var cc_cur = this.completion_cursor;
161 var cc_cur = this.completion_cursor;
162 if (ed_cur.line !== cc_cur.line || ed_cur.ch !== cc_cur.ch) {
162 if (ed_cur.line !== cc_cur.line || ed_cur.ch !== cc_cur.ch) {
163 this.is_completing = false;
163 this.is_completing = false;
164 this.completion_cursor = null;
164 this.completion_cursor = null;
165 };
165 };
166 };
166 };
167 return false;
167 return false;
168 };
168 };
169 return false;
169 return false;
170 };
170 };
171
171
172 CodeCell.prototype.remove_and_cancel_tooltip = function() {
172 CodeCell.prototype.remove_and_cancel_tooltip = function() {
173 // note that we don't handle closing directly inside the calltip
173 // note that we don't handle closing directly inside the calltip
174 // as in the completer, because it is not focusable, so won't
174 // as in the completer, because it is not focusable, so won't
175 // get the event.
175 // get the event.
176 if (this.tooltip_timeout != null){
176 if (this.tooltip_timeout != null){
177 clearTimeout(this.tooltip_timeout);
177 clearTimeout(this.tooltip_timeout);
178 $('#tooltip').remove();
178 $('#tooltip').remove();
179 this.tooltip_timeout = null;
179 this.tooltip_timeout = null;
180 }
180 }
181 }
181 }
182
182
183 CodeCell.prototype.finish_tooltip = function (reply) {
183 CodeCell.prototype.finish_tooltip = function (reply) {
184 // Extract call tip data; the priority is call, init, main.
184 // Extract call tip data; the priority is call, init, main.
185 defstring = reply.call_def;
185 defstring = reply.call_def;
186 if (defstring == null) { defstring = reply.init_definition; }
186 if (defstring == null) { defstring = reply.init_definition; }
187 if (defstring == null) { defstring = reply.definition; }
187 if (defstring == null) { defstring = reply.definition; }
188
188
189 docstring = reply.call_docstring;
189 docstring = reply.call_docstring;
190 if (docstring == null) { docstring = reply.init_docstring; }
190 if (docstring == null) { docstring = reply.init_docstring; }
191 if (docstring == null) { docstring = reply.docstring; }
191 if (docstring == null) { docstring = reply.docstring; }
192 if (docstring == null) { docstring = "<empty docstring>"; }
192 if (docstring == null) { docstring = "<empty docstring>"; }
193
193
194 name=reply.name;
194 name=reply.name;
195
195
196 var that = this;
196 var that = this;
197 var tooltip = $('<div/>').attr('id', 'tooltip').addClass('tooltip');
197 var tooltip = $('<div/>').attr('id', 'tooltip').addClass('tooltip');
198 // remove to have the tooltip not Limited in X and Y
198 // remove to have the tooltip not Limited in X and Y
199 tooltip.addClass('smalltooltip');
199 tooltip.addClass('smalltooltip');
200 var pre=$('<pre/>').html(utils.fixConsole(docstring));
200 var pre=$('<pre/>').html(utils.fixConsole(docstring));
201 var expandlink=$('<a/>').attr('href',"#");
201 var expandlink=$('<a/>').attr('href',"#");
202 expandlink.addClass("ui-corner-all"); //rounded corner
202 expandlink.addClass("ui-corner-all"); //rounded corner
203 expandlink.attr('role',"button");
203 expandlink.attr('role',"button");
204 //expandlink.addClass('ui-button');
204 //expandlink.addClass('ui-button');
205 //expandlink.addClass('ui-state-default');
205 //expandlink.addClass('ui-state-default');
206 var expandspan=$('<span/>').text('Expand');
206 var expandspan=$('<span/>').text('Expand');
207 expandspan.addClass('ui-icon');
207 expandspan.addClass('ui-icon');
208 expandspan.addClass('ui-icon-plus');
208 expandspan.addClass('ui-icon-plus');
209 expandlink.append(expandspan);
209 expandlink.append(expandspan);
210 expandlink.attr('id','expanbutton');
210 expandlink.attr('id','expanbutton');
211 expandlink.click(function(){
211 expandlink.click(function(){
212 tooltip.removeClass('smalltooltip');
212 tooltip.removeClass('smalltooltip');
213 tooltip.addClass('bigtooltip');
213 tooltip.addClass('bigtooltip');
214 $('#expanbutton').remove();
214 $('#expanbutton').remove();
215 setTimeout(function(){that.code_mirror.focus();}, 50);
215 setTimeout(function(){that.code_mirror.focus();}, 50);
216 });
216 });
217 var morelink=$('<a/>').attr('href',"#");
217 var morelink=$('<a/>').attr('href',"#");
218 morelink.attr('role',"button");
218 morelink.attr('role',"button");
219 morelink.addClass('ui-button');
219 morelink.addClass('ui-button');
220 //morelink.addClass("ui-corner-all"); //rounded corner
220 //morelink.addClass("ui-corner-all"); //rounded corner
221 //morelink.addClass('ui-state-default');
221 //morelink.addClass('ui-state-default');
222 var morespan=$('<span/>').text('Open in Pager');
222 var morespan=$('<span/>').text('Open in Pager');
223 morespan.addClass('ui-icon');
223 morespan.addClass('ui-icon');
224 morespan.addClass('ui-icon-arrowstop-l-n');
224 morespan.addClass('ui-icon-arrowstop-l-n');
225 morelink.append(morespan);
225 morelink.append(morespan);
226 morelink.click(function(){
226 morelink.click(function(){
227 var msg_id = IPython.notebook.kernel.execute(name+"?");
227 var msg_id = IPython.notebook.kernel.execute(name+"?");
228 IPython.notebook.msg_cell_map[msg_id] = IPython.notebook.get_selected_cell().cell_id;
228 IPython.notebook.msg_cell_map[msg_id] = IPython.notebook.get_selected_cell().cell_id;
229 that.remove_and_cancel_tooltip();
229 that.remove_and_cancel_tooltip();
230 setTimeout(function(){that.code_mirror.focus();}, 50);
230 setTimeout(function(){that.code_mirror.focus();}, 50);
231 });
231 });
232
232
233 var closelink=$('<a/>').attr('href',"#");
233 var closelink=$('<a/>').attr('href',"#");
234 closelink.attr('role',"button");
234 closelink.attr('role',"button");
235 closelink.addClass('ui-button');
235 closelink.addClass('ui-button');
236 //closelink.addClass("ui-corner-all"); //rounded corner
236 //closelink.addClass("ui-corner-all"); //rounded corner
237 //closelink.adClass('ui-state-default'); // grey background and blue cross
237 //closelink.adClass('ui-state-default'); // grey background and blue cross
238 var closespan=$('<span/>').text('Close');
238 var closespan=$('<span/>').text('Close');
239 closespan.addClass('ui-icon');
239 closespan.addClass('ui-icon');
240 closespan.addClass('ui-icon-close');
240 closespan.addClass('ui-icon-close');
241 closelink.append(closespan);
241 closelink.append(closespan);
242 closelink.click(function(){
242 closelink.click(function(){
243 that.remove_and_cancel_tooltip();
243 that.remove_and_cancel_tooltip();
244 setTimeout(function(){that.code_mirror.focus();}, 50);
244 setTimeout(function(){that.code_mirror.focus();}, 50);
245 });
245 });
246 //construct the tooltip
246 //construct the tooltip
247 tooltip.append(closelink);
247 tooltip.append(closelink);
248 tooltip.append(expandlink);
248 tooltip.append(expandlink);
249 tooltip.append(morelink);
249 tooltip.append(morelink);
250 if(defstring){
250 if(defstring){
251 defstring_html = $('<pre/>').html(utils.fixConsole(defstring));
251 defstring_html = $('<pre/>').html(utils.fixConsole(defstring));
252 tooltip.append(defstring_html);
252 tooltip.append(defstring_html);
253 }
253 }
254 tooltip.append(pre);
254 tooltip.append(pre);
255 var pos = this.code_mirror.cursorCoords();
255 var pos = this.code_mirror.cursorCoords();
256 tooltip.css('left',pos.x+'px');
256 tooltip.css('left',pos.x+'px');
257 tooltip.css('top',pos.yBot+'px');
257 tooltip.css('top',pos.yBot+'px');
258 $('body').append(tooltip);
258 $('body').append(tooltip);
259
259
260 // issues with cross-closing if multiple tooltip in less than 5sec
260 // issues with cross-closing if multiple tooltip in less than 5sec
261 // keep it comented for now
261 // keep it comented for now
262 // setTimeout(that.remove_and_cancel_tooltip, 5000);
262 // setTimeout(that.remove_and_cancel_tooltip, 5000);
263 };
263 };
264
264
265 // As you type completer
265 // As you type completer
266 CodeCell.prototype.finish_completing = function (matched_text, matches) {
266 CodeCell.prototype.requestCompletion= function(ed,callback)
267 if(matched_text[0]=='%'){
267 {
268 completing_from_magic = true;
268 this._compcallback = callback;
269 completing_to_magic = false;
269 this._editor = ed;
270 } else {
270 var cur = ed.getCursor();
271 completing_from_magic = false;
271 var pre_cursor = this.code_mirror.getRange({line:cur.line,ch:0},cur);
272 completing_to_magic = false;
272 pre_cursor.trim();
273 }
273 // Autocomplete the current line.
274 //return if not completing or nothing to complete
274 var line = this.code_mirror.getLine(cur.line);
275 if (!this.is_completing || matches.length === 0) {return;}
275 this.is_completing = true;
276
276 this.completion_cursor = cur;
277 // for later readability
277 IPython.notebook.complete_cell(this, line, cur.ch);
278 var key = { tab:9,
278 }
279 esc:27,
280 backspace:8,
281 space:32,
282 shift:16,
283 enter:13,
284 // _ is 95
285 isCompSymbol : function (code)
286 {
287 return (code > 64 && code <= 90)
288 || (code >= 97 && code <= 122)
289 || (code == 95)
290 },
291 dismissAndAppend : function (code)
292 {
293 chararr = '()[]+-/\\. ,=*'.split("");
294 codearr = chararr.map(function(x){return x.charCodeAt(0)});
295 return jQuery.inArray(code, codearr) != -1;
296 }
297
298 }
299
300 // smart completion, sort kwarg ending with '='
301 var newm = new Array();
302 if(this.notebook.smart_completer)
303 {
304 kwargs = new Array();
305 other = new Array();
306 for(var i = 0 ; i<matches.length ; ++i){
307 if(matches[i].substr(-1) === '='){
308 kwargs.push(matches[i]);
309 }else{other.push(matches[i]);}
310 }
311 newm = kwargs.concat(other);
312 matches = newm;
313 }
314 // end sort kwargs
315
316 // give common prefix of a array of string
317 function sharedStart(A){
318 shared='';
319 if(A.length == 1){shared=A[0]}
320 if(A.length > 1 ){
321 var tem1, tem2, s, A = A.slice(0).sort();
322 tem1 = A[0];
323 s = tem1.length;
324 tem2 = A.pop();
325 while(s && tem2.indexOf(tem1) == -1){
326 tem1 = tem1.substring(0, --s);
327 }
328 shared = tem1;
329 }
330 if (shared[0] == '%' && !completing_from_magic)
331 {
332 shared = shared.substr(1);
333 return [shared, true];
334 } else {
335 return [shared, false];
336 }
337 }
338
339
340 //try to check if the user is typing tab at least twice after a word
341 // and completion is "done"
342 fallback_on_tooltip_after = 2
343 if(matches.length == 1 && matched_text === matches[0])
344 {
345 if(this.npressed >fallback_on_tooltip_after && this.prevmatch==matched_text)
346 {
347 this.request_tooltip_after_time(matched_text+'(',0);
348 return;
349 }
350 this.prevmatch = matched_text
351 this.npressed = this.npressed+1;
352 }
353 else
354 {
355 this.prevmatch = "";
356 this.npressed = 0;
357 }
358 // end fallback on tooltip
359 //==================================
360 // Real completion logic start here
361 var that = this;
362 var cur = this.completion_cursor;
363 var done = false;
364
365 // call to dismmiss the completer
366 var close = function () {
367 if (done) return;
368 done = true;
369 if (complete != undefined)
370 {complete.remove();}
371 that.is_completing = false;
372 that.completion_cursor = null;
373 };
374
375 // update codemirror with the typed text
376 prev = matched_text
377 var update = function (inserted_text, event) {
378 that.code_mirror.replaceRange(
379 inserted_text,
380 {line: cur.line, ch: (cur.ch-matched_text.length)},
381 {line: cur.line, ch: (cur.ch+prev.length-matched_text.length)}
382 );
383 prev = inserted_text
384 if(event != null){
385 event.stopPropagation();
386 event.preventDefault();
387 }
388 };
389 // insert the given text and exit the completer
390 var insert = function (selected_text, event) {
391 update(selected_text)
392 close();
393 setTimeout(function(){that.code_mirror.focus();}, 50);
394 };
395
396 // insert the curent highlited selection and exit
397 var pick = function () {
398 insert(select.val()[0],null);
399 };
400
401
279
402 // Define function to clear the completer, refill it with the new
280 CodeCell.prototype.finish_completing = function (matched_text, matches) {
403 // matches, update the pseuso typing field. autopick insert match if
281 // let's build a function that wrap all that stuff into what is needed for the
404 // only one left, in no matches (anymore) dismiss itself by pasting
282 // new completer:
405 // what the user have typed until then
283 //
406 var complete_with = function(matches,typed_text,autopick,event)
284 var cur = this._editor.getCursor();
285 res = CodeMirror.contextHint(this._editor);
286 for( i=0; i< matches.length ; i++)
407 {
287 {
408 // If autopick an only one match, past.
288 res.push(
409 // Used to 'pick' when pressing tab
410 var prefix = '';
411 if(completing_to_magic && !completing_from_magic)
412 {
413 prefix='%';
414 }
415 if (matches.length < 1) {
416 insert(prefix+typed_text,event);
417 if(event != null){
418 event.stopPropagation();
419 event.preventDefault();
420 }
421 } else if (autopick && matches.length == 1) {
422 insert(matches[0],event);
423 if(event != null){
424 event.stopPropagation();
425 event.preventDefault();
426 }
427 return;
428 }
429 //clear the previous completion if any
430 update(prefix+typed_text,event);
431 complete.children().children().remove();
432 $('#asyoutype').html("<b>"+prefix+matched_text+"</b>"+typed_text.substr(matched_text.length));
433 select = $('#asyoutypeselect');
434 for (var i = 0; i<matches.length; ++i) {
435 select.append($('<option/>').html(matches[i]));
436 }
437 select.children().first().attr('selected','true');
438 }
439
440 // create html for completer
441 var complete = $('<div/>').addClass('completions');
442 complete.attr('id','complete');
443 complete.append($('<p/>').attr('id', 'asyoutype').html('<b>fixed part</b>user part'));//pseudo input field
444
445 var select = $('<select/>').attr('multiple','true');
446 select.attr('id', 'asyoutypeselect')
447 select.attr('size',Math.min(10,matches.length));
448 var pos = this.code_mirror.cursorCoords();
449
450 // TODO: I propose to remove enough horizontal pixel
451 // to align the text later
452 complete.css('left',pos.x+'px');
453 complete.css('top',pos.yBot+'px');
454 complete.append(select);
455
456 $('body').append(complete);
457
458 // So a first actual completion. see if all the completion start wit
459 // the same letter and complete if necessary
460 ff = sharedStart(matches)
461 fastForward = ff[0];
462 completing_to_magic = ff[1];
463 typed_characters = fastForward.substr(matched_text.length);
464 complete_with(matches,matched_text+typed_characters,true,null);
465 filterd = matches;
466 // Give focus to select, and make it filter the match as the user type
467 // by filtering the previous matches. Called by .keypress and .keydown
468 var downandpress = function (event,press_or_down) {
469 var code = event.which;
470 var autopick = false; // auto 'pick' if only one match
471 if (press_or_down === 0){
472 press = true; down = false; //Are we called from keypress or keydown
473 } else if (press_or_down == 1){
474 press = false; down = true;
475 }
476 if (code === key.shift) {
477 // nothing on Shift
478 return;
479 }
480 if (key.dismissAndAppend(code) && press) {
481 var newchar = String.fromCharCode(code);
482 typed_characters = typed_characters+newchar;
483 insert(matched_text+typed_characters,event);
484 return
485 }
486 if (code === key.enter) {
487 // Pressing ENTER will cause a pick
488 event.stopPropagation();
489 event.preventDefault();
490 pick();
491 } else if (code === 38 || code === 40) {
492 // We don't want the document keydown handler to handle UP/DOWN,
493 // but we want the default action.
494 event.stopPropagation();
495 } else if ( (code == key.backspace)||(code == key.tab && down) || press || key.isCompSymbol(code)){
496 if( key.isCompSymbol(code) && press)
497 {
289 {
498 var newchar = String.fromCharCode(code);
290 str : matches[i],
499 typed_characters = typed_characters+newchar;
291 type : "introspection",
500 } else if (code == key.tab) {
292 from : {line: cur.line, ch: cur.ch-matched_text.length},
501 ff = sharedStart(matches)
293 to : {line: cur.line, ch: cur.ch}
502 fastForward = ff[0];
503 completing_to_magic = ff[1];
504 ffsub = fastForward.substr(matched_text.length+typed_characters.length);
505 typed_characters = typed_characters+ffsub;
506 autopick = true;
507 } else if (code == key.backspace && down) {
508 // cancel if user have erase everything, otherwise decrease
509 // what we filter with
510 event.preventDefault();
511 if (typed_characters.length <= 0)
512 {
513 insert(matched_text,event)
514 return
515 }
516 typed_characters = typed_characters.substr(0,typed_characters.length-1);
517 } else if (press && code != key.backspace && code != key.tab && code != 0){
518 insert(matched_text+typed_characters,event);
519 return
520 } else {
521 return
522 }
294 }
523 re = new RegExp("^"+"\%?"+matched_text+typed_characters,"");
295 )
524 filterd = matches.filter(function(x){return re.test(x)});
525 ff = sharedStart(filterd);
526 completing_to_magic = ff[1];
527 complete_with(filterd,matched_text+typed_characters,autopick,event);
528 } else if (code == key.esc) {
529 // dismiss the completer and go back to before invoking it
530 insert(matched_text,event);
531 } else if (press) { // abort only on .keypress or esc
532 }
533 }
296 }
534 select.keydown(function (event) {
297 this._compcallback(res);
535 downandpress(event,1)
298
536 });
537 select.keypress(function (event) {
538 downandpress(event,0)
539 });
540 // Double click also causes a pick.
541 // and bind the last actions.
542 select.dblclick(pick);
543 select.blur(close);
544 select.focus();
545 };
299 };
546
300
547
301
548 CodeCell.prototype.select = function () {
302 CodeCell.prototype.select = function () {
549 IPython.Cell.prototype.select.apply(this);
303 IPython.Cell.prototype.select.apply(this);
550 this.code_mirror.refresh();
304 this.code_mirror.refresh();
551 this.code_mirror.focus();
305 this.code_mirror.focus();
552 // We used to need an additional refresh() after the focus, but
306 // We used to need an additional refresh() after the focus, but
553 // it appears that this has been fixed in CM. This bug would show
307 // it appears that this has been fixed in CM. This bug would show
554 // up on FF when a newly loaded markdown cell was edited.
308 // up on FF when a newly loaded markdown cell was edited.
555 };
309 };
556
310
557
311
558 CodeCell.prototype.select_all = function () {
312 CodeCell.prototype.select_all = function () {
559 var start = {line: 0, ch: 0};
313 var start = {line: 0, ch: 0};
560 var nlines = this.code_mirror.lineCount();
314 var nlines = this.code_mirror.lineCount();
561 var last_line = this.code_mirror.getLine(nlines-1);
315 var last_line = this.code_mirror.getLine(nlines-1);
562 var end = {line: nlines-1, ch: last_line.length};
316 var end = {line: nlines-1, ch: last_line.length};
563 this.code_mirror.setSelection(start, end);
317 this.code_mirror.setSelection(start, end);
564 };
318 };
565
319
566
320
567 CodeCell.prototype.append_output = function (json, dynamic) {
321 CodeCell.prototype.append_output = function (json, dynamic) {
568 // If dynamic is true, javascript output will be eval'd.
322 // If dynamic is true, javascript output will be eval'd.
569 this.expand();
323 this.expand();
570 this.flush_clear_timeout();
324 this.flush_clear_timeout();
571 if (json.output_type === 'pyout') {
325 if (json.output_type === 'pyout') {
572 this.append_pyout(json, dynamic);
326 this.append_pyout(json, dynamic);
573 } else if (json.output_type === 'pyerr') {
327 } else if (json.output_type === 'pyerr') {
574 this.append_pyerr(json);
328 this.append_pyerr(json);
575 } else if (json.output_type === 'display_data') {
329 } else if (json.output_type === 'display_data') {
576 this.append_display_data(json, dynamic);
330 this.append_display_data(json, dynamic);
577 } else if (json.output_type === 'stream') {
331 } else if (json.output_type === 'stream') {
578 this.append_stream(json);
332 this.append_stream(json);
579 };
333 };
580 this.outputs.push(json);
334 this.outputs.push(json);
581 };
335 };
582
336
583
337
584 CodeCell.prototype.create_output_area = function () {
338 CodeCell.prototype.create_output_area = function () {
585 var oa = $("<div/>").addClass("hbox output_area");
339 var oa = $("<div/>").addClass("hbox output_area");
586 oa.append($('<div/>').addClass('prompt'));
340 oa.append($('<div/>').addClass('prompt'));
587 return oa;
341 return oa;
588 };
342 };
589
343
590
344
591 CodeCell.prototype.append_pyout = function (json, dynamic) {
345 CodeCell.prototype.append_pyout = function (json, dynamic) {
592 n = json.prompt_number || ' ';
346 n = json.prompt_number || ' ';
593 var toinsert = this.create_output_area();
347 var toinsert = this.create_output_area();
594 toinsert.find('div.prompt').addClass('output_prompt').html('Out[' + n + ']:');
348 toinsert.find('div.prompt').addClass('output_prompt').html('Out[' + n + ']:');
595 this.append_mime_type(json, toinsert, dynamic);
349 this.append_mime_type(json, toinsert, dynamic);
596 this.element.find('div.output').append(toinsert);
350 this.element.find('div.output').append(toinsert);
597 // If we just output latex, typeset it.
351 // If we just output latex, typeset it.
598 if ((json.latex !== undefined) || (json.html !== undefined)) {
352 if ((json.latex !== undefined) || (json.html !== undefined)) {
599 this.typeset();
353 this.typeset();
600 };
354 };
601 };
355 };
602
356
603
357
604 CodeCell.prototype.append_pyerr = function (json) {
358 CodeCell.prototype.append_pyerr = function (json) {
605 var tb = json.traceback;
359 var tb = json.traceback;
606 if (tb !== undefined && tb.length > 0) {
360 if (tb !== undefined && tb.length > 0) {
607 var s = '';
361 var s = '';
608 var len = tb.length;
362 var len = tb.length;
609 for (var i=0; i<len; i++) {
363 for (var i=0; i<len; i++) {
610 s = s + tb[i] + '\n';
364 s = s + tb[i] + '\n';
611 }
365 }
612 s = s + '\n';
366 s = s + '\n';
613 var toinsert = this.create_output_area();
367 var toinsert = this.create_output_area();
614 this.append_text(s, toinsert);
368 this.append_text(s, toinsert);
615 this.element.find('div.output').append(toinsert);
369 this.element.find('div.output').append(toinsert);
616 };
370 };
617 };
371 };
618
372
619
373
620 CodeCell.prototype.append_stream = function (json) {
374 CodeCell.prototype.append_stream = function (json) {
621 // temporary fix: if stream undefined (json file written prior to this patch),
375 // temporary fix: if stream undefined (json file written prior to this patch),
622 // default to most likely stdout:
376 // default to most likely stdout:
623 if (json.stream == undefined){
377 if (json.stream == undefined){
624 json.stream = 'stdout';
378 json.stream = 'stdout';
625 }
379 }
626 if (!utils.fixConsole(json.text)){
380 if (!utils.fixConsole(json.text)){
627 // fixConsole gives nothing (empty string, \r, etc.)
381 // fixConsole gives nothing (empty string, \r, etc.)
628 // so don't append any elements, which might add undesirable space
382 // so don't append any elements, which might add undesirable space
629 return;
383 return;
630 }
384 }
631 var subclass = "output_"+json.stream;
385 var subclass = "output_"+json.stream;
632 if (this.outputs.length > 0){
386 if (this.outputs.length > 0){
633 // have at least one output to consider
387 // have at least one output to consider
634 var last = this.outputs[this.outputs.length-1];
388 var last = this.outputs[this.outputs.length-1];
635 if (last.output_type == 'stream' && json.stream == last.stream){
389 if (last.output_type == 'stream' && json.stream == last.stream){
636 // latest output was in the same stream,
390 // latest output was in the same stream,
637 // so append directly into its pre tag
391 // so append directly into its pre tag
638 // escape ANSI & HTML specials:
392 // escape ANSI & HTML specials:
639 var text = utils.fixConsole(json.text);
393 var text = utils.fixConsole(json.text);
640 this.element.find('div.'+subclass).last().find('pre').append(text);
394 this.element.find('div.'+subclass).last().find('pre').append(text);
641 return;
395 return;
642 }
396 }
643 }
397 }
644
398
645 // If we got here, attach a new div
399 // If we got here, attach a new div
646 var toinsert = this.create_output_area();
400 var toinsert = this.create_output_area();
647 this.append_text(json.text, toinsert, "output_stream "+subclass);
401 this.append_text(json.text, toinsert, "output_stream "+subclass);
648 this.element.find('div.output').append(toinsert);
402 this.element.find('div.output').append(toinsert);
649 };
403 };
650
404
651
405
652 CodeCell.prototype.append_display_data = function (json, dynamic) {
406 CodeCell.prototype.append_display_data = function (json, dynamic) {
653 var toinsert = this.create_output_area();
407 var toinsert = this.create_output_area();
654 this.append_mime_type(json, toinsert, dynamic);
408 this.append_mime_type(json, toinsert, dynamic);
655 this.element.find('div.output').append(toinsert);
409 this.element.find('div.output').append(toinsert);
656 // If we just output latex, typeset it.
410 // If we just output latex, typeset it.
657 if ( (json.latex !== undefined) || (json.html !== undefined) ) {
411 if ( (json.latex !== undefined) || (json.html !== undefined) ) {
658 this.typeset();
412 this.typeset();
659 };
413 };
660 };
414 };
661
415
662
416
663 CodeCell.prototype.append_mime_type = function (json, element, dynamic) {
417 CodeCell.prototype.append_mime_type = function (json, element, dynamic) {
664 if (json.javascript !== undefined && dynamic) {
418 if (json.javascript !== undefined && dynamic) {
665 this.append_javascript(json.javascript, element, dynamic);
419 this.append_javascript(json.javascript, element, dynamic);
666 } else if (json.html !== undefined) {
420 } else if (json.html !== undefined) {
667 this.append_html(json.html, element);
421 this.append_html(json.html, element);
668 } else if (json.latex !== undefined) {
422 } else if (json.latex !== undefined) {
669 this.append_latex(json.latex, element);
423 this.append_latex(json.latex, element);
670 } else if (json.svg !== undefined) {
424 } else if (json.svg !== undefined) {
671 this.append_svg(json.svg, element);
425 this.append_svg(json.svg, element);
672 } else if (json.png !== undefined) {
426 } else if (json.png !== undefined) {
673 this.append_png(json.png, element);
427 this.append_png(json.png, element);
674 } else if (json.jpeg !== undefined) {
428 } else if (json.jpeg !== undefined) {
675 this.append_jpeg(json.jpeg, element);
429 this.append_jpeg(json.jpeg, element);
676 } else if (json.text !== undefined) {
430 } else if (json.text !== undefined) {
677 this.append_text(json.text, element);
431 this.append_text(json.text, element);
678 };
432 };
679 };
433 };
680
434
681
435
682 CodeCell.prototype.append_html = function (html, element) {
436 CodeCell.prototype.append_html = function (html, element) {
683 var toinsert = $("<div/>").addClass("box_flex1 output_subarea output_html rendered_html");
437 var toinsert = $("<div/>").addClass("box_flex1 output_subarea output_html rendered_html");
684 toinsert.append(html);
438 toinsert.append(html);
685 element.append(toinsert);
439 element.append(toinsert);
686 };
440 };
687
441
688
442
689 CodeCell.prototype.append_javascript = function (js, container) {
443 CodeCell.prototype.append_javascript = function (js, container) {
690 // We just eval the JS code, element appears in the local scope.
444 // We just eval the JS code, element appears in the local scope.
691 var element = $("<div/>").addClass("box_flex1 output_subarea");
445 var element = $("<div/>").addClass("box_flex1 output_subarea");
692 container.append(element);
446 container.append(element);
693 // Div for js shouldn't be drawn, as it will add empty height to the area.
447 // Div for js shouldn't be drawn, as it will add empty height to the area.
694 container.hide();
448 container.hide();
695 // If the Javascript appends content to `element` that should be drawn, then
449 // If the Javascript appends content to `element` that should be drawn, then
696 // it must also call `container.show()`.
450 // it must also call `container.show()`.
697 eval(js);
451 eval(js);
698 }
452 }
699
453
700
454
701 CodeCell.prototype.append_text = function (data, element, extra_class) {
455 CodeCell.prototype.append_text = function (data, element, extra_class) {
702 var toinsert = $("<div/>").addClass("box_flex1 output_subarea output_text");
456 var toinsert = $("<div/>").addClass("box_flex1 output_subarea output_text");
703 // escape ANSI & HTML specials in plaintext:
457 // escape ANSI & HTML specials in plaintext:
704 data = utils.fixConsole(data);
458 data = utils.fixConsole(data);
705 if (extra_class){
459 if (extra_class){
706 toinsert.addClass(extra_class);
460 toinsert.addClass(extra_class);
707 }
461 }
708 toinsert.append($("<pre/>").html(data));
462 toinsert.append($("<pre/>").html(data));
709 element.append(toinsert);
463 element.append(toinsert);
710 };
464 };
711
465
712
466
713 CodeCell.prototype.append_svg = function (svg, element) {
467 CodeCell.prototype.append_svg = function (svg, element) {
714 var toinsert = $("<div/>").addClass("box_flex1 output_subarea output_svg");
468 var toinsert = $("<div/>").addClass("box_flex1 output_subarea output_svg");
715 toinsert.append(svg);
469 toinsert.append(svg);
716 element.append(toinsert);
470 element.append(toinsert);
717 };
471 };
718
472
719
473
720 CodeCell.prototype.append_png = function (png, element) {
474 CodeCell.prototype.append_png = function (png, element) {
721 var toinsert = $("<div/>").addClass("box_flex1 output_subarea output_png");
475 var toinsert = $("<div/>").addClass("box_flex1 output_subarea output_png");
722 toinsert.append($("<img/>").attr('src','data:image/png;base64,'+png));
476 toinsert.append($("<img/>").attr('src','data:image/png;base64,'+png));
723 element.append(toinsert);
477 element.append(toinsert);
724 };
478 };
725
479
726
480
727 CodeCell.prototype.append_jpeg = function (jpeg, element) {
481 CodeCell.prototype.append_jpeg = function (jpeg, element) {
728 var toinsert = $("<div/>").addClass("box_flex1 output_subarea output_jpeg");
482 var toinsert = $("<div/>").addClass("box_flex1 output_subarea output_jpeg");
729 toinsert.append($("<img/>").attr('src','data:image/jpeg;base64,'+jpeg));
483 toinsert.append($("<img/>").attr('src','data:image/jpeg;base64,'+jpeg));
730 element.append(toinsert);
484 element.append(toinsert);
731 };
485 };
732
486
733
487
734 CodeCell.prototype.append_latex = function (latex, element) {
488 CodeCell.prototype.append_latex = function (latex, element) {
735 // This method cannot do the typesetting because the latex first has to
489 // This method cannot do the typesetting because the latex first has to
736 // be on the page.
490 // be on the page.
737 var toinsert = $("<div/>").addClass("box_flex1 output_subarea output_latex");
491 var toinsert = $("<div/>").addClass("box_flex1 output_subarea output_latex");
738 toinsert.append(latex);
492 toinsert.append(latex);
739 element.append(toinsert);
493 element.append(toinsert);
740 };
494 };
741
495
742
496
743 CodeCell.prototype.clear_output = function (stdout, stderr, other) {
497 CodeCell.prototype.clear_output = function (stdout, stderr, other) {
744 var that = this;
498 var that = this;
745 if (this.clear_out_timeout != null){
499 if (this.clear_out_timeout != null){
746 // fire previous pending clear *immediately*
500 // fire previous pending clear *immediately*
747 clearTimeout(this.clear_out_timeout);
501 clearTimeout(this.clear_out_timeout);
748 this.clear_out_timeout = null;
502 this.clear_out_timeout = null;
749 this.clear_output_callback(this._clear_stdout, this._clear_stderr, this._clear_other);
503 this.clear_output_callback(this._clear_stdout, this._clear_stderr, this._clear_other);
750 }
504 }
751 // store flags for flushing the timeout
505 // store flags for flushing the timeout
752 this._clear_stdout = stdout;
506 this._clear_stdout = stdout;
753 this._clear_stderr = stderr;
507 this._clear_stderr = stderr;
754 this._clear_other = other;
508 this._clear_other = other;
755 this.clear_out_timeout = setTimeout(function(){
509 this.clear_out_timeout = setTimeout(function(){
756 // really clear timeout only after a short delay
510 // really clear timeout only after a short delay
757 // this reduces flicker in 'clear_output; print' cases
511 // this reduces flicker in 'clear_output; print' cases
758 that.clear_out_timeout = null;
512 that.clear_out_timeout = null;
759 that._clear_stdout = that._clear_stderr = that._clear_other = null;
513 that._clear_stdout = that._clear_stderr = that._clear_other = null;
760 that.clear_output_callback(stdout, stderr, other);
514 that.clear_output_callback(stdout, stderr, other);
761 }, 500
515 }, 500
762 );
516 );
763 };
517 };
764
518
765 CodeCell.prototype.clear_output_callback = function (stdout, stderr, other) {
519 CodeCell.prototype.clear_output_callback = function (stdout, stderr, other) {
766 var output_div = this.element.find("div.output");
520 var output_div = this.element.find("div.output");
767
521
768 if (stdout && stderr && other){
522 if (stdout && stderr && other){
769 // clear all, no need for logic
523 // clear all, no need for logic
770 output_div.html("");
524 output_div.html("");
771 this.outputs = [];
525 this.outputs = [];
772 return;
526 return;
773 }
527 }
774 // remove html output
528 // remove html output
775 // each output_subarea that has an identifying class is in an output_area
529 // each output_subarea that has an identifying class is in an output_area
776 // which is the element to be removed.
530 // which is the element to be removed.
777 if (stdout){
531 if (stdout){
778 output_div.find("div.output_stdout").parent().remove();
532 output_div.find("div.output_stdout").parent().remove();
779 }
533 }
780 if (stderr){
534 if (stderr){
781 output_div.find("div.output_stderr").parent().remove();
535 output_div.find("div.output_stderr").parent().remove();
782 }
536 }
783 if (other){
537 if (other){
784 output_div.find("div.output_subarea").not("div.output_stderr").not("div.output_stdout").parent().remove();
538 output_div.find("div.output_subarea").not("div.output_stderr").not("div.output_stdout").parent().remove();
785 }
539 }
786
540
787 // remove cleared outputs from JSON list:
541 // remove cleared outputs from JSON list:
788 for (var i = this.outputs.length - 1; i >= 0; i--){
542 for (var i = this.outputs.length - 1; i >= 0; i--){
789 var out = this.outputs[i];
543 var out = this.outputs[i];
790 var output_type = out.output_type;
544 var output_type = out.output_type;
791 if (output_type == "display_data" && other){
545 if (output_type == "display_data" && other){
792 this.outputs.splice(i,1);
546 this.outputs.splice(i,1);
793 }else if (output_type == "stream"){
547 }else if (output_type == "stream"){
794 if (stdout && out.stream == "stdout"){
548 if (stdout && out.stream == "stdout"){
795 this.outputs.splice(i,1);
549 this.outputs.splice(i,1);
796 }else if (stderr && out.stream == "stderr"){
550 }else if (stderr && out.stream == "stderr"){
797 this.outputs.splice(i,1);
551 this.outputs.splice(i,1);
798 }
552 }
799 }
553 }
800 }
554 }
801 };
555 };
802
556
803
557
804 CodeCell.prototype.clear_input = function () {
558 CodeCell.prototype.clear_input = function () {
805 this.code_mirror.setValue('');
559 this.code_mirror.setValue('');
806 };
560 };
807
561
808 CodeCell.prototype.flush_clear_timeout = function() {
562 CodeCell.prototype.flush_clear_timeout = function() {
809 var output_div = this.element.find('div.output');
563 var output_div = this.element.find('div.output');
810 if (this.clear_out_timeout){
564 if (this.clear_out_timeout){
811 clearTimeout(this.clear_out_timeout);
565 clearTimeout(this.clear_out_timeout);
812 this.clear_out_timeout = null;
566 this.clear_out_timeout = null;
813 this.clear_output_callback(this._clear_stdout, this._clear_stderr, this._clear_other);
567 this.clear_output_callback(this._clear_stdout, this._clear_stderr, this._clear_other);
814 };
568 };
815 }
569 }
816
570
817
571
818 CodeCell.prototype.collapse = function () {
572 CodeCell.prototype.collapse = function () {
819 if (!this.collapsed) {
573 if (!this.collapsed) {
820 this.element.find('div.output').hide();
574 this.element.find('div.output').hide();
821 this.collapsed = true;
575 this.collapsed = true;
822 };
576 };
823 };
577 };
824
578
825
579
826 CodeCell.prototype.expand = function () {
580 CodeCell.prototype.expand = function () {
827 if (this.collapsed) {
581 if (this.collapsed) {
828 this.element.find('div.output').show();
582 this.element.find('div.output').show();
829 this.collapsed = false;
583 this.collapsed = false;
830 };
584 };
831 };
585 };
832
586
833
587
834 CodeCell.prototype.toggle_output = function () {
588 CodeCell.prototype.toggle_output = function () {
835 if (this.collapsed) {
589 if (this.collapsed) {
836 this.expand();
590 this.expand();
837 } else {
591 } else {
838 this.collapse();
592 this.collapse();
839 };
593 };
840 };
594 };
841
595
842 CodeCell.prototype.set_input_prompt = function (number) {
596 CodeCell.prototype.set_input_prompt = function (number) {
843 this.input_prompt_number = number;
597 this.input_prompt_number = number;
844 var ns = number || "&nbsp;";
598 var ns = number || "&nbsp;";
845 this.element.find('div.input_prompt').html('In&nbsp;[' + ns + ']:');
599 this.element.find('div.input_prompt').html('In&nbsp;[' + ns + ']:');
846 };
600 };
847
601
848
602
849 CodeCell.prototype.get_text = function () {
603 CodeCell.prototype.get_text = function () {
850 return this.code_mirror.getValue();
604 return this.code_mirror.getValue();
851 };
605 };
852
606
853
607
854 CodeCell.prototype.set_text = function (code) {
608 CodeCell.prototype.set_text = function (code) {
855 return this.code_mirror.setValue(code);
609 return this.code_mirror.setValue(code);
856 };
610 };
857
611
858
612
859 CodeCell.prototype.at_top = function () {
613 CodeCell.prototype.at_top = function () {
860 var cursor = this.code_mirror.getCursor();
614 var cursor = this.code_mirror.getCursor();
861 if (cursor.line === 0) {
615 if (cursor.line === 0) {
862 return true;
616 return true;
863 } else {
617 } else {
864 return false;
618 return false;
865 }
619 }
866 };
620 };
867
621
868
622
869 CodeCell.prototype.at_bottom = function () {
623 CodeCell.prototype.at_bottom = function () {
870 var cursor = this.code_mirror.getCursor();
624 var cursor = this.code_mirror.getCursor();
871 if (cursor.line === (this.code_mirror.lineCount()-1)) {
625 if (cursor.line === (this.code_mirror.lineCount()-1)) {
872 return true;
626 return true;
873 } else {
627 } else {
874 return false;
628 return false;
875 }
629 }
876 };
630 };
877
631
878
632
879 CodeCell.prototype.fromJSON = function (data) {
633 CodeCell.prototype.fromJSON = function (data) {
880 if (data.cell_type === 'code') {
634 if (data.cell_type === 'code') {
881 if (data.input !== undefined) {
635 if (data.input !== undefined) {
882 this.set_text(data.input);
636 this.set_text(data.input);
883 }
637 }
884 if (data.prompt_number !== undefined) {
638 if (data.prompt_number !== undefined) {
885 this.set_input_prompt(data.prompt_number);
639 this.set_input_prompt(data.prompt_number);
886 } else {
640 } else {
887 this.set_input_prompt();
641 this.set_input_prompt();
888 };
642 };
889 var len = data.outputs.length;
643 var len = data.outputs.length;
890 for (var i=0; i<len; i++) {
644 for (var i=0; i<len; i++) {
891 // append with dynamic=false.
645 // append with dynamic=false.
892 this.append_output(data.outputs[i], false);
646 this.append_output(data.outputs[i], false);
893 };
647 };
894 if (data.collapsed !== undefined) {
648 if (data.collapsed !== undefined) {
895 if (data.collapsed) {
649 if (data.collapsed) {
896 this.collapse();
650 this.collapse();
897 } else {
651 } else {
898 this.expand();
652 this.expand();
899 };
653 };
900 };
654 };
901 };
655 };
902 };
656 };
903
657
904
658
905 CodeCell.prototype.toJSON = function () {
659 CodeCell.prototype.toJSON = function () {
906 var data = {};
660 var data = {};
907 data.input = this.get_text();
661 data.input = this.get_text();
908 data.cell_type = 'code';
662 data.cell_type = 'code';
909 if (this.input_prompt_number) {
663 if (this.input_prompt_number) {
910 data.prompt_number = this.input_prompt_number;
664 data.prompt_number = this.input_prompt_number;
911 };
665 };
912 var outputs = [];
666 var outputs = [];
913 var len = this.outputs.length;
667 var len = this.outputs.length;
914 for (var i=0; i<len; i++) {
668 for (var i=0; i<len; i++) {
915 outputs[i] = this.outputs[i];
669 outputs[i] = this.outputs[i];
916 };
670 };
917 data.outputs = outputs;
671 data.outputs = outputs;
918 data.language = 'python';
672 data.language = 'python';
919 data.collapsed = this.collapsed;
673 data.collapsed = this.collapsed;
920 return data;
674 return data;
921 };
675 };
922
676
923
677
924 IPython.CodeCell = CodeCell;
678 IPython.CodeCell = CodeCell;
925
679
926 return IPython;
680 return IPython;
927 }(IPython));
681 }(IPython));
@@ -1,235 +1,238
1 {% extends page.html %}
1 {% extends page.html %}
2
3 {% block stylesheet %}
2 {% block stylesheet %}
4
3
5 {% if mathjax_url %}
4 {% if mathjax_url %}
6 <script type="text/javascript" src="{{mathjax_url}}?config=TeX-AMS_HTML" charset="utf-8"></script>
5 <script type="text/javascript" src="{{mathjax_url}}?config=TeX-AMS_HTML" charset="utf-8"></script>
7 {% end %}
6 {% end %}
8 <script type="text/javascript">
7 <script type="text/javascript">
9 // MathJax disabled, set as null to distingish from *missing* MathJax,
8 // MathJax disabled, set as null to distingish from *missing* MathJax,
10 // where it will be undefined, and should prompt a dialog later.
9 // where it will be undefined, and should prompt a dialog later.
11 window.mathjax_url = "{{mathjax_url}}";
10 window.mathjax_url = "{{mathjax_url}}";
12 </script>
11 </script>
13
12
14 <link rel="stylesheet" href="{{ static_url("codemirror/lib/codemirror.css") }}">
13 <link rel="stylesheet" href="{{ static_url("codemirror/lib/codemirror.css") }}">
15 <link rel="stylesheet" href="{{ static_url("codemirror/theme/ipython.css") }}">
14 <link rel="stylesheet" href="{{ static_url("codemirror/theme/ipython.css") }}">
16
15
17 <link rel="stylesheet" href="{{ static_url("prettify/prettify.css") }}"/>
16 <link rel="stylesheet" href="{{ static_url("prettify/prettify.css") }}"/>
18
17
19 <link rel="stylesheet" href="{{ static_url("css/notebook.css") }}" type="text/css" />
18 <link rel="stylesheet" href="{{ static_url("css/notebook.css") }}" type="text/css" />
20 <link rel="stylesheet" href="{{ static_url("css/renderedhtml.css") }}" type="text/css" />
19 <link rel="stylesheet" href="{{ static_url("css/renderedhtml.css") }}" type="text/css" />
21
20
22 {% end %}
21 {% end %}
23
22
24
23
25 {% block params %}
24 {% block params %}
26
25
27 data-project={{project}}
26 data-project={{project}}
28 data-base-project-url={{base_project_url}}
27 data-base-project-url={{base_project_url}}
29 data-base-kernel-url={{base_kernel_url}}
28 data-base-kernel-url={{base_kernel_url}}
30 data-read-only={{read_only and not logged_in}}
29 data-read-only={{read_only and not logged_in}}
31 data-notebook-id={{notebook_id}}
30 data-notebook-id={{notebook_id}}
32
31
33 {% end %}
32 {% end %}
34
33
35
34
36 {% block header %}
35 {% block header %}
37
36
38 <span id="save_widget">
37 <span id="save_widget">
39 <span id="notebook_name"></span>
38 <span id="notebook_name"></span>
40 <span id="save_status"></span>
39 <span id="save_status"></span>
41 </span>
40 </span>
42
41
43 {% end %}
42 {% end %}
44
43
45
44
46 {% block site %}
45 {% block site %}
47
46
48 <div id="menubar_container">
47 <div id="menubar_container">
49 <div id="menubar">
48 <div id="menubar">
50 <ul id="menus">
49 <ul id="menus">
51 <li><a href="#">File</a>
50 <li><a href="#">File</a>
52 <ul>
51 <ul>
53 <li id="new_notebook"><a href="#">New</a></li>
52 <li id="new_notebook"><a href="#">New</a></li>
54 <li id="open_notebook"><a href="#">Open...</a></li>
53 <li id="open_notebook"><a href="#">Open...</a></li>
55 <hr/>
54 <hr/>
56 <li id="copy_notebook"><a href="#">Make a Copy...</a></li>
55 <li id="copy_notebook"><a href="#">Make a Copy...</a></li>
57 <li id="rename_notebook"><a href="#">Rename...</a></li>
56 <li id="rename_notebook"><a href="#">Rename...</a></li>
58 <li id="save_notebook"><a href="#">Save</a></li>
57 <li id="save_notebook"><a href="#">Save</a></li>
59 <hr/>
58 <hr/>
60 <li><a href="#">Download as</a>
59 <li><a href="#">Download as</a>
61 <ul>
60 <ul>
62 <li id="download_ipynb"><a href="#">IPython (.ipynb)</a></li>
61 <li id="download_ipynb"><a href="#">IPython (.ipynb)</a></li>
63 <li id="download_py"><a href="#">Python (.py)</a></li>
62 <li id="download_py"><a href="#">Python (.py)</a></li>
64 </ul>
63 </ul>
65 </li>
64 </li>
66 <hr/>
65 <hr/>
67 <li id="print_notebook"><a href="/{{notebook_id}}/print" target="_blank">Print View</a></li>
66 <li id="print_notebook"><a href="/{{notebook_id}}/print" target="_blank">Print View</a></li>
68 <hr/>
67 <hr/>
69 <li id="kill_and_exit"><a href="#" >Close and halt</a></li>
68 <li id="kill_and_exit"><a href="#" >Close and halt</a></li>
70 </ul>
69 </ul>
71 </li>
70 </li>
72 <li><a href="#">Edit</a>
71 <li><a href="#">Edit</a>
73 <ul>
72 <ul>
74 <li id="cut_cell"><a href="#">Cut Cell</a></li>
73 <li id="cut_cell"><a href="#">Cut Cell</a></li>
75 <li id="copy_cell"><a href="#">Copy Cell</a></li>
74 <li id="copy_cell"><a href="#">Copy Cell</a></li>
76 <li id="paste_cell" class="ui-state-disabled"><a href="#">Paste Cell</a></li>
75 <li id="paste_cell" class="ui-state-disabled"><a href="#">Paste Cell</a></li>
77 <li id="paste_cell_above" class="ui-state-disabled"><a href="#">Paste Cell Above</a></li>
76 <li id="paste_cell_above" class="ui-state-disabled"><a href="#">Paste Cell Above</a></li>
78 <li id="paste_cell_below" class="ui-state-disabled"><a href="#">Paste Cell Below</a></li>
77 <li id="paste_cell_below" class="ui-state-disabled"><a href="#">Paste Cell Below</a></li>
79 <li id="delete_cell"><a href="#">Delete</a></li>
78 <li id="delete_cell"><a href="#">Delete</a></li>
80 <hr/>
79 <hr/>
81 <li id="split_cell"><a href="#">Split Cell</a></li>
80 <li id="split_cell"><a href="#">Split Cell</a></li>
82 <li id="merge_cell_above"><a href="#">Merge Cell Above</a></li>
81 <li id="merge_cell_above"><a href="#">Merge Cell Above</a></li>
83 <li id="merge_cell_below"><a href="#">Merge Cell Below</a></li>
82 <li id="merge_cell_below"><a href="#">Merge Cell Below</a></li>
84 <hr/>
83 <hr/>
85 <li id="move_cell_up"><a href="#">Move Cell Up</a></li>
84 <li id="move_cell_up"><a href="#">Move Cell Up</a></li>
86 <li id="move_cell_down"><a href="#">Move Cell Down</a></li>
85 <li id="move_cell_down"><a href="#">Move Cell Down</a></li>
87 <hr/>
86 <hr/>
88 <li id="select_previous"><a href="#">Select Previous Cell</a></li>
87 <li id="select_previous"><a href="#">Select Previous Cell</a></li>
89 <li id="select_next"><a href="#">Select Next Cell</a></li>
88 <li id="select_next"><a href="#">Select Next Cell</a></li>
90 </ul>
89 </ul>
91 </li>
90 </li>
92 <li><a href="#">View</a>
91 <li><a href="#">View</a>
93 <ul>
92 <ul>
94 <li id="toggle_header"><a href="#">Toggle Header</a></li>
93 <li id="toggle_header"><a href="#">Toggle Header</a></li>
95 <li id="toggle_toolbar"><a href="#">Toggle Toolbar</a></li>
94 <li id="toggle_toolbar"><a href="#">Toggle Toolbar</a></li>
96 </ul>
95 </ul>
97 </li>
96 </li>
98 <li><a href="#">Insert</a>
97 <li><a href="#">Insert</a>
99 <ul>
98 <ul>
100 <li id="insert_cell_above"><a href="#">Insert Cell Above</a></li>
99 <li id="insert_cell_above"><a href="#">Insert Cell Above</a></li>
101 <li id="insert_cell_below"><a href="#">Insert Cell Below</a></li>
100 <li id="insert_cell_below"><a href="#">Insert Cell Below</a></li>
102 </ul>
101 </ul>
103 </li>
102 </li>
104 <li><a href="#">Cell</a>
103 <li><a href="#">Cell</a>
105 <ul>
104 <ul>
106 <li id="run_cell"><a href="#">Run</a></li>
105 <li id="run_cell"><a href="#">Run</a></li>
107 <li id="run_cell_in_place"><a href="#">Run in Place</a></li>
106 <li id="run_cell_in_place"><a href="#">Run in Place</a></li>
108 <li id="run_all_cells"><a href="#">Run All</a></li>
107 <li id="run_all_cells"><a href="#">Run All</a></li>
109 <hr/>
108 <hr/>
110 <li id="to_code"><a href="#">Code</a></li>
109 <li id="to_code"><a href="#">Code</a></li>
111 <li id="to_markdown"><a href="#">Markdown </a></li>
110 <li id="to_markdown"><a href="#">Markdown </a></li>
112 <li id="to_raw"><a href="#">Raw Text</a></li>
111 <li id="to_raw"><a href="#">Raw Text</a></li>
113 <li id="to_heading1"><a href="#">Heading 1</a></li>
112 <li id="to_heading1"><a href="#">Heading 1</a></li>
114 <li id="to_heading2"><a href="#">Heading 2</a></li>
113 <li id="to_heading2"><a href="#">Heading 2</a></li>
115 <li id="to_heading3"><a href="#">Heading 3</a></li>
114 <li id="to_heading3"><a href="#">Heading 3</a></li>
116 <li id="to_heading4"><a href="#">Heading 4</a></li>
115 <li id="to_heading4"><a href="#">Heading 4</a></li>
117 <li id="to_heading5"><a href="#">Heading 5</a></li>
116 <li id="to_heading5"><a href="#">Heading 5</a></li>
118 <li id="to_heading6"><a href="#">Heading 6</a></li>
117 <li id="to_heading6"><a href="#">Heading 6</a></li>
119 <hr/>
118 <hr/>
120 <li id="toggle_output"><a href="#">Toggle Output</a></li>
119 <li id="toggle_output"><a href="#">Toggle Output</a></li>
121 <li id="clear_all_output"><a href="#">Clear All Output</a></li>
120 <li id="clear_all_output"><a href="#">Clear All Output</a></li>
122 </ul>
121 </ul>
123 </li>
122 </li>
124 <li><a href="#">Kernel</a>
123 <li><a href="#">Kernel</a>
125 <ul>
124 <ul>
126 <li id="int_kernel"><a href="#">Interrupt</a></li>
125 <li id="int_kernel"><a href="#">Interrupt</a></li>
127 <li id="restart_kernel"><a href="#">Restart</a></li>
126 <li id="restart_kernel"><a href="#">Restart</a></li>
128 </ul>
127 </ul>
129 </li>
128 </li>
130 <li><a href="#">Help</a>
129 <li><a href="#">Help</a>
131 <ul>
130 <ul>
132 <li><a href="http://ipython.org/documentation.html" target="_blank">IPython Help</a></li>
131 <li><a href="http://ipython.org/documentation.html" target="_blank">IPython Help</a></li>
133 <li><a href="http://ipython.org/ipython-doc/stable/interactive/htmlnotebook.html" target="_blank">Notebook Help</a></li>
132 <li><a href="http://ipython.org/ipython-doc/stable/interactive/htmlnotebook.html" target="_blank">Notebook Help</a></li>
134 <li id="keyboard_shortcuts"><a href="#">Keyboard Shortcuts</a></li>
133 <li id="keyboard_shortcuts"><a href="#">Keyboard Shortcuts</a></li>
135 <hr/>
134 <hr/>
136 <li><a href="http://docs.python.org" target="_blank">Python</a></li>
135 <li><a href="http://docs.python.org" target="_blank">Python</a></li>
137 <li><a href="http://docs.scipy.org/doc/numpy/reference/" target="_blank">NumPy</a></li>
136 <li><a href="http://docs.scipy.org/doc/numpy/reference/" target="_blank">NumPy</a></li>
138 <li><a href="http://docs.scipy.org/doc/scipy/reference/" target="_blank">SciPy</a></li>
137 <li><a href="http://docs.scipy.org/doc/scipy/reference/" target="_blank">SciPy</a></li>
139 <li><a href="http://docs.sympy.org/dev/index.html" target="_blank">SymPy</a></li>
138 <li><a href="http://docs.sympy.org/dev/index.html" target="_blank">SymPy</a></li>
140 <li><a href="http://matplotlib.sourceforge.net/" target="_blank">Matplotlib</a></li>
139 <li><a href="http://matplotlib.sourceforge.net/" target="_blank">Matplotlib</a></li>
141 </ul>
140 </ul>
142 </li>
141 </li>
143 </ul>
142 </ul>
144
143
145 </div>
144 </div>
146 <div id="notification"></div>
145 <div id="notification"></div>
147 </div>
146 </div>
148
147
149
148
150 <div id="toolbar">
149 <div id="toolbar">
151
150
152 <span>
151 <span>
153 <button id="save_b">Save</button>
152 <button id="save_b">Save</button>
154 </span>
153 </span>
155 <span id="cut_copy_paste">
154 <span id="cut_copy_paste">
156 <button id="cut_b" title="Cut Cell">Cut Cell</button>
155 <button id="cut_b" title="Cut Cell">Cut Cell</button>
157 <button id="copy_b" title="Copy Cell">Copy Cell</button>
156 <button id="copy_b" title="Copy Cell">Copy Cell</button>
158 <button id="paste_b" title="Paste Cell">Paste Cell</button>
157 <button id="paste_b" title="Paste Cell">Paste Cell</button>
159 </span>
158 </span>
160 <span id="move_up_down">
159 <span id="move_up_down">
161 <button id="move_up_b" title="Move Cell Up">Move Cell Up</button>
160 <button id="move_up_b" title="Move Cell Up">Move Cell Up</button>
162 <button id="move_down_b" title="Move Cell Down">Move Down</button>
161 <button id="move_down_b" title="Move Cell Down">Move Down</button>
163 </span>
162 </span>
164 <span id="insert_above_below">
163 <span id="insert_above_below">
165 <button id="insert_above_b" title="Insert Cell Above">Insert Cell Above</button>
164 <button id="insert_above_b" title="Insert Cell Above">Insert Cell Above</button>
166 <button id="insert_below_b" title="Insert Cell Below">Insert Cell Below</button>
165 <button id="insert_below_b" title="Insert Cell Below">Insert Cell Below</button>
167 </span>
166 </span>
168 <span id="run_int">
167 <span id="run_int">
169 <button id="run_b" title="Run Cell">Run Cell</button>
168 <button id="run_b" title="Run Cell">Run Cell</button>
170 <button id="interrupt_b" title="Interrupt">Interrupt</button>
169 <button id="interrupt_b" title="Interrupt">Interrupt</button>
171 </span>
170 </span>
172 <span>
171 <span>
173 <select id="cell_type">
172 <select id="cell_type">
174 <option value="code">Code</option>
173 <option value="code">Code</option>
175 <option value="markdown">Markdown</option>
174 <option value="markdown">Markdown</option>
176 <option value="raw">Raw Text</option>
175 <option value="raw">Raw Text</option>
177 <option value="heading1">Heading 1</option>
176 <option value="heading1">Heading 1</option>
178 <option value="heading2">Heading 2</option>
177 <option value="heading2">Heading 2</option>
179 <option value="heading3">Heading 3</option>
178 <option value="heading3">Heading 3</option>
180 <option value="heading4">Heading 4</option>
179 <option value="heading4">Heading 4</option>
181 <option value="heading5">Heading 5</option>
180 <option value="heading5">Heading 5</option>
182 <option value="heading6">Heading 6</option>
181 <option value="heading6">Heading 6</option>
183 </select>
182 </select>
184 </span>
183 </span>
185
184
186 </div>
185 </div>
187
186
188 <div id="main_app">
187 <div id="main_app">
189
188
190 <div id="notebook_panel">
189 <div id="notebook_panel">
191 <div id="notebook"></div>
190 <div id="notebook"></div>
192 <div id="pager_splitter"></div>
191 <div id="pager_splitter"></div>
193 <div id="pager"></div>
192 <div id="pager"></div>
194 </div>
193 </div>
195
194
196 </div>
195 </div>
197
196
198 {% end %}
197 {% end %}
199
198
200
199
201 {% block script %}
200 {% block script %}
202
201
203 <script src="{{ static_url("codemirror/lib/codemirror.js") }}" charset="utf-8"></script>
202 <script src="{{ static_url("codemirror/lib/codemirror.js") }}" charset="utf-8"></script>
204 <script src="{{ static_url("codemirror/mode/python/python.js") }}" charset="utf-8"></script>
203 <script src="{{ static_url("codemirror/mode/python/python.js") }}" charset="utf-8"></script>
205 <script src="{{ static_url("codemirror/mode/htmlmixed/htmlmixed.js") }}" charset="utf-8"></script>
204 <script src="{{ static_url("codemirror/mode/htmlmixed/htmlmixed.js") }}" charset="utf-8"></script>
206 <script src="{{ static_url("codemirror/mode/xml/xml.js") }}" charset="utf-8"></script>
205 <script src="{{ static_url("codemirror/mode/xml/xml.js") }}" charset="utf-8"></script>
207 <script src="{{ static_url("codemirror/mode/javascript/javascript.js") }}" charset="utf-8"></script>
206 <script src="{{ static_url("codemirror/mode/javascript/javascript.js") }}" charset="utf-8"></script>
208 <script src="{{ static_url("codemirror/mode/css/css.js") }}" charset="utf-8"></script>
207 <script src="{{ static_url("codemirror/mode/css/css.js") }}" charset="utf-8"></script>
209 <script src="{{ static_url("codemirror/mode/rst/rst.js") }}" charset="utf-8"></script>
208 <script src="{{ static_url("codemirror/mode/rst/rst.js") }}" charset="utf-8"></script>
210 <script src="{{ static_url("codemirror/mode/markdown/markdown.js") }}" charset="utf-8"></script>
209 <script src="{{ static_url("codemirror/mode/markdown/markdown.js") }}" charset="utf-8"></script>
211
210
212 <script src="{{ static_url("pagedown/Markdown.Converter.js") }}" charset="utf-8"></script>
211 <script src="{{ static_url("pagedown/Markdown.Converter.js") }}" charset="utf-8"></script>
213
212
214 <script src="{{ static_url("prettify/prettify.js") }}" charset="utf-8"></script>
213 <script src="{{ static_url("prettify/prettify.js") }}" charset="utf-8"></script>
215 <script src="{{ static_url("dateformat/date.format.js") }}" charset="utf-8"></script>
214 <script src="{{ static_url("dateformat/date.format.js") }}" charset="utf-8"></script>
216
215
217 <script src="{{ static_url("js/events.js") }}" type="text/javascript" charset="utf-8"></script>
216 <script src="{{ static_url("js/events.js") }}" type="text/javascript" charset="utf-8"></script>
218 <script src="{{ static_url("js/utils.js") }}" type="text/javascript" charset="utf-8"></script>
217 <script src="{{ static_url("js/utils.js") }}" type="text/javascript" charset="utf-8"></script>
219 <script src="{{ static_url("js/layoutmanager.js") }}" type="text/javascript" charset="utf-8"></script>
218 <script src="{{ static_url("js/layoutmanager.js") }}" type="text/javascript" charset="utf-8"></script>
220 <script src="{{ static_url("js/initmathjax.js") }}" type="text/javascript" charset="utf-8"></script>
219 <script src="{{ static_url("js/initmathjax.js") }}" type="text/javascript" charset="utf-8"></script>
221 <script src="{{ static_url("js/cell.js") }}" type="text/javascript" charset="utf-8"></script>
220 <script src="{{ static_url("js/cell.js") }}" type="text/javascript" charset="utf-8"></script>
222 <script src="{{ static_url("js/codecell.js") }}" type="text/javascript" charset="utf-8"></script>
221 <script src="{{ static_url("js/codecell.js") }}" type="text/javascript" charset="utf-8"></script>
222 <script src="{{ static_url("js/completer.js") }}" type="text/javascript" charset="utf-8"></script>
223 <script src="{{ static_url("js/textcell.js") }}" type="text/javascript" charset="utf-8"></script>
223 <script src="{{ static_url("js/textcell.js") }}" type="text/javascript" charset="utf-8"></script>
224 <script src="{{ static_url("js/kernel.js") }}" type="text/javascript" charset="utf-8"></script>
224 <script src="{{ static_url("js/kernel.js") }}" type="text/javascript" charset="utf-8"></script>
225 <script src="{{ static_url("js/savewidget.js") }}" type="text/javascript" charset="utf-8"></script>
225 <script src="{{ static_url("js/savewidget.js") }}" type="text/javascript" charset="utf-8"></script>
226 <script src="{{ static_url("js/quickhelp.js") }}" type="text/javascript" charset="utf-8"></script>
226 <script src="{{ static_url("js/quickhelp.js") }}" type="text/javascript" charset="utf-8"></script>
227 <script src="{{ static_url("js/pager.js") }}" type="text/javascript" charset="utf-8"></script>
227 <script src="{{ static_url("js/pager.js") }}" type="text/javascript" charset="utf-8"></script>
228 <script src="{{ static_url("js/menubar.js") }}" type="text/javascript" charset="utf-8"></script>
228 <script src="{{ static_url("js/menubar.js") }}" type="text/javascript" charset="utf-8"></script>
229 <script src="{{ static_url("js/toolbar.js") }}" type="text/javascript" charset="utf-8"></script>
229 <script src="{{ static_url("js/toolbar.js") }}" type="text/javascript" charset="utf-8"></script>
230 <script src="{{ static_url("js/notebook.js") }}" type="text/javascript" charset="utf-8"></script>
230 <script src="{{ static_url("js/notebook.js") }}" type="text/javascript" charset="utf-8"></script>
231 <script src="{{ static_url("js/notificationwidget.js") }}" type="text/javascript" charset="utf-8"></script>
231 <script src="{{ static_url("js/notificationwidget.js") }}" type="text/javascript" charset="utf-8"></script>
232 <script src="{{ static_url("js/notebookmain.js") }}" type="text/javascript" charset="utf-8"></script>
232 <script src="{{ static_url("js/notebookmain.js") }}" type="text/javascript" charset="utf-8"></script>
233
233
234 <script src="{{ static_url("js/context-hint.js") }} charset="utf-8"></script>
235 <script src="{{ static_url("codemirror/lib/util/simple-hint.js") }} charset="utf-8"></script>
236
234 {% end %}
237 {% end %}
235
238
General Comments 0
You need to be logged in to leave comments. Login now