##// END OF EJS Templates
Merge pull request #2333 from Carreau/metaui...
Brian E. Granger -
r9086:57b04505 merge
parent child Browse files
Show More
@@ -0,0 +1,53 b''
1 /*Css for the metadata edit area*/
2
3 .celltoolbar{
4 border:thin solid #DDD;
5 margin-left:81px;
6 border-bottom:none;
7 background : #EEE;
8 border-top-right-radius: 3px;
9 border-top-left-radius: 3px;
10 display:none;
11 }
12
13 .code_cell .celltoolbar{
14 margin-left:81px;
15 }
16
17 .text_cell .celltoolbar{
18 margin-left:0px;
19 }
20
21 .celltoolbar-on div.input_area , .celltoolbar-on div.text_cell_input{
22 border-top-right-radius: 0px;
23 border-top-left-radius: 0px;
24 }
25
26 .celltoolbar-on .celltoolbar {
27 display:block;
28 }
29
30 .celltoolbar ui-button {
31 border :none;
32 }
33
34 .button_container {
35 float:right;
36 }
37
38 .button_container .ui-state-default, .button_container .ui-state-hover, .button_container .ui-state-hover span{
39 border-radius : 0 0 0 0;
40 border : none;
41 }
42
43 .celltoolbar select {
44 margin:10px;
45 margin-top:0px;
46 margin-bottom:0px;
47 }
48
49 .celltoolbar input[type=checkbox] {
50 margin-bottom:1px;
51
52 }
53
@@ -0,0 +1,358 b''
1 //----------------------------------------------------------------------------
2 // Copyright (C) 2012 The IPython Development Team
3 //
4 // Distributed under the terms of the BSD License. The full license is in
5 // the file COPYING, distributed as part of this software.
6 //----------------------------------------------------------------------------
7
8 //============================================================================
9 // CellToolbar
10 //============================================================================
11
12
13 /**
14 * A Module to control the per-cell toolbar.
15 * @module IPython
16 * @namespace IPython
17 * @submodule CellToolbar
18 */
19 var IPython = (function (IPython) {
20 "use strict";
21
22
23 /**
24 * @constructor
25 * @class CellToolbar
26 * @param {The cell to attach the metadata UI to} cell
27 */
28 var CellToolbar = function (cell) {
29 CellToolbar._instances.push(this);
30 this.inner_element = $('<div/>');
31 this.cell = cell;
32 this.element = $('<div/>').addClass('celltoolbar')
33 .append(this.inner_element)
34 this.rebuild();
35 return this;
36 };
37
38 CellToolbar.dropdown_preset_element = $('<select/>')
39 .addClass('ui-widget ui-widget-content')
40 .attr('id', 'celltoolbar_selector')
41 .append($('<option/>').attr('value', '').text('None'))
42
43 CellToolbar.dropdown_preset_element.change(function(){
44 var val = CellToolbar.dropdown_preset_element.val()
45 if(val ==''){
46 $('body').removeClass('celltoolbar-on')
47 } else {
48 $('body').addClass('celltoolbar-on')
49 CellToolbar.activate_preset(val)
50 }
51 })
52
53
54
55 /**
56 * Class variable that should contain a dict of all availlable callback
57 * we need to think of wether or not we allow nested namespace
58 * @property _callback_dict
59 * @private
60 * @static
61 * @type Dict
62 */
63 CellToolbar._callback_dict = {};
64
65 /**
66 * Class variable that should contain the reverse order list of the button
67 * to add to the toolbar of each cell
68 * @property _ui_controls_list
69 * @private
70 * @static
71 * @type List
72 */
73 CellToolbar._ui_controls_list = [];
74
75 /**
76 * Class variable that should contains the CellToolbar instances for each
77 * cell of the notebook
78 *
79 * @private
80 * @property _instances
81 * @static
82 * @type List
83 */
84 CellToolbar._instances =[]
85
86 /**
87 * keep a list of all the availlabel presets for the toolbar
88 * @private
89 * @property _presets
90 * @static
91 * @type Dict
92 */
93 CellToolbar._presets ={}
94
95 // this is by design not a prototype.
96 /**
97 * Register a callback to create an UI element in a cell toolbar.
98 * @method register_callback
99 * @param name {String} name to use to refer to the callback. It is advised to use a prefix with the name
100 * for easier sorting and avoid collision
101 * @param callback {function(div, cell)} callback that will be called to generate the ui element
102 *
103 *
104 * The callback will receive the following element :
105 *
106 * * a div in which to add element.
107 * * the cell it is responsible from
108 *
109 * @example
110 *
111 * Example that create callback for a button that toggle between `true` and `false` label,
112 * with the metadata under the key 'foo' to reflect the status of the button.
113 *
114 * // first param reference to a DOM div
115 * // second param reference to the cell.
116 * var toggle = function(div, cell) {
117 * var button_container = $(div)
118 *
119 * // let's create a button that show the current value of the metadata
120 * var button = $('<div/>').button({label:String(cell.metadata.foo)});
121 *
122 * // On click, change the metadata value and update the button label
123 * button.click(function(){
124 * var v = cell.metadata.foo;
125 * cell.metadata.foo = !v;
126 * button.button("option", "label", String(!v));
127 * })
128 *
129 * // add the button to the DOM div.
130 * button_container.append(button);
131 * }
132 *
133 * // now we register the callback under the name `foo` to give the
134 * // user the ability to use it later
135 * CellToolbar.register_callback('foo', toggle);
136 */
137 CellToolbar.register_callback = function(name, callback){
138 // Overwrite if it already exists.
139 CellToolbar._callback_dict[name] = callback;
140 };
141
142 /**
143 * Register a preset of UI element in a cell toolbar.
144 * Not supported Yet.
145 * @method register_preset
146 * @param name {String} name to use to refer to the preset. It is advised to use a prefix with the name
147 * for easier sorting and avoid collision
148 * @param preset_list {List of String} reverse order of the button in the toolbar. Each String of the list
149 * should correspond to a name of a registerd callback.
150 *
151 * @private
152 * @example
153 *
154 * CellToolbar.register_callback('foo.c1', function(div, cell){...});
155 * CellToolbar.register_callback('foo.c2', function(div, cell){...});
156 * CellToolbar.register_callback('foo.c3', function(div, cell){...});
157 * CellToolbar.register_callback('foo.c4', function(div, cell){...});
158 * CellToolbar.register_callback('foo.c5', function(div, cell){...});
159 *
160 * CellToolbar.register_preset('foo.foo_preset1', ['foo.c1', 'foo.c2', 'foo.c5'])
161 * CellToolbar.register_preset('foo.foo_preset2', ['foo.c4', 'foo.c5'])
162 */
163 CellToolbar.register_preset = function(name, preset_list){
164 CellToolbar._presets[name] = preset_list
165 CellToolbar.dropdown_preset_element.append(
166 $('<option/>').attr('value', name).text(name)
167 )
168 }
169 /**
170 * Activate an UI preset from `register_preset`
171 *
172 * This does not update the selection UI.
173 *
174 * @method activate_preset
175 * @param preset_name {String} string corresponding to the preset name
176 *
177 * @static
178 * @private
179 * @example
180 *
181 * CellToolbar.activate_preset('foo.foo_preset1');
182 */
183 CellToolbar.activate_preset= function(preset_name){
184 var preset = CellToolbar._presets[preset_name];
185
186 if(preset != undefined){
187 CellToolbar._ui_controls_list = preset;
188 CellToolbar.rebuild_all();
189 }
190 }
191
192
193 // this is by design not a prototype.
194 /**
195 * This should be called on the class and not on a instance as it will trigger
196 * rebuild of all the instances.
197 * @method rebuild_all
198 * @static
199 *
200 */
201 CellToolbar.rebuild_all = function(){
202 for(var i in CellToolbar._instances){
203 CellToolbar._instances[i].rebuild();
204 }
205 }
206
207 /**
208 * Rebuild all the button on the toolbar to update it's state.
209 * @method rebuild
210 */
211 CellToolbar.prototype.rebuild = function(){
212 // strip evrything from the div
213 // which is probabli metainner.
214 // or this.element.
215 this.inner_element.empty();
216
217 var cdict = CellToolbar._callback_dict;
218 var preset = CellToolbar._ui_controls_list;
219 // Yes we iterate on the class varaible, not the instance one.
220 for ( var index in CellToolbar._ui_controls_list){
221 var local_div = $('<div/>').addClass('button_container');
222 // Note,
223 // do this the other way, wrap in try/catch and don't append if any errors.
224 this.inner_element.append(local_div)
225 cdict[preset[index]](local_div, this.cell)
226 }
227
228 }
229
230
231 /**
232 */
233 CellToolbar.utils = {};
234
235 /**
236 * A utility function to generate bindings between a checkbox and cell/metadata
237 * @method utils.checkbox_ui_generator
238 * @static
239 *
240 * @param name {string} Label in front of the checkbox
241 * @param setter {function( cell, newValue )}
242 * A setter method to set the newValue
243 * @param getter {function( cell )}
244 * A getter methods which return the current value.
245 *
246 * @return callback {function( div, cell )} Callback to be passed to `register_callback`
247 *
248 * @example
249 *
250 * An exmple that bind the subkey `slideshow.isSectionStart` to a checkbox with a `New Slide` label
251 *
252 * var newSlide = CellToolbar.utils.checkbox_ui_generator('New Slide',
253 * // setter
254 * function(cell, value){
255 * // we check that the slideshow namespace exist and create it if needed
256 * if (cell.metadata.slideshow == undefined){cell.metadata.slideshow = {}}
257 * // set the value
258 * cell.metadata.slideshow.isSectionStart = value
259 * },
260 * //geter
261 * function(cell){ var ns = cell.metadata.slideshow;
262 * // if the slideshow namespace does not exist return `undefined`
263 * // (will be interpreted as `false` by checkbox) otherwise
264 * // return the value
265 * return (ns == undefined)? undefined: ns.isSectionStart
266 * }
267 * );
268 *
269 * CellToolbar.register_callback('newSlide', newSlide);
270 *
271 */
272 CellToolbar.utils.checkbox_ui_generator = function(name, setter, getter){
273 return function(div, cell) {
274 var button_container = $(div)
275
276 var chkb = $('<input/>').attr('type', 'checkbox');
277 var lbl = $('<label/>').append($('<span/>').text(name).css('font-size', '77%'));
278 lbl.append(chkb);
279 chkb.attr("checked", getter(cell));
280
281 chkb.click(function(){
282 var v = getter(cell);
283 setter(cell, !v);
284 chkb.attr("checked", !v);
285 })
286 button_container.append($('<div/>').append(lbl));
287
288 }
289 }
290
291 /**
292 * A utility function to generate bindings between a dropdown list cell
293 * @method utils.select_ui_generator
294 * @static
295 *
296 * @param list_list {list of sublist} List of sublist of metadata value and name in the dropdown list.
297 * subslit shoud contain 2 element each, first a string that woul be displayed in the dropdown list,
298 * and second the corresponding value to be passed to setter/return by getter.
299 * @param setter {function( cell, newValue )}
300 * A setter method to set the newValue
301 * @param getter {function( cell )}
302 * A getter methods which return the current value of the metadata.
303 * @param [label=""] {String} optionnal label for the dropdown menu
304 *
305 * @return callback {function( div, cell )} Callback to be passed to `register_callback`
306 *
307 * @example
308 *
309 * var select_type = CellToolbar.utils.select_ui_generator([
310 * ["<None>" , undefined ],
311 * ["Header Slide" , "header_slide" ],
312 * ["Slide" , "slide" ],
313 * ["Fragment" , "fragment" ],
314 * ["Skip" , "skip" ],
315 * ],
316 * // setter
317 * function(cell, value){
318 * // we check that the slideshow namespace exist and create it if needed
319 * if (cell.metadata.slideshow == undefined){cell.metadata.slideshow = {}}
320 * // set the value
321 * cell.metadata.slideshow.slide_type = value
322 * },
323 * //geter
324 * function(cell){ var ns = cell.metadata.slideshow;
325 * // if the slideshow namespace does not exist return `undefined`
326 * // (will be interpreted as `false` by checkbox) otherwise
327 * // return the value
328 * return (ns == undefined)? undefined: ns.slide_type
329 * }
330 * CellToolbar.register_callback('slideshow.select', select_type);
331 *
332 */
333 CellToolbar.utils.select_ui_generator = function(list_list, setter, getter, label){
334 label= label? label: "";
335 return function(div, cell) {
336 var button_container = $(div)
337 var lbl = $("<label/>").append($('<span/>').text(label).css('font-size', '77%'));
338 var select = $('<select/>');
339 for(var itemn in list_list){
340 var opt = $('<option/>');
341 opt.attr('value', list_list[itemn][1])
342 opt.text(list_list[itemn][0])
343 select.append(opt);
344 }
345 select.val(getter(cell));
346 select.change(function(){
347 setter(cell, select.val());
348 });
349 button_container.append($('<div/>').append(lbl).append(select));
350
351 }
352 };
353
354
355 IPython.CellToolbar = CellToolbar;
356
357 return IPython;
358 }(IPython));
@@ -0,0 +1,94 b''
1 //----------------------------------------------------------------------------
2 // Copyright (C) 2012 The IPython Development Team
3 //
4 // Distributed under the terms of the BSD License. The full license is in
5 // the file COPYING, distributed as part of this software.
6 //----------------------------------------------------------------------------
7
8 //============================================================================
9 // CellToolbar Default
10 //============================================================================
11
12 /**
13 * Example Use for the CellToolbar library
14 */
15 // IIFE without asignement, we don't modifiy the IPython namespace
16 (function (IPython) {
17 "use strict";
18
19 var CellToolbar = IPython.CellToolbar;
20
21 var raw_edit = function(cell){
22
23 var md = cell.metadata
24 var error_div = $('<div/>').css('color','red')
25
26 var textarea = $('<textarea/>')
27 .attr('rows','13')
28 .attr('cols','75')
29 .attr('name','metadata')
30 .text(JSON.stringify(md, null,4)||'');
31 var dialogform = $('<div/>').attr('title','Edit the metadata')
32 .append(
33 $('<form/>').append(
34 $('<fieldset/>').append(
35 $('<label/>')
36 .attr('for','metadata')
37 .text("Manually edit the JSON below to manipulate the metadata for this cell. This assumes you know what you are doing and won't complain if it breaks your notebook. We also recommend putting your metadata attributes in an appropriately named sub-structure, so they don't conflict with those of others.")
38 )
39 .append(error_div)
40 .append($('<br/>'))
41 .append(
42 textarea
43 )
44 )
45 );
46 var editor = CodeMirror.fromTextArea(textarea[0], {
47 lineNumbers: true,
48 matchBrackets: true,
49 });
50 $(dialogform).dialog({
51 autoOpen: true,
52 height: 300,
53 width: 650,
54 modal: true,
55 buttons: {
56 "Ok": function() {
57 //validate json and set it
58 try {
59 var json = JSON.parse(editor.getValue());
60 cell.metadata = json;
61 $( this ).dialog( "close" );
62 }
63 catch(e)
64 {
65 error_div.text('Warning, invalid json, not saved');
66 }
67 },
68 Cancel: function() {
69 $( this ).dialog( "close" );
70 }
71 },
72 close: function() {
73 //cleanup on close
74 $(this).remove();
75 }
76 });
77 editor.refresh();
78 }
79
80 var add_raw_edit_button = function(div, cell) {
81 var button_container = div
82 var button = $('<div/>').button({label:'Raw Edit'})
83 .click(function(){raw_edit(cell); return false;})
84 button_container.append(button);
85 }
86
87 CellToolbar.register_callback('default.rawedit',add_raw_edit_button);
88 var example_preset = []
89 example_preset.push('default.rawedit');
90
91 CellToolbar.register_preset('Default',example_preset);
92 console.log('Default extension for metadata editting loaded.');
93
94 }(IPython));
@@ -0,0 +1,154 b''
1 //----------------------------------------------------------------------------
2 // Copyright (C) 2012 The IPython Development Team
3 //
4 // Distributed under the terms of the BSD License. The full license is in
5 // the file COPYING, distributed as part of this software.
6 //----------------------------------------------------------------------------
7
8 //============================================================================
9 // CellToolbar Example
10 //============================================================================
11
12 /**
13 * Example Use for the CellToolbar library
14 * add the following to your custom.js to load
15 * Celltoolbar UI for slideshow
16 *
17 * ```
18 * $.getScript('/static/js/celltoolbarpresets/example.js');
19 * ```
20 */
21 // IIFE without asignement, we don't modifiy the IPython namespace
22 (function (IPython) {
23 "use strict";
24
25 var CellToolbar = IPython.CellToolbar;
26
27 var example_preset = [];
28
29 var simple_button = function(div, cell) {
30 var button_container = $(div);
31 var button = $('<div/>').button({icons:{primary:'ui-icon-locked'}});
32 var fun = function(value){
33 try{
34 if(value){
35 cell.code_mirror.setOption('readOnly','nocursor')
36 button.button('option','icons',{primary:'ui-icon-locked'})
37 } else {
38 cell.code_mirror.setOption('readOnly',false)
39 button.button('option','icons',{primary:'ui-icon-unlocked'})
40 }
41 } catch(e){}
42
43 }
44 fun(cell.metadata.ro)
45 button.click(function(){
46 var v = cell.metadata.ro;
47 var locked = !v;
48 cell.metadata.ro = locked;
49 fun(locked)
50 })
51 .css('height','16px')
52 .css('width','35px');
53 button_container.append(button);
54 }
55
56 CellToolbar.register_callback('example.lock',simple_button);
57 example_preset.push('example.lock');
58
59 var toggle_test = function(div, cell) {
60 var button_container = $(div)
61 var button = $('<div/>')
62 .button({label:String(cell.metadata.foo)}).
63 css('width','65px');
64 button.click(function(){
65 var v = cell.metadata.foo;
66 cell.metadata.foo = !v;
67 button.button("option","label",String(!v));
68 })
69 button_container.append(button);
70 }
71
72 CellToolbar.register_callback('example.toggle',toggle_test);
73 example_preset.push('example.toggle');
74
75 var checkbox_test = CellToolbar.utils.checkbox_ui_generator('Yes/No',
76 // setter
77 function(cell, value){
78 // we check that the slideshow namespace exist and create it if needed
79 if (cell.metadata.yn_test == undefined){cell.metadata.yn_test = {}}
80 // set the value
81 cell.metadata.yn_test.value = value
82 },
83 //geter
84 function(cell){ var ns = cell.metadata.yn_test;
85 // if the slideshow namespace does not exist return `undefined`
86 // (will be interpreted as `false` by checkbox) otherwise
87 // return the value
88 return (ns == undefined)? undefined: ns.value
89 }
90 );
91
92
93 CellToolbar.register_callback('example.checkbox',checkbox_test);
94 example_preset.push('example.checkbox');
95
96 var select_test = CellToolbar.utils.select_ui_generator([
97 ["-" ,undefined ],
98 ["Header Slide" ,"header_slide" ],
99 ["Slide" ,"slide" ],
100 ["Fragment" ,"fragment" ],
101 ["Skip" ,"skip" ],
102 ],
103 // setter
104 function(cell,value){
105 // we check that the slideshow namespace exist and create it if needed
106 if (cell.metadata.test == undefined){cell.metadata.test = {}}
107 // set the value
108 cell.metadata.test.slide_type = value
109 },
110 //geter
111 function(cell){ var ns = cell.metadata.test;
112 // if the slideshow namespace does not exist return `undefined`
113 // (will be interpreted as `false` by checkbox) otherwise
114 // return the value
115 return (ns == undefined)? undefined: ns.slide_type
116 });
117
118 CellToolbar.register_callback('example.select',select_test);
119 example_preset.push('example.select');
120
121 var simple_dialog = function(title,text){
122 var dlg = $('<div/>').attr('title',title)
123 .append($('<p/>').text(text))
124 $(dlg).dialog({
125 autoOpen: true,
126 height: 300,
127 width: 650,
128 modal: true,
129 close: function() {
130 //cleanup on close
131 $(this).remove();
132 }
133 });
134 }
135
136 var add_simple_dialog_button = function(div, cell) {
137 var help_text = ["This is the Metadata editting UI.",
138 "It heavily rely on plugin to work ",
139 "and is still under developpement. You shouldn't wait too long before",
140 " seeing some customisable buttons in those toolbar."
141 ].join('\n')
142 var button_container = $(div)
143 var button = $('<div/>').button({label:'?'})
144 .click(function(){simple_dialog('help',help_text); return false;})
145 button_container.append(button);
146 }
147
148 CellToolbar.register_callback('example.help',add_simple_dialog_button)
149 example_preset.push('example.help')
150
151 CellToolbar.register_preset('Example',example_preset);
152 console.log('Example extension for metadata editting loaded.');
153
154 }(IPython));
@@ -1,414 +1,418 b''
1 1 /**
2 2 * Primary styles
3 3 *
4 4 * Author: IPython Development Team
5 5 */
6 6
7 7
8 8 body {
9 9 overflow: hidden;
10 10 }
11 11
12 12 blockquote {
13 13 border-left: 4px solid #DDD;
14 14 padding: 0 15px;
15 15 color: #777;
16 16 }
17 17
18 18 span#save_widget {
19 19 padding: 5px;
20 20 margin: 0px 0px 0px 300px;
21 21 display:inline-block;
22 22 }
23 23
24 24 span#notebook_name {
25 25 height: 1em;
26 26 line-height: 1em;
27 27 padding: 3px;
28 28 border: none;
29 29 font-size: 146.5%;
30 30 }
31 31
32
32 33 .ui-menubar-item .ui-button .ui-button-text {
33 34 padding: 0.4em 1.0em;
34 35 font-size: 100%;
35 36 }
36 37
37 38 .ui-menu {
38 39 -moz-box-shadow: 0px 6px 10px -1px #adadad;
39 40 -webkit-box-shadow: 0px 6px 10px -1px #adadad;
40 41 box-shadow: 0px 6px 10px -1px #adadad;
41 42 }
42 43
43 44 .ui-menu .ui-menu-item a {
44 45 border: 1px solid transparent;
45 46 padding: 2px 1.6em;
46 47 }
47 48
48 49 .ui-menu .ui-menu-item a.ui-state-focus {
49 50 margin: 0;
50 51 }
51 52
52 53 .ui-menu hr {
53 54 margin: 0.3em 0;
54 55 }
55 56
56 57 #menubar_container {
57 58 position: relative;
58 59 }
59 60
60 61 #notification_area {
61 62 position: absolute;
62 63 right: 0px;
63 64 top: 0px;
64 65 height: 25px;
65 66 padding: 3px 0px;
66 67 padding-right: 3px;
67 68 z-index: 10;
68 69 }
69 70
70 71 .notification_widget{
71 72 float : right;
72 73 right: 0px;
73 74 top: 1px;
74 75 height: 25px;
75 76 padding: 3px 6px;
76 77 z-index: 10;
77 78 }
78 79
79 80 .toolbar {
80 81 padding: 3px 15px;
81 82 }
82 83
83 #cell_type {
84 #maintoolbar > select, #maintoolbar label {
84 85 font-size: 85%;
86 margin-left:0.3em;
87 margin-right:0.3em;
88
85 89 }
86 90
87 91
88 92 div#main_app {
89 93 width: 100%;
90 94 position: relative;
91 95 }
92 96
93 97 span#quick_help_area {
94 98 position: static;
95 99 padding: 5px 0px;
96 100 margin: 0px 0px 0px 0px;
97 101 }
98 102
99 103 .help_string {
100 104 float: right;
101 105 width: 170px;
102 106 padding: 0px 5px;
103 107 text-align: left;
104 108 font-size: 85%;
105 109 }
106 110
107 111 .help_string_label {
108 112 float: right;
109 113 font-size: 85%;
110 114 }
111 115
112 116 div#notebook_panel {
113 117 margin: 0px 0px 0px 0px;
114 118 padding: 0px;
115 119 }
116 120
117 121 div#notebook {
118 122 overflow-y: scroll;
119 123 overflow-x: auto;
120 124 width: 100%;
121 125 /* This spaces the cell away from the edge of the notebook area */
122 126 padding: 5px 5px 15px 5px;
123 127 margin: 0px;
124 128 background-color: white;
125 129 }
126 130
127 131 div#pager_splitter {
128 132 height: 8px;
129 133 }
130 134
131 135 #pager_container {
132 136 position : relative;
133 137 }
134 138
135 139 div#pager {
136 140 padding: 15px;
137 141 overflow: auto;
138 142 display: none;
139 143 }
140 144
141 145 div.ui-widget-content {
142 146 border: 1px solid #aaa;
143 147 outline: none;
144 148 }
145 149
146 150 .cell {
147 151 border: 1px solid transparent;
148 152 }
149 153
150 154 div.cell {
151 155 width: 100%;
152 156 padding: 5px 5px 5px 0px;
153 157 /* This acts as a spacer between cells, that is outside the border */
154 158 margin: 2px 0px 2px 0px;
155 159 }
156 160
157 161 div.code_cell {
158 162 background-color: white;
159 163 }
160 164
161 165 /* any special styling for code cells that are currently running goes here */
162 166 div.code_cell.running {
163 167 }
164 168
165 169 div.prompt {
166 170 /* This needs to be wide enough for 3 digit prompt numbers: In[100]: */
167 171 width: 11ex;
168 172 /* This 0.4em is tuned to match the padding on the CodeMirror editor. */
169 173 padding: 0.4em;
170 174 margin: 0px;
171 175 font-family: monospace;
172 176 text-align:right;
173 177 }
174 178
175 179 div.input {
176 180 page-break-inside: avoid;
177 181 }
178 182
179 183 /* input_area and input_prompt must match in top border and margin for alignment */
180 184 div.input_area {
181 185 color: black;
182 186 border: 1px solid #ddd;
183 187 border-radius: 3px;
184 188 background: #f7f7f7;
185 189 }
186 190
187 191 div.input_prompt {
188 192 color: navy;
189 193 border-top: 1px solid transparent;
190 194 }
191 195
192 196 div.output_wrapper {
193 197 /* This is a spacer between the input and output of each cell */
194 198 margin-top: 5px;
195 199 margin-left: 5px;
196 200 /* FF needs explicit width to stretch */
197 201 width: 100%;
198 202 /* this position must be relative to enable descendents to be absolute within it */
199 203 position: relative;
200 204 }
201 205
202 206 /* class for the output area when it should be height-limited */
203 207 div.output_scroll {
204 208 /* ideally, this would be max-height, but FF barfs all over that */
205 209 height: 24em;
206 210 /* FF needs this *and the wrapper* to specify full width, or it will shrinkwrap */
207 211 width: 100%;
208 212
209 213 overflow: auto;
210 214 border-radius: 3px;
211 215 box-shadow: inset 0 2px 8px rgba(0, 0, 0, .8);
212 216 }
213 217
214 218 /* output div while it is collapsed */
215 219 div.output_collapsed {
216 220 margin-right: 5px;
217 221 }
218 222
219 223 div.out_prompt_overlay {
220 224 height: 100%;
221 225 padding: 0px;
222 226 position: absolute;
223 227 border-radius: 3px;
224 228 }
225 229
226 230 div.out_prompt_overlay:hover {
227 231 /* use inner shadow to get border that is computed the same on WebKit/FF */
228 232 box-shadow: inset 0 0 1px #000;
229 233 background: rgba(240, 240, 240, 0.5);
230 234 }
231 235
232 236 div.output_prompt {
233 237 color: darkred;
234 238 /* 5px right shift to account for margin in parent container */
235 239 margin: 0 5px 0 -5px;
236 240 }
237 241
238 242 /* This class is the outer container of all output sections. */
239 243 div.output_area {
240 244 padding: 0px;
241 245 page-break-inside: avoid;
242 246 }
243 247
244 248 /* This class is for the output subarea inside the output_area and after
245 249 the prompt div. */
246 250 div.output_subarea {
247 251 padding: 0.44em 0.4em 0.4em 1px;
248 252 }
249 253
250 254 /* The rest of the output_* classes are for special styling of the different
251 255 output types */
252 256
253 257 /* all text output has this class: */
254 258 div.output_text {
255 259 text-align: left;
256 260 color: black;
257 261 font-family: monospace;
258 262 }
259 263
260 264 /* stdout/stderr are 'text' as well as 'stream', but pyout/pyerr are *not* streams */
261 265 div.output_stream {
262 266 padding-top: 0.0em;
263 267 padding-bottom: 0.0em;
264 268 }
265 269 div.output_stdout {
266 270 }
267 271 div.output_stderr {
268 272 background: #fdd; /* very light red background for stderr */
269 273 }
270 274
271 275 div.output_latex {
272 276 text-align: left;
273 277 color: black;
274 278 }
275 279
276 280 div.output_html {
277 281 }
278 282
279 283 div.output_png {
280 284 }
281 285
282 286 div.output_jpeg {
283 287 }
284 288
285 289 div.text_cell {
286 290 background-color: white;
287 291 padding: 5px 5px 5px 5px;
288 292 }
289 293
290 294 div.text_cell_input {
291 295 color: black;
292 296 border: 1px solid #ddd;
293 297 border-radius: 3px;
294 298 background: #f7f7f7;
295 299 }
296 300
297 301 div.text_cell_render {
298 302 font-family: "Helvetica Neue", Arial, Helvetica, Geneva, sans-serif;
299 303 outline: none;
300 304 resize: none;
301 305 width: inherit;
302 306 border-style: none;
303 307 padding: 5px;
304 308 color: black;
305 309 }
306 310
307 311 /* The following gets added to the <head> if it is detected that the user has a
308 312 * monospace font with inconsistent normal/bold/italic height. See
309 313 * notebookmain.js. Such fonts will have keywords vertically offset with
310 314 * respect to the rest of the text. The user should select a better font.
311 315 * See: https://github.com/ipython/ipython/issues/1503
312 316 *
313 317 * .CodeMirror span {
314 318 * vertical-align: bottom;
315 319 * }
316 320 */
317 321
318 322 .CodeMirror {
319 323 line-height: 1.231; /* Changed from 1em to our global default */
320 324 }
321 325
322 326 .CodeMirror-scroll {
323 327 height: auto; /* Changed to auto to autogrow */
324 328 /* The CodeMirror docs are a bit fuzzy on if overflow-y should be hidden or visible.*/
325 329 /* We have found that if it is visible, vertical scrollbars appear with font size changes.*/
326 330 overflow-y: hidden;
327 331 overflow-x: auto; /* Changed from auto to remove scrollbar */
328 332 }
329 333
330 334 /* CSS font colors for translated ANSI colors. */
331 335
332 336
333 337 .ansiblack {color: black;}
334 338 .ansired {color: darkred;}
335 339 .ansigreen {color: darkgreen;}
336 340 .ansiyellow {color: brown;}
337 341 .ansiblue {color: darkblue;}
338 342 .ansipurple {color: darkviolet;}
339 343 .ansicyan {color: steelblue;}
340 344 .ansigrey {color: grey;}
341 345 .ansibold {font-weight: bold;}
342 346
343 347 .completions {
344 348 position: absolute;
345 349 z-index: 10;
346 350 overflow: hidden;
347 351 border: 1px solid grey;
348 352 }
349 353
350 354 .completions select {
351 355 background: white;
352 356 outline: none;
353 357 border: none;
354 358 padding: 0px;
355 359 margin: 0px;
356 360 overflow: auto;
357 361 font-family: monospace;
358 362 }
359 363
360 364 option.context {
361 365 background-color: #DEF7FF;
362 366 }
363 367 option.introspection {
364 368 background-color: #EBF4EB;
365 369 }
366 370
367 371 /*fixed part of the completion*/
368 372 .completions p b {
369 373 font-weight:bold;
370 374 }
371 375
372 376 .completions p {
373 377 background: #DDF;
374 378 /*outline: none;
375 379 padding: 0px;*/
376 380 border-bottom: black solid 1px;
377 381 padding: 1px;
378 382 font-family: monospace;
379 383 }
380 384
381 385 pre.dialog {
382 386 background-color: #f7f7f7;
383 387 border: 1px solid #ddd;
384 388 border-radius: 3px;
385 389 padding: 0.4em;
386 390 padding-left: 2em;
387 391 }
388 392
389 393 p.dialog {
390 394 padding : 0.2em;
391 395 }
392 396
393 397 .shortcut_key {
394 398 display: inline-block;
395 399 width: 15ex;
396 400 text-align: right;
397 401 font-family: monospace;
398 402 }
399 403
400 404 .shortcut_descr {
401 405 }
402 406
403 407 /* Word-wrap output correctly. This is the CSS3 spelling, though Firefox seems
404 408 to not honor it correctly. Webkit browsers (Chrome, rekonq, Safari) do.
405 409 */
406 410 pre, code, kbd, samp { white-space: pre-wrap; }
407 411
408 412 #fonttest {
409 413 font-family: monospace;
410 414 }
411 415
412 416 .js-error {
413 417 color: darkred;
414 418 }
@@ -1,312 +1,315 b''
1 1 //----------------------------------------------------------------------------
2 2 // Copyright (C) 2008-2011 The IPython Development Team
3 3 //
4 4 // Distributed under the terms of the BSD License. The full license is in
5 5 // the file COPYING, distributed as part of this software.
6 6 //----------------------------------------------------------------------------
7 7
8 8 //============================================================================
9 9 // Cell
10 10 //============================================================================
11 11 /**
12 12 * An extendable module that provide base functionnality to create cell for notebook.
13 13 * @module IPython
14 14 * @namespace IPython
15 15 * @submodule Cell
16 16 */
17 17
18 18 var IPython = (function (IPython) {
19 19
20 20 var utils = IPython.utils;
21 21
22 22 /**
23 23 * The Base `Cell` class from which to inherit
24 24 * @class Cell
25 25 */
26 26
27 27 /*
28 28 * @constructor
29 29 */
30 30 var Cell = function () {
31 31 this.placeholder = this.placeholder || '';
32 32 this.read_only = false;
33 33 this.selected = false;
34 34 this.element = null;
35 35 this.metadata = {};
36 36 // load this from metadata later ?
37 37 this.user_highlight = 'auto';
38 38 this.create_element();
39 39 if (this.element !== null) {
40 40 this.element.data("cell", this);
41 41 this.bind_events();
42 42 }
43 43 this.cell_id = utils.uuid();
44 44 };
45 45
46 46
47 47 /**
48 48 * Empty. Subclasses must implement create_element.
49 49 * This should contain all the code to create the DOM element in notebook
50 50 * and will be called by Base Class constructor.
51 51 * @method create_element
52 52 */
53 Cell.prototype.create_element = function () {};
53 Cell.prototype.create_element = function () {
54 this.celltoolbar = new IPython.CellToolbar(this);
55 };
54 56
55 57
56 58 /**
57 59 * Subclasses can implement override bind_events.
58 60 * Be carefull to call the parent method when overwriting as it fires event.
59 61 * this will be triggerd after create_element in constructor.
60 62 * @method bind_events
61 63 */
62 64 Cell.prototype.bind_events = function () {
63 65 var that = this;
64 66 // We trigger events so that Cell doesn't have to depend on Notebook.
65 67 that.element.click(function (event) {
66 68 if (that.selected === false) {
67 69 $([IPython.events]).trigger('select.Cell', {'cell':that});
68 70 }
69 71 });
70 72 that.element.focusin(function (event) {
71 73 if (that.selected === false) {
72 74 $([IPython.events]).trigger('select.Cell', {'cell':that});
73 75 }
74 76 });
75 77 };
76 78
77 79 /**
78 80 * Triger typsetting of math by mathjax on current cell element
79 81 * @method typeset
80 82 */
81 83 Cell.prototype.typeset = function () {
82 84 if (window.MathJax){
83 85 var cell_math = this.element.get(0);
84 86 MathJax.Hub.Queue(["Typeset",MathJax.Hub,cell_math]);
85 87 }
86 88 };
87 89
88 90 /**
89 91 * should be triggerd when cell is selected
90 92 * @method select
91 93 */
92 94 Cell.prototype.select = function () {
93 95 this.element.addClass('ui-widget-content ui-corner-all');
94 96 this.selected = true;
95 97 };
96 98
97 99
98 100 /**
99 101 * should be triggerd when cell is unselected
100 102 * @method unselect
101 103 */
102 104 Cell.prototype.unselect = function () {
103 105 this.element.removeClass('ui-widget-content ui-corner-all');
104 106 this.selected = false;
105 107 };
106 108
107 109 /**
108 110 * should be overritten by subclass
109 111 * @method get_text
110 112 */
111 113 Cell.prototype.get_text = function () {
112 114 };
113 115
114 116 /**
115 117 * should be overritten by subclass
116 118 * @method set_text
117 119 * @param {string} text
118 120 */
119 121 Cell.prototype.set_text = function (text) {
120 122 };
121 123
122 124 /**
123 125 * Refresh codemirror instance
124 126 * @method refresh
125 127 */
126 128 Cell.prototype.refresh = function () {
127 129 this.code_mirror.refresh();
128 130 };
129 131
130 132
131 133 /**
132 134 * should be overritten by subclass
133 135 * @method edit
134 136 **/
135 137 Cell.prototype.edit = function () {
136 138 };
137 139
138 140
139 141 /**
140 142 * should be overritten by subclass
141 143 * @method render
142 144 **/
143 145 Cell.prototype.render = function () {
144 146 };
145 147
146 148 /**
147 149 * should be overritten by subclass
148 150 * serialise cell to json.
149 151 * @method toJSON
150 152 **/
151 153 Cell.prototype.toJSON = function () {
152 154 var data = {};
153 155 data.metadata = this.metadata;
154 156 return data;
155 157 };
156 158
157 159
158 160 /**
159 161 * should be overritten by subclass
160 162 * @method fromJSON
161 163 **/
162 164 Cell.prototype.fromJSON = function (data) {
163 165 if (data.metadata !== undefined) {
164 166 this.metadata = data.metadata;
165 167 }
168 this.celltoolbar.rebuild();
166 169 };
167 170
168 171
169 172 /**
170 173 * can the cell be splitted in 2 cells.
171 174 * @method is_splittable
172 175 **/
173 176 Cell.prototype.is_splittable = function () {
174 177 return true;
175 178 };
176 179
177 180
178 181 /**
179 182 * @return {String} - the text before the cursor
180 183 * @method get_pre_cursor
181 184 **/
182 185 Cell.prototype.get_pre_cursor = function () {
183 186 var cursor = this.code_mirror.getCursor();
184 187 var text = this.code_mirror.getRange({line:0,ch:0}, cursor);
185 188 text = text.replace(/^\n+/, '').replace(/\n+$/, '');
186 189 return text;
187 190 }
188 191
189 192
190 193 /**
191 194 * @return {String} - the text after the cursor
192 195 * @method get_post_cursor
193 196 **/
194 197 Cell.prototype.get_post_cursor = function () {
195 198 var cursor = this.code_mirror.getCursor();
196 199 var last_line_num = this.code_mirror.lineCount()-1;
197 200 var last_line_len = this.code_mirror.getLine(last_line_num).length;
198 201 var end = {line:last_line_num, ch:last_line_len}
199 202 var text = this.code_mirror.getRange(cursor, end);
200 203 text = text.replace(/^\n+/, '').replace(/\n+$/, '');
201 204 return text;
202 205 };
203 206
204 207
205 208 /** Grow the cell by hand. This is used upon reloading from JSON, when the
206 209 * autogrow handler is not called.
207 210 *
208 211 * could be made static
209 212 *
210 213 * @param {Dom element} - element
211 214 * @method grow
212 215 **/
213 216 Cell.prototype.grow = function(element) {
214 217 var dom = element.get(0);
215 218 var lines_count = 0;
216 219 // modified split rule from
217 220 // http://stackoverflow.com/questions/2035910/how-to-get-the-number-of-lines-in-a-textarea/2036424#2036424
218 221 var lines = dom.value.split(/\r|\r\n|\n/);
219 222 lines_count = lines.length;
220 223 if (lines_count >= 1) {
221 224 dom.rows = lines_count;
222 225 } else {
223 226 dom.rows = 1;
224 227 }
225 228 };
226 229
227 230 /**
228 231 * Toggle CodeMirror LineNumber
229 232 * @method toggle_line_numbers
230 233 **/
231 234 Cell.prototype.toggle_line_numbers = function () {
232 235 if (this.code_mirror.getOption('lineNumbers') == false) {
233 236 this.code_mirror.setOption('lineNumbers', true);
234 237 } else {
235 238 this.code_mirror.setOption('lineNumbers', false);
236 239 }
237 240 this.code_mirror.refresh();
238 241 };
239 242
240 243 /**
241 244 * force codemirror highlight mode
242 245 * @method force_highlight
243 246 * @param {object} - CodeMirror mode
244 247 **/
245 248 Cell.prototype.force_highlight = function(mode) {
246 249 this.user_highlight = mode;
247 250 this.auto_highlight();
248 251 };
249 252
250 253 /**
251 254 * Try to autodetect cell highlight mode, or use selected mode
252 255 * @methods _auto_highlight
253 256 * @private
254 257 * @param {String|object|undefined} - CodeMirror mode | 'auto'
255 258 **/
256 259 Cell.prototype._auto_highlight = function (modes) {
257 260 //Here we handle manually selected modes
258 261 if( this.user_highlight != undefined && this.user_highlight != 'auto' )
259 262 {
260 263 var mode = this.user_highlight;
261 264 CodeMirror.autoLoadMode(this.code_mirror, mode);
262 265 this.code_mirror.setOption('mode', mode);
263 266 return;
264 267 }
265 268 var first_line = this.code_mirror.getLine(0);
266 269 // loop on every pairs
267 270 for( var mode in modes) {
268 271 var regs = modes[mode]['reg'];
269 272 // only one key every time but regexp can't be keys...
270 273 for(var reg in regs ) {
271 274 // here we handle non magic_modes
272 275 if(first_line.match(regs[reg]) != null) {
273 276 if (mode.search('magic_') != 0) {
274 277 this.code_mirror.setOption('mode',mode);
275 278 CodeMirror.autoLoadMode(this.code_mirror, mode);
276 279 return;
277 280 }
278 281 var open = modes[mode]['open']|| "%%";
279 282 var close = modes[mode]['close']|| "%%end";
280 283 var mmode = mode;
281 284 mode = mmode.substr(6);
282 285 CodeMirror.autoLoadMode(this.code_mirror, mode);
283 286 // create on the fly a mode that swhitch between
284 287 // plain/text and smth else otherwise `%%` is
285 288 // source of some highlight issues.
286 289 // we use patchedGetMode to circumvent a bug in CM
287 290 CodeMirror.defineMode(mmode , function(config) {
288 291 return CodeMirror.multiplexingMode(
289 292 CodeMirror.patchedGetMode(config, 'text/plain'),
290 293 // always set someting on close
291 294 {open: open, close: close,
292 295 mode: CodeMirror.patchedGetMode(config, mode),
293 296 delimStyle: "delimit"
294 297 }
295 298 );
296 299 });
297 300 this.code_mirror.setOption('mode', mmode);
298 301 return;
299 302 }
300 303 }
301 304 }
302 305 // fallback on default (python)
303 306 var default_mode = this.default_mode || 'text/plain';
304 307 this.code_mirror.setOption('mode', default_mode);
305 308 };
306 309
307 310 IPython.Cell = Cell;
308 311
309 312 return IPython;
310 313
311 314 }(IPython));
312 315
@@ -1,378 +1,381 b''
1 1 //----------------------------------------------------------------------------
2 2 // Copyright (C) 2008-2011 The IPython Development Team
3 3 //
4 4 // Distributed under the terms of the BSD License. The full license is in
5 5 // the file COPYING, distributed as part of this software.
6 6 //----------------------------------------------------------------------------
7 7
8 8 //============================================================================
9 9 // CodeCell
10 10 //============================================================================
11 11 /**
12 12 * An extendable module that provide base functionnality to create cell for notebook.
13 13 * @module IPython
14 14 * @namespace IPython
15 15 * @submodule CodeCell
16 16 */
17 17
18 18 var IPython = (function (IPython) {
19 19 "use strict";
20 20
21 21 var utils = IPython.utils;
22 22 var key = IPython.utils.keycodes;
23 23 CodeMirror.modeURL = "/static/codemirror/mode/%N/%N.js";
24 24
25 25 /**
26 26 * A Cell conceived to write code.
27 27 *
28 28 * The kernel doesn't have to be set at creation time, in that case
29 29 * it will be null and set_kernel has to be called later.
30 30 * @class CodeCell
31 31 * @extends IPython.Cell
32 32 *
33 33 * @constructor
34 34 * @param {Object|null} kernel
35 35 */
36 36 var CodeCell = function (kernel) {
37 37 this.kernel = kernel || null;
38 38 this.code_mirror = null;
39 39 this.input_prompt_number = null;
40 40 this.collapsed = false;
41 41 this.default_mode = 'python';
42 42 IPython.Cell.apply(this, arguments);
43 43
44 44 var that = this;
45 45 this.element.focusout(
46 46 function() { that.auto_highlight(); }
47 47 );
48 48 };
49 49
50 50 CodeCell.prototype = new IPython.Cell();
51 51
52 52 /**
53 53 * @method auto_highlight
54 54 */
55 55 CodeCell.prototype.auto_highlight = function () {
56 56 this._auto_highlight(IPython.config.cell_magic_highlight)
57 57 };
58 58
59 59 /** @method create_element */
60 60 CodeCell.prototype.create_element = function () {
61 IPython.Cell.prototype.create_element.apply(this, arguments);
62
61 63 var cell = $('<div></div>').addClass('cell border-box-sizing code_cell vbox');
64 cell.append(this.celltoolbar.element);
62 65 cell.attr('tabindex','2');
63 66 var input = $('<div></div>').addClass('input hbox');
64 67 input.append($('<div/>').addClass('prompt input_prompt'));
65 68 var input_area = $('<div/>').addClass('input_area box-flex1');
66 69 this.code_mirror = CodeMirror(input_area.get(0), {
67 70 indentUnit : 4,
68 71 mode: 'python',
69 72 theme: 'ipython',
70 73 readOnly: this.read_only,
71 74 extraKeys: {"Tab": "indentMore","Shift-Tab" : "indentLess",'Backspace':"delSpaceToPrevTabStop"},
72 75 onKeyEvent: $.proxy(this.handle_codemirror_keyevent,this),
73 76 matchBrackets: true
74 77 });
75 78 input.append(input_area);
76 79 var output = $('<div></div>');
77 80 cell.append(input).append(output);
78 81 this.element = cell;
79 82 this.output_area = new IPython.OutputArea(output, true);
80 83
81 84 // construct a completer only if class exist
82 85 // otherwise no print view
83 86 if (IPython.Completer !== undefined)
84 87 {
85 88 this.completer = new IPython.Completer(this);
86 89 }
87 90 };
88 91
89 92 /**
90 93 * This method gets called in CodeMirror's onKeyDown/onKeyPress
91 94 * handlers and is used to provide custom key handling. Its return
92 95 * value is used to determine if CodeMirror should ignore the event:
93 96 * true = ignore, false = don't ignore.
94 97 * @method handle_codemirror_keyevent
95 98 */
96 99 CodeCell.prototype.handle_codemirror_keyevent = function (editor, event) {
97 100
98 101 if (this.read_only){
99 102 return false;
100 103 }
101 104
102 105 var that = this;
103 106 // whatever key is pressed, first, cancel the tooltip request before
104 107 // they are sent, and remove tooltip if any, except for tab again
105 108 if (event.type === 'keydown' && event.which != key.TAB ) {
106 109 IPython.tooltip.remove_and_cancel_tooltip();
107 110 };
108 111
109 112 var cur = editor.getCursor();
110 113 if (event.keyCode === key.ENTER){
111 114 this.auto_highlight();
112 115 }
113 116
114 117 if (event.keyCode === key.ENTER && (event.shiftKey || event.ctrlKey)) {
115 118 // Always ignore shift-enter in CodeMirror as we handle it.
116 119 return true;
117 120 } else if (event.which === 40 && event.type === 'keypress' && IPython.tooltip.time_before_tooltip >= 0) {
118 121 // triger on keypress (!) otherwise inconsistent event.which depending on plateform
119 122 // browser and keyboard layout !
120 123 // Pressing '(' , request tooltip, don't forget to reappend it
121 124 IPython.tooltip.pending(that);
122 125 } else if (event.which === key.UPARROW && event.type === 'keydown') {
123 126 // If we are not at the top, let CM handle the up arrow and
124 127 // prevent the global keydown handler from handling it.
125 128 if (!that.at_top()) {
126 129 event.stop();
127 130 return false;
128 131 } else {
129 132 return true;
130 133 };
131 134 } else if (event.which === key.ESC) {
132 135 IPython.tooltip.remove_and_cancel_tooltip(true);
133 136 return true;
134 137 } else if (event.which === key.DOWNARROW && event.type === 'keydown') {
135 138 // If we are not at the bottom, let CM handle the down arrow and
136 139 // prevent the global keydown handler from handling it.
137 140 if (!that.at_bottom()) {
138 141 event.stop();
139 142 return false;
140 143 } else {
141 144 return true;
142 145 };
143 146 } else if (event.keyCode === key.TAB && event.type == 'keydown' && event.shiftKey) {
144 147 if (editor.somethingSelected()){
145 148 var anchor = editor.getCursor("anchor");
146 149 var head = editor.getCursor("head");
147 150 if( anchor.line != head.line){
148 151 return false;
149 152 }
150 153 }
151 154 IPython.tooltip.request(that);
152 155 event.stop();
153 156 return true;
154 157 } else if (event.keyCode === key.TAB && event.type == 'keydown') {
155 158 // Tab completion.
156 159 //Do not trim here because of tooltip
157 160 if (editor.somethingSelected()){return false}
158 161 var pre_cursor = editor.getRange({line:cur.line,ch:0},cur);
159 162 if (pre_cursor.trim() === "") {
160 163 // Don't autocomplete if the part of the line before the cursor
161 164 // is empty. In this case, let CodeMirror handle indentation.
162 165 return false;
163 166 } else if ((pre_cursor.substr(-1) === "("|| pre_cursor.substr(-1) === " ") && IPython.config.tooltip_on_tab ) {
164 167 IPython.tooltip.request(that);
165 168 // Prevent the event from bubbling up.
166 169 event.stop();
167 170 // Prevent CodeMirror from handling the tab.
168 171 return true;
169 172 } else {
170 173 event.stop();
171 174 this.completer.startCompletion();
172 175 return true;
173 176 };
174 177 } else {
175 178 // keypress/keyup also trigger on TAB press, and we don't want to
176 179 // use those to disable tab completion.
177 180 return false;
178 181 };
179 182 return false;
180 183 };
181 184
182 185
183 186 // Kernel related calls.
184 187
185 188 CodeCell.prototype.set_kernel = function (kernel) {
186 189 this.kernel = kernel;
187 190 }
188 191
189 192 /**
190 193 * Execute current code cell to the kernel
191 194 * @method execute
192 195 */
193 196 CodeCell.prototype.execute = function () {
194 197 this.output_area.clear_output(true, true, true);
195 198 this.set_input_prompt('*');
196 199 this.element.addClass("running");
197 200 var callbacks = {
198 201 'execute_reply': $.proxy(this._handle_execute_reply, this),
199 202 'output': $.proxy(this.output_area.handle_output, this.output_area),
200 203 'clear_output': $.proxy(this.output_area.handle_clear_output, this.output_area),
201 204 'set_next_input': $.proxy(this._handle_set_next_input, this)
202 205 };
203 206 var msg_id = this.kernel.execute(this.get_text(), callbacks, {silent: false});
204 207 };
205 208
206 209 /**
207 210 * @method _handle_execute_reply
208 211 * @private
209 212 */
210 213 CodeCell.prototype._handle_execute_reply = function (content) {
211 214 this.set_input_prompt(content.execution_count);
212 215 this.element.removeClass("running");
213 216 $([IPython.events]).trigger('set_dirty.Notebook', {'value': true});
214 217 }
215 218
216 219 CodeCell.prototype._handle_set_next_input = function (text) {
217 220 var data = {'cell': this, 'text': text}
218 221 $([IPython.events]).trigger('set_next_input.Notebook', data);
219 222 }
220 223
221 224 // Basic cell manipulation.
222 225
223 226 CodeCell.prototype.select = function () {
224 227 IPython.Cell.prototype.select.apply(this);
225 228 this.code_mirror.refresh();
226 229 this.code_mirror.focus();
227 230 this.auto_highlight();
228 231 // We used to need an additional refresh() after the focus, but
229 232 // it appears that this has been fixed in CM. This bug would show
230 233 // up on FF when a newly loaded markdown cell was edited.
231 234 };
232 235
233 236
234 237 CodeCell.prototype.select_all = function () {
235 238 var start = {line: 0, ch: 0};
236 239 var nlines = this.code_mirror.lineCount();
237 240 var last_line = this.code_mirror.getLine(nlines-1);
238 241 var end = {line: nlines-1, ch: last_line.length};
239 242 this.code_mirror.setSelection(start, end);
240 243 };
241 244
242 245
243 246 CodeCell.prototype.collapse = function () {
244 247 this.collapsed = true;
245 248 this.output_area.collapse();
246 249 };
247 250
248 251
249 252 CodeCell.prototype.expand = function () {
250 253 this.collapsed = false;
251 254 this.output_area.expand();
252 255 };
253 256
254 257
255 258 CodeCell.prototype.toggle_output = function () {
256 259 this.collapsed = Boolean(1 - this.collapsed);
257 260 this.output_area.toggle_output();
258 261 };
259 262
260 263
261 264 CodeCell.prototype.toggle_output_scroll = function () {
262 265 this.output_area.toggle_scroll();
263 266 };
264 267
265 268
266 269 CodeCell.input_prompt_classical = function (prompt_value, lines_number) {
267 270 var ns = prompt_value || "&nbsp;";
268 271 return 'In&nbsp;[' + ns + ']:'
269 272 };
270 273
271 274 CodeCell.input_prompt_continuation = function (prompt_value, lines_number) {
272 275 var html = [CodeCell.input_prompt_classical(prompt_value, lines_number)];
273 276 for(var i=1; i < lines_number; i++){html.push(['...:'])};
274 277 return html.join('</br>')
275 278 };
276 279
277 280 CodeCell.input_prompt_function = CodeCell.input_prompt_classical;
278 281
279 282
280 283 CodeCell.prototype.set_input_prompt = function (number) {
281 284 var nline = 1
282 285 if( this.code_mirror != undefined) {
283 286 nline = this.code_mirror.lineCount();
284 287 }
285 288 this.input_prompt_number = number;
286 289 var prompt_html = CodeCell.input_prompt_function(this.input_prompt_number, nline);
287 290 this.element.find('div.input_prompt').html(prompt_html);
288 291 };
289 292
290 293
291 294 CodeCell.prototype.clear_input = function () {
292 295 this.code_mirror.setValue('');
293 296 };
294 297
295 298
296 299 CodeCell.prototype.get_text = function () {
297 300 return this.code_mirror.getValue();
298 301 };
299 302
300 303
301 304 CodeCell.prototype.set_text = function (code) {
302 305 return this.code_mirror.setValue(code);
303 306 };
304 307
305 308
306 309 CodeCell.prototype.at_top = function () {
307 310 var cursor = this.code_mirror.getCursor();
308 311 if (cursor.line === 0 && cursor.ch === 0) {
309 312 return true;
310 313 } else {
311 314 return false;
312 315 }
313 316 };
314 317
315 318
316 319 CodeCell.prototype.at_bottom = function () {
317 320 var cursor = this.code_mirror.getCursor();
318 321 if (cursor.line === (this.code_mirror.lineCount()-1) && cursor.ch === this.code_mirror.getLine(cursor.line).length) {
319 322 return true;
320 323 } else {
321 324 return false;
322 325 }
323 326 };
324 327
325 328
326 329 CodeCell.prototype.clear_output = function (stdout, stderr, other) {
327 330 this.output_area.clear_output(stdout, stderr, other);
328 331 };
329 332
330 333
331 334 // JSON serialization
332 335
333 336 CodeCell.prototype.fromJSON = function (data) {
334 337 IPython.Cell.prototype.fromJSON.apply(this, arguments);
335 338 if (data.cell_type === 'code') {
336 339 if (data.input !== undefined) {
337 340 this.set_text(data.input);
338 341 // make this value the starting point, so that we can only undo
339 342 // to this state, instead of a blank cell
340 343 this.code_mirror.clearHistory();
341 344 this.auto_highlight();
342 345 }
343 346 if (data.prompt_number !== undefined) {
344 347 this.set_input_prompt(data.prompt_number);
345 348 } else {
346 349 this.set_input_prompt();
347 350 };
348 351 this.output_area.fromJSON(data.outputs);
349 352 if (data.collapsed !== undefined) {
350 353 if (data.collapsed) {
351 354 this.collapse();
352 355 } else {
353 356 this.expand();
354 357 };
355 358 };
356 359 };
357 360 };
358 361
359 362
360 363 CodeCell.prototype.toJSON = function () {
361 364 var data = IPython.Cell.prototype.toJSON.apply(this);
362 365 data.input = this.get_text();
363 366 data.cell_type = 'code';
364 367 if (this.input_prompt_number) {
365 368 data.prompt_number = this.input_prompt_number;
366 369 };
367 370 var outputs = this.output_area.toJSON();
368 371 data.outputs = outputs;
369 372 data.language = 'python';
370 373 data.collapsed = this.collapsed;
371 374 return data;
372 375 };
373 376
374 377
375 378 IPython.CodeCell = CodeCell;
376 379
377 380 return IPython;
378 381 }(IPython));
@@ -1,35 +1,47 b''
1 1 // leave at least 2 line with only a star on it below, or doc generation fails
2 2 /**
3 3 *
4 4 *
5 5 * Placeholder for custom user javascript
6 6 * mainly to be overridden in profile/static/js/custom.js
7 7 * This will always be an empty file in IPython
8 8 *
9 9 * User could add any javascript in the `profile/static/js/custom.js` file
10 10 * (and should create it if it does not exist).
11 11 * It will be executed by the ipython notebook at load time.
12 12 *
13 13 * Same thing with `profile/static/css/custom.css` to inject custom css into the notebook.
14 14 *
15 15 * Example :
16 16 *
17 17 * Create a custom button in toolbar that execute `%qtconsole` in kernel
18 18 * and hence open a qtconsole attached to the same kernel as the current notebook
19 19 *
20 20 * $([IPython.events]).on('notebook_loaded.Notebook', function(){
21 21 * IPython.toolbar.add_buttons_group([
22 22 * {
23 23 * 'label' : 'run qtconsole',
24 24 * 'icon' : 'ui-icon-calculator', // select your icon from http://jqueryui.com/themeroller/
25 25 * 'callback': function(){IPython.notebook.kernel.execute('%qtconsole')}
26 26 * }
27 27 * // add more button here if needed.
28 28 * ]);
29 29 * });
30 30 *
31 * Example :
32 *
33 * Use `jQuery.getScript(url [, success(script, textStatus, jqXHR)] );`
34 * to load custom script into the notebook.
35 *
36 * // to load the metadata ui extension example.
37 * $.getScript('/static/js/celltoolbarpresets/example.js');
38 * // or
39 * // to load the metadata ui extension to control slideshow mode / reveal js for nbconvert
40 * $.getScript('/static/js/celltoolbarpresets/slideshow.js');
41 *
42 *
31 43 * @module IPython
32 44 * @namespace IPython
33 45 * @class customjs
34 46 * @static
35 47 */
@@ -1,177 +1,178 b''
1 1 //----------------------------------------------------------------------------
2 2 // Copyright (C) 2011 The IPython Development Team
3 3 //
4 4 // Distributed under the terms of the BSD License. The full license is in
5 5 // the file COPYING, distributed as part of this software.
6 6 //----------------------------------------------------------------------------
7 7
8 8 //============================================================================
9 9 // ToolBar
10 10 //============================================================================
11 11
12 12 var IPython = (function (IPython) {
13 13
14 14 var MainToolBar = function (selector) {
15 15 this.selector = selector;
16 16 IPython.ToolBar.apply(this, arguments);
17 17 this.construct();
18 18 this.add_drop_down_list();
19 19 this.bind_events();
20 $(this.selector)
21 .append($('<label/>').text('Cell Toolbar:'))
22 .append(IPython.CellToolbar.dropdown_preset_element)
20 23 };
21 24
22 25 MainToolBar.prototype = new IPython.ToolBar();
23 26
24 27 MainToolBar.prototype.construct = function () {
25 28 this.add_buttons_group([
26 29 {
27 30 id : 'save_b',
28 31 label : 'Save',
29 32 icon : 'ui-icon-disk',
30 33 callback : function () {
31 34 IPython.notebook.save_notebook();
32 35 }
33 36 }
34 37 ]);
35 38 this.add_buttons_group([
36 39 {
37 40 id : 'cut_b',
38 41 label : 'Cut Cell',
39 42 icon : 'ui-icon-scissors',
40 43 callback : function () {
41 44 IPython.notebook.cut_cell();
42 45 }
43 46 },
44 47 {
45 48 id : 'copy_b',
46 49 label : 'Copy Cell',
47 50 icon : 'ui-icon-copy',
48 51 callback : function () {
49 52 IPython.notebook.copy_cell();
50 53 }
51 54 },
52 55 {
53 56 id : 'paste_b',
54 57 label : 'Paste Cell Below',
55 58 icon : 'ui-icon-clipboard',
56 59 callback : function () {
57 60 IPython.notebook.paste_cell_below();
58 61 }
59 62 }
60 63 ],'cut_copy_paste');
61 64
62 65 this.add_buttons_group([
63 66 {
64 67 id : 'move_up_b',
65 68 label : 'Move Cell Up',
66 69 icon : 'ui-icon-arrowthick-1-n',
67 70 callback : function () {
68 71 IPython.notebook.move_cell_up();
69 72 }
70 73 },
71 74 {
72 75 id : 'move_down_b',
73 76 label : 'Move Cell Down',
74 77 icon : 'ui-icon-arrowthick-1-s',
75 78 callback : function () {
76 79 IPython.notebook.move_cell_down();
77 80 }
78 81 }
79 82 ],'move_up_down');
80 83
81 84 this.add_buttons_group([
82 85 {
83 86 id : 'insert_above_b',
84 87 label : 'Insert Cell Above',
85 88 icon : 'ui-icon-arrowthickstop-1-n',
86 89 callback : function () {
87 90 IPython.notebook.insert_cell_above('code');
88 91 }
89 92 },
90 93 {
91 94 id : 'insert_below_b',
92 95 label : 'Insert Cell Below',
93 96 icon : 'ui-icon-arrowthickstop-1-s',
94 97 callback : function () {
95 98 IPython.notebook.insert_cell_below('code');
96 99 }
97 100 }
98 101 ],'insert_above_below');
99 102
100 103 this.add_buttons_group([
101 104 {
102 105 id : 'run_b',
103 106 label : 'Run Cell',
104 107 icon : 'ui-icon-play',
105 108 callback : function () {
106 109 IPython.notebook.execute_selected_cell();
107 110 }
108 111 },
109 112 {
110 113 id : 'interrupt_b',
111 114 label : 'Interrupt',
112 115 icon : 'ui-icon-stop',
113 116 callback : function () {
114 117 IPython.notebook.kernel.interrupt();
115 118 }
116 119 }
117 120 ],'run_int');
118
119
120 121 };
121 122
122 123 MainToolBar.prototype.add_drop_down_list = function () {
123 124 var select = $(this.selector)
124 125 .append($('<select/>')
125 126 .attr('id','cell_type')
126 127 .addClass('ui-widget ui-widget-content')
127 128 .append($('<option/>').attr('value','code').text('Code'))
128 129 .append($('<option/>').attr('value','markdown').text('Markdown'))
129 130 .append($('<option/>').attr('value','raw').text('Raw Text'))
130 131 .append($('<option/>').attr('value','heading1').text('Heading 1'))
131 132 .append($('<option/>').attr('value','heading2').text('Heading 2'))
132 133 .append($('<option/>').attr('value','heading3').text('Heading 3'))
133 134 .append($('<option/>').attr('value','heading4').text('Heading 4'))
134 135 .append($('<option/>').attr('value','heading5').text('Heading 5'))
135 136 .append($('<option/>').attr('value','heading6').text('Heading 6'))
136 137 );
137 138 };
138 139
139 140 MainToolBar.prototype.bind_events = function () {
140 141 var that = this;
141 142
142 143 this.element.find('#cell_type').change(function () {
143 144 var cell_type = $(this).val();
144 145 if (cell_type === 'code') {
145 146 IPython.notebook.to_code();
146 147 } else if (cell_type === 'markdown') {
147 148 IPython.notebook.to_markdown();
148 149 } else if (cell_type === 'raw') {
149 150 IPython.notebook.to_raw();
150 151 } else if (cell_type === 'heading1') {
151 152 IPython.notebook.to_heading(undefined, 1);
152 153 } else if (cell_type === 'heading2') {
153 154 IPython.notebook.to_heading(undefined, 2);
154 155 } else if (cell_type === 'heading3') {
155 156 IPython.notebook.to_heading(undefined, 3);
156 157 } else if (cell_type === 'heading4') {
157 158 IPython.notebook.to_heading(undefined, 4);
158 159 } else if (cell_type === 'heading5') {
159 160 IPython.notebook.to_heading(undefined, 5);
160 161 } else if (cell_type === 'heading6') {
161 162 IPython.notebook.to_heading(undefined, 6);
162 163 }
163 164 });
164 165 $([IPython.events]).on('selected_cell_type_changed.Notebook', function (event, data) {
165 166 if (data.cell_type === 'heading') {
166 167 that.element.find('#cell_type').val(data.cell_type+data.level);
167 168 } else {
168 169 that.element.find('#cell_type').val(data.cell_type);
169 170 }
170 171 });
171 172 };
172 173
173 174 IPython.MainToolBar = MainToolBar;
174 175
175 176 return IPython;
176 177
177 178 }(IPython));
@@ -1,531 +1,533 b''
1 1 //----------------------------------------------------------------------------
2 2 // Copyright (C) 2008-2012 The IPython Development Team
3 3 //
4 4 // Distributed under the terms of the BSD License. The full license is in
5 5 // the file COPYING, distributed as part of this software.
6 6 //----------------------------------------------------------------------------
7 7
8 8 //============================================================================
9 9 // TextCell
10 10 //============================================================================
11 11
12 12 /**
13 13 A module that allow to create different type of Text Cell
14 14 @module IPython
15 15 @namespace IPython
16 16 */
17 17 var IPython = (function (IPython) {
18 18
19 19 // TextCell base class
20 20 var key = IPython.utils.keycodes;
21 21
22 22 /**
23 23 * Construct a new TextCell, codemirror mode is by default 'htmlmixed', and cell type is 'text'
24 24 * cell start as not redered.
25 25 *
26 26 * @class TextCell
27 27 * @constructor TextCell
28 28 * @extend Ipython.Cell
29 29 */
30 30 var TextCell = function () {
31 31 this.code_mirror_mode = this.code_mirror_mode || 'htmlmixed';
32 32 IPython.Cell.apply(this, arguments);
33 33 this.rendered = false;
34 34 this.cell_type = this.cell_type || 'text';
35 35 };
36 36
37 37 TextCell.prototype = new IPython.Cell();
38 38
39 39 /**
40 40 * Create the DOM element of the TextCell
41 41 * @method create_element
42 42 * @private
43 43 */
44 44 TextCell.prototype.create_element = function () {
45 var cell = $("<div>").addClass('cell text_cell border-box-sizing');
45 IPython.Cell.prototype.create_element.apply(this, arguments);
46 var cell = $("<div>").addClass('cell text_cell border-box-sizing vbox');
47 cell.append(this.celltoolbar.element);
46 48 cell.attr('tabindex','2');
47 49 var input_area = $('<div/>').addClass('text_cell_input border-box-sizing');
48 50 this.code_mirror = CodeMirror(input_area.get(0), {
49 51 indentUnit : 4,
50 52 mode: this.code_mirror_mode,
51 53 theme: 'default',
52 54 value: this.placeholder,
53 55 readOnly: this.read_only,
54 56 lineWrapping : true,
55 57 extraKeys: {"Tab": "indentMore","Shift-Tab" : "indentLess"},
56 58 onKeyEvent: $.proxy(this.handle_codemirror_keyevent,this)
57 59 });
58 60 // The tabindex=-1 makes this div focusable.
59 61 var render_area = $('<div/>').addClass('text_cell_render border-box-sizing').
60 62 addClass('rendered_html').attr('tabindex','-1');
61 63 cell.append(input_area).append(render_area);
62 64 this.element = cell;
63 65 };
64 66
65 67
66 68 /**
67 69 * Bind the DOM evet to cell actions
68 70 * Need to be called after TextCell.create_element
69 71 * @private
70 72 * @method bind_event
71 73 */
72 74 TextCell.prototype.bind_events = function () {
73 75 IPython.Cell.prototype.bind_events.apply(this);
74 76 var that = this;
75 77 this.element.keydown(function (event) {
76 78 if (event.which === 13 && !event.shiftKey) {
77 79 if (that.rendered) {
78 80 that.edit();
79 81 return false;
80 82 };
81 83 };
82 84 });
83 85 this.element.dblclick(function () {
84 86 that.edit();
85 87 });
86 88 };
87 89
88 90 /**
89 91 * This method gets called in CodeMirror's onKeyDown/onKeyPress
90 92 * handlers and is used to provide custom key handling.
91 93 *
92 94 * Subclass should override this method to have custom handeling
93 95 *
94 96 * @method handle_codemirror_keyevent
95 97 * @param {CodeMirror} editor - The codemirror instance bound to the cell
96 98 * @param {event} event -
97 99 * @return {Boolean} `true` if CodeMirror should ignore the event, `false` Otherwise
98 100 */
99 101 TextCell.prototype.handle_codemirror_keyevent = function (editor, event) {
100 102
101 103 if (event.keyCode === 13 && (event.shiftKey || event.ctrlKey)) {
102 104 // Always ignore shift-enter in CodeMirror as we handle it.
103 105 return true;
104 106 }
105 107 return false;
106 108 };
107 109
108 110 /**
109 111 * Select the current cell and trigger 'focus'
110 112 * @method select
111 113 */
112 114 TextCell.prototype.select = function () {
113 115 IPython.Cell.prototype.select.apply(this);
114 116 var output = this.element.find("div.text_cell_render");
115 117 output.trigger('focus');
116 118 };
117 119
118 120 /**
119 121 * unselect the current cell and `render` it
120 122 * @method unselect
121 123 */
122 124 TextCell.prototype.unselect = function() {
123 125 // render on selection of another cell
124 126 this.render();
125 127 IPython.Cell.prototype.unselect.apply(this);
126 128 };
127 129
128 130 /**
129 131 *
130 132 * put the current cell in edition mode
131 133 * @method edit
132 134 */
133 135 TextCell.prototype.edit = function () {
134 136 if ( this.read_only ) return;
135 137 if (this.rendered === true) {
136 138 var text_cell = this.element;
137 139 var output = text_cell.find("div.text_cell_render");
138 140 output.hide();
139 141 text_cell.find('div.text_cell_input').show();
140 142 this.code_mirror.refresh();
141 143 this.code_mirror.focus();
142 144 // We used to need an additional refresh() after the focus, but
143 145 // it appears that this has been fixed in CM. This bug would show
144 146 // up on FF when a newly loaded markdown cell was edited.
145 147 this.rendered = false;
146 148 if (this.get_text() === this.placeholder) {
147 149 this.set_text('');
148 150 this.refresh();
149 151 }
150 152 }
151 153 };
152 154
153 155
154 156 /**
155 157 * Empty, Subclasses must define render.
156 158 * @method render
157 159 */
158 160 TextCell.prototype.render = function () {};
159 161
160 162
161 163 /**
162 164 * setter: {{#crossLink "TextCell/set_text"}}{{/crossLink}}
163 165 * @method get_text
164 166 * @retrun {string} CodeMirror current text value
165 167 */
166 168 TextCell.prototype.get_text = function() {
167 169 return this.code_mirror.getValue();
168 170 };
169 171
170 172 /**
171 173 * @param {string} text - Codemiror text value
172 174 * @see TextCell#get_text
173 175 * @method set_text
174 176 * */
175 177 TextCell.prototype.set_text = function(text) {
176 178 this.code_mirror.setValue(text);
177 179 this.code_mirror.refresh();
178 180 };
179 181
180 182 /**
181 183 * setter :{{#crossLink "TextCell/set_rendered"}}{{/crossLink}}
182 184 * @method get_rendered
183 185 * @return {html} html of rendered element
184 186 * */
185 187 TextCell.prototype.get_rendered = function() {
186 188 return this.element.find('div.text_cell_render').html();
187 189 };
188 190
189 191 /**
190 192 * @method set_rendered
191 193 */
192 194 TextCell.prototype.set_rendered = function(text) {
193 195 this.element.find('div.text_cell_render').html(text);
194 196 };
195 197
196 198 /**
197 199 * not deprecated, but implementation wrong
198 200 * @method at_top
199 201 * @deprecated
200 202 * @return {Boolean} true is cell rendered, false otherwise
201 203 * I doubt this is what it is supposed to do
202 204 * this implementation is completly false
203 205 */
204 206 TextCell.prototype.at_top = function () {
205 207 if (this.rendered) {
206 208 return true;
207 209 } else {
208 210 return false;
209 211 }
210 212 };
211 213
212 214
213 215 /**
214 216 * not deprecated, but implementation wrong
215 217 * @method at_bottom
216 218 * @deprecated
217 219 * @return {Boolean} true is cell rendered, false otherwise
218 220 * I doubt this is what it is supposed to do
219 221 * this implementation is completly false
220 222 * */
221 223 TextCell.prototype.at_bottom = function () {
222 224 if (this.rendered) {
223 225 return true;
224 226 } else {
225 227 return false;
226 228 }
227 229 };
228 230
229 231 /**
230 232 * Create Text cell from JSON
231 233 * @param {json} data - JSON serialized text-cell
232 234 * @method fromJSON
233 235 */
234 236 TextCell.prototype.fromJSON = function (data) {
235 237 IPython.Cell.prototype.fromJSON.apply(this, arguments);
236 238 if (data.cell_type === this.cell_type) {
237 239 if (data.source !== undefined) {
238 240 this.set_text(data.source);
239 241 // make this value the starting point, so that we can only undo
240 242 // to this state, instead of a blank cell
241 243 this.code_mirror.clearHistory();
242 244 this.set_rendered(data.rendered || '');
243 245 this.rendered = false;
244 246 this.render();
245 247 }
246 248 }
247 249 };
248 250
249 251 /** Generate JSON from cell
250 252 * @return {object} cell data serialised to json
251 253 */
252 254 TextCell.prototype.toJSON = function () {
253 255 var data = IPython.Cell.prototype.toJSON.apply(this);
254 256 data.cell_type = this.cell_type;
255 257 data.source = this.get_text();
256 258 return data;
257 259 };
258 260
259 261
260 262 /**
261 263 * @constructor HtmlCell
262 264 * @class HtmlCell
263 265 * @extends Ipython.TextCell
264 266 */
265 267 var HTMLCell = function () {
266 268 this.placeholder = "Type <strong>HTML</strong> and LaTeX: $\\alpha^2$";
267 269 IPython.TextCell.apply(this, arguments);
268 270 this.cell_type = 'html';
269 271 };
270 272
271 273
272 274 HTMLCell.prototype = new TextCell();
273 275
274 276 /**
275 277 * @method render
276 278 */
277 279 HTMLCell.prototype.render = function () {
278 280 if (this.rendered === false) {
279 281 var text = this.get_text();
280 282 if (text === "") { text = this.placeholder; }
281 283 this.set_rendered(text);
282 284 this.typeset();
283 285 this.element.find('div.text_cell_input').hide();
284 286 this.element.find("div.text_cell_render").show();
285 287 this.rendered = true;
286 288 }
287 289 };
288 290
289 291
290 292 /**
291 293 * @class MarkdownCell
292 294 * @constructor MarkdownCell
293 295 * @extends Ipython.HtmlCell
294 296 */
295 297 var MarkdownCell = function () {
296 298 this.placeholder = "Type *Markdown* and LaTeX: $\\alpha^2$";
297 299 IPython.TextCell.apply(this, arguments);
298 300 this.cell_type = 'markdown';
299 301 };
300 302
301 303
302 304 MarkdownCell.prototype = new TextCell();
303 305
304 306 /**
305 307 * @method render
306 308 */
307 309 MarkdownCell.prototype.render = function () {
308 310 if (this.rendered === false) {
309 311 var text = this.get_text();
310 312 if (text === "") { text = this.placeholder; }
311 313 text = IPython.mathjaxutils.remove_math(text)
312 314 var html = IPython.markdown_converter.makeHtml(text);
313 315 html = IPython.mathjaxutils.replace_math(html)
314 316 try {
315 317 this.set_rendered(html);
316 318 } catch (e) {
317 319 console.log("Error running Javascript in Markdown:");
318 320 console.log(e);
319 321 this.set_rendered($("<div/>").addClass("js-error").html(
320 322 "Error rendering Markdown!<br/>" + e.toString())
321 323 );
322 324 }
323 325 this.element.find('div.text_cell_input').hide();
324 326 this.element.find("div.text_cell_render").show();
325 327 var code_snippets = this.element.find("pre > code");
326 328 code_snippets.replaceWith(function () {
327 329 var code = $(this).html();
328 330 /* Substitute br for newlines and &nbsp; for spaces
329 331 before highlighting, since prettify doesn't
330 332 preserve those on all browsers */
331 333 code = code.replace(/(\r\n|\n|\r)/gm, "<br/>");
332 334 code = code.replace(/ /gm, '&nbsp;');
333 335 code = prettyPrintOne(code);
334 336
335 337 return '<code class="prettyprint">' + code + '</code>';
336 338 });
337 339 this.typeset()
338 340 this.rendered = true;
339 341 }
340 342 };
341 343
342 344
343 345 // RawCell
344 346
345 347 /**
346 348 * @class RawCell
347 349 * @constructor RawCell
348 350 * @extends Ipython.TextCell
349 351 */
350 352 var RawCell = function () {
351 353 this.placeholder = "Type plain text and LaTeX: $\\alpha^2$";
352 354 this.code_mirror_mode = 'rst';
353 355 IPython.TextCell.apply(this, arguments);
354 356 this.cell_type = 'raw';
355 357 var that = this
356 358
357 359 this.element.focusout(
358 360 function() { that.auto_highlight(); }
359 361 );
360 362 };
361 363
362 364
363 365 RawCell.prototype = new TextCell();
364 366
365 367 /**
366 368 * Trigger autodetection of highlight scheme for current cell
367 369 * @method auto_highlight
368 370 */
369 371 RawCell.prototype.auto_highlight = function () {
370 372 this._auto_highlight(IPython.config.raw_cell_highlight);
371 373 };
372 374
373 375 /** @method render **/
374 376 RawCell.prototype.render = function () {
375 377 this.rendered = true;
376 378 this.edit();
377 379 };
378 380
379 381
380 382 /** @method handle_codemirror_keyevent **/
381 383 RawCell.prototype.handle_codemirror_keyevent = function (editor, event) {
382 384
383 385 var that = this;
384 386 if (event.which === key.UPARROW && event.type === 'keydown') {
385 387 // If we are not at the top, let CM handle the up arrow and
386 388 // prevent the global keydown handler from handling it.
387 389 if (!that.at_top()) {
388 390 event.stop();
389 391 return false;
390 392 } else {
391 393 return true;
392 394 };
393 395 } else if (event.which === key.DOWNARROW && event.type === 'keydown') {
394 396 // If we are not at the bottom, let CM handle the down arrow and
395 397 // prevent the global keydown handler from handling it.
396 398 if (!that.at_bottom()) {
397 399 event.stop();
398 400 return false;
399 401 } else {
400 402 return true;
401 403 };
402 404 };
403 405 return false;
404 406 };
405 407
406 408 /** @method select **/
407 409 RawCell.prototype.select = function () {
408 410 IPython.Cell.prototype.select.apply(this);
409 411 this.code_mirror.refresh();
410 412 this.code_mirror.focus();
411 413 };
412 414
413 415 /** @method at_top **/
414 416 RawCell.prototype.at_top = function () {
415 417 var cursor = this.code_mirror.getCursor();
416 418 if (cursor.line === 0 && cursor.ch === 0) {
417 419 return true;
418 420 } else {
419 421 return false;
420 422 }
421 423 };
422 424
423 425
424 426 /** @method at_bottom **/
425 427 RawCell.prototype.at_bottom = function () {
426 428 var cursor = this.code_mirror.getCursor();
427 429 if (cursor.line === (this.code_mirror.lineCount()-1) && cursor.ch === this.code_mirror.getLine(cursor.line).length) {
428 430 return true;
429 431 } else {
430 432 return false;
431 433 }
432 434 };
433 435
434 436
435 437 /**
436 438 * @class HeadingCell
437 439 * @extends Ipython.TextCell
438 440 */
439 441
440 442 /**
441 443 * @constructor HeadingCell
442 444 * @extends Ipython.TextCell
443 445 */
444 446 var HeadingCell = function () {
445 447 this.placeholder = "Type Heading Here";
446 448 IPython.TextCell.apply(this, arguments);
447 449 /**
448 450 * heading level of the cell, use getter and setter to access
449 451 * @property level
450 452 */
451 453 this.level = 1;
452 454 this.cell_type = 'heading';
453 455 };
454 456
455 457
456 458 HeadingCell.prototype = new TextCell();
457 459
458 460 /** @method fromJSON */
459 461 HeadingCell.prototype.fromJSON = function (data) {
460 462 if (data.level != undefined){
461 463 this.level = data.level;
462 464 }
463 465 IPython.TextCell.prototype.fromJSON.apply(this, arguments);
464 466 };
465 467
466 468
467 469 /** @method toJSON */
468 470 HeadingCell.prototype.toJSON = function () {
469 471 var data = IPython.TextCell.prototype.toJSON.apply(this);
470 472 data.level = this.get_level();
471 473 return data;
472 474 };
473 475
474 476
475 477 /**
476 478 * Change heading level of cell, and re-render
477 479 * @method set_level
478 480 */
479 481 HeadingCell.prototype.set_level = function (level) {
480 482 this.level = level;
481 483 if (this.rendered) {
482 484 this.rendered = false;
483 485 this.render();
484 486 };
485 487 };
486 488
487 489 /** The depth of header cell, based on html (h1 to h6)
488 490 * @method get_level
489 491 * @return {integer} level - for 1 to 6
490 492 */
491 493 HeadingCell.prototype.get_level = function () {
492 494 return this.level;
493 495 };
494 496
495 497
496 498 HeadingCell.prototype.set_rendered = function (text) {
497 499 var r = this.element.find("div.text_cell_render");
498 500 r.empty();
499 501 r.append($('<h'+this.level+'/>').html(text));
500 502 };
501 503
502 504
503 505 HeadingCell.prototype.get_rendered = function () {
504 506 var r = this.element.find("div.text_cell_render");
505 507 return r.children().first().html();
506 508 };
507 509
508 510
509 511 HeadingCell.prototype.render = function () {
510 512 if (this.rendered === false) {
511 513 var text = this.get_text();
512 514 if (text === "") { text = this.placeholder; }
513 515 this.set_rendered(text);
514 516 this.typeset();
515 517 this.element.find('div.text_cell_input').hide();
516 518 this.element.find("div.text_cell_render").show();
517 519 this.rendered = true;
518 520 };
519 521 };
520 522
521 523 IPython.TextCell = TextCell;
522 524 IPython.HTMLCell = HTMLCell;
523 525 IPython.MarkdownCell = MarkdownCell;
524 526 IPython.RawCell = RawCell;
525 527 IPython.HeadingCell = HeadingCell;
526 528
527 529
528 530 return IPython;
529 531
530 532 }(IPython));
531 533
@@ -1,111 +1,111 b''
1 1 //----------------------------------------------------------------------------
2 2 // Copyright (C) 2008 The IPython Development Team
3 3 //
4 4 // Distributed under the terms of the BSD License. The full license is in
5 5 // the file COPYING, distributed as part of this software.
6 6 //----------------------------------------------------------------------------
7 7
8 8 //============================================================================
9 9 // ToolBar
10 10 //============================================================================
11 11 /**
12 12 * @module IPython
13 13 * @namespace IPython
14 14 * @submodule ToolBar
15 15 */
16 16
17 17 var IPython = (function (IPython) {
18 18
19 19 /**
20 20 * A generic toolbar on which one can add button
21 21 * @class ToolBar
22 22 * @constructor
23 23 * @param {Dom object} selector
24 24 */
25 25 var ToolBar = function (selector) {
26 26 this.selector = selector;
27 27 if (this.selector !== undefined) {
28 28 this.element = $(selector);
29 29 this.style();
30 30 }
31 31 };
32 32
33 33 /**
34 34 * add a group of button into the current toolbar.
35 35 *
36 36 *
37 37 * @example
38 38 *
39 * IPython.toolbar.add_button_group([
39 * IPython.toolbar.add_buttons_group([
40 40 * {
41 41 * label:'my button',
42 42 * icon:'ui-icon-disk',
43 43 * callback:function(){alert('hoho'),
44 44 * id : 'my_button_id', // this is optional
45 45 * },
46 46 * {
47 47 * label:'my second button',
48 48 * icon:'ui-icon-scissors',
49 49 * callback:function(){alert('be carefull I cut')}
50 50 * }
51 51 * ],
52 52 * "my_button_group_id"
53 53 * )
54 54 *
55 55 * @method add_buttons_group
56 56 * @param list {List}
57 57 * List of button of the group, with the following paramter for each :
58 58 * @param list.label {string} text to show on button hover
59 59 * @param list.icon {string} icon to choose from [jQuery ThemeRoller](http://jqueryui.com/themeroller/)
60 60 * @param list.callback {function} function to be called on button click
61 61 * @param [list.id] {String} id to give to the button
62 62 * @param [group_id] {String} optionnal id to give to the group
63 63 *
64 64 */
65 65 ToolBar.prototype.add_buttons_group = function (list, group_id) {
66 66 var span_group = $('<span/>');
67 67 if( group_id != undefined ) {
68 68 span_group.attr('id',group_id);
69 69 }
70 70 for(var el in list) {
71 71 var button = $('<button/>').button({
72 72 icons : {primary : list[el].icon},
73 73 text : false,
74 74 label : list[el].label
75 75 });
76 76 var id = list[el].id;
77 77 if( id != undefined )
78 78 button.attr('id',id);
79 79 var fun = list[el].callback;
80 80 button.click(fun);
81 81 span_group.append(button);
82 82 }
83 83 span_group.buttonset();
84 84 $(this.selector).append(span_group);
85 85 };
86 86
87 87 ToolBar.prototype.style = function () {
88 88 this.element.addClass('border-box-sizing').
89 89 addClass('ui-widget ui-widget-content toolbar').
90 90 css('border-top-style','none').
91 91 css('border-left-style','none').
92 92 css('border-right-style','none');
93 93 };
94 94
95 95 /**
96 96 * Show and hide toolbar
97 97 * @method toggle
98 98 */
99 99 ToolBar.prototype.toggle = function () {
100 100 this.element.toggle();
101 101 if (IPython.layout_manager != undefined) {
102 102 IPython.layout_manager.do_resize();
103 103 }
104 104 };
105 105
106 106
107 107 IPython.ToolBar = ToolBar;
108 108
109 109 return IPython;
110 110
111 111 }(IPython));
@@ -1,227 +1,229 b''
1 1 {% extends "page.html" %}
2 2
3 3 {% block stylesheet %}
4 4
5 5 {% if mathjax_url %}
6 6 <script type="text/javascript" src="{{mathjax_url}}?config=TeX-AMS_HTML-full&delayStartupUntil=configured" charset="utf-8"></script>
7 7 {% endif %}
8 8 <script type="text/javascript">
9 9 // MathJax disabled, set as null to distingish from *missing* MathJax,
10 10 // where it will be undefined, and should prompt a dialog later.
11 11 window.mathjax_url = "{{mathjax_url}}";
12 12 </script>
13 13
14 14 <link rel="stylesheet" href="{{ static_url("codemirror/lib/codemirror.css") }}">
15 15 <link rel="stylesheet" href="{{ static_url("codemirror/theme/ipython.css") }}">
16 16
17 17 <link rel="stylesheet" href="{{ static_url("prettify/prettify.css") }}"/>
18 18
19 19 <link rel="stylesheet" href="{{ static_url("css/notebook.css") }}" type="text/css" />
20 <link rel="stylesheet" href="{{ static_url("css/celltoolbar.css") }}" type="text/css" />
20 21 <link rel="stylesheet" href="{{ static_url("css/tooltip.css") }}" type="text/css" />
21 22 <link rel="stylesheet" href="{{ static_url("css/renderedhtml.css") }}" type="text/css" />
22 23
23 24 <link rel="stylesheet" href="{{ static_url("css/printnotebook.css") }}" type="text/css" media="print"/>
24 25 {% endblock %}
25 26
26 27 {% block params %}
27 28
28 29 data-project={{project}}
29 30 data-base-project-url={{base_project_url}}
30 31 data-base-kernel-url={{base_kernel_url}}
31 32 data-read-only={{read_only and not logged_in}}
32 33 data-notebook-id={{notebook_id}}
33 34
34 35 {% endblock %}
35 36
36 37
37 38 {% block header %}
38 39
39 40 <span id="save_widget">
40 41 <span id="notebook_name"></span>
41 42 <span id="save_status"></span>
42 43 </span>
43 44
44 45 {% endblock %}
45 46
46 47
47 48 {% block site %}
48 49
49 50 <div id="menubar_container">
50 51 <div id="menubar">
51 52 <ul id="menus">
52 53 <li><a href="#">File</a>
53 54 <ul>
54 55 <li id="new_notebook"><a href="#">New</a></li>
55 56 <li id="open_notebook"><a href="#">Open...</a></li>
56 57 <hr/>
57 58 <li id="copy_notebook"><a href="#">Make a Copy...</a></li>
58 59 <li id="rename_notebook"><a href="#">Rename...</a></li>
59 60 <li id="save_notebook"><a href="#">Save</a></li>
60 61 <hr/>
61 62 <li><a href="#">Download as</a>
62 63 <ul>
63 64 <li id="download_ipynb"><a href="#">IPython (.ipynb)</a></li>
64 65 <li id="download_py"><a href="#">Python (.py)</a></li>
65 66 </ul>
66 67 </li>
67 68 <hr/>
68 69 <li id="print_notebook"><a href="/{{notebook_id}}/print" target="_blank">Print View</a></li>
69 70 <hr/>
70 71 <li id="kill_and_exit"><a href="#" >Close and halt</a></li>
71 72 </ul>
72 73 </li>
73 74 <li><a href="#">Edit</a>
74 75 <ul>
75 76 <li id="cut_cell"><a href="#">Cut Cell</a></li>
76 77 <li id="copy_cell"><a href="#">Copy Cell</a></li>
77 78 <li id="paste_cell_above" class="ui-state-disabled"><a href="#">Paste Cell Above</a></li>
78 79 <li id="paste_cell_below" class="ui-state-disabled"><a href="#">Paste Cell Below</a></li>
79 80 <li id="paste_cell_replace" class="ui-state-disabled"><a href="#">Paste Cell &amp; Replace</a></li>
80 81 <li id="delete_cell"><a href="#">Delete</a></li>
81 82 <hr/>
82 83 <li id="split_cell"><a href="#">Split Cell</a></li>
83 84 <li id="merge_cell_above"><a href="#">Merge Cell Above</a></li>
84 85 <li id="merge_cell_below"><a href="#">Merge Cell Below</a></li>
85 86 <hr/>
86 87 <li id="move_cell_up"><a href="#">Move Cell Up</a></li>
87 88 <li id="move_cell_down"><a href="#">Move Cell Down</a></li>
88 89 <hr/>
89 90 <li id="select_previous"><a href="#">Select Previous Cell</a></li>
90 91 <li id="select_next"><a href="#">Select Next Cell</a></li>
91 92 </ul>
92 93 </li>
93 94 <li><a href="#">View</a>
94 95 <ul>
95 96 <li id="toggle_header"><a href="#">Toggle Header</a></li>
96 97 <li id="toggle_toolbar"><a href="#">Toggle Toolbar</a></li>
97 98 </ul>
98 99 </li>
99 100 <li><a href="#">Insert</a>
100 101 <ul>
101 102 <li id="insert_cell_above"><a href="#">Insert Cell Above</a></li>
102 103 <li id="insert_cell_below"><a href="#">Insert Cell Below</a></li>
103 104 </ul>
104 105 </li>
105 106 <li><a href="#">Cell</a>
106 107 <ul>
107 108 <li id="run_cell"><a href="#">Run</a></li>
108 109 <li id="run_cell_in_place"><a href="#">Run in Place</a></li>
109 110 <li id="run_all_cells"><a href="#">Run All</a></li>
110 111 <li id="run_all_cells_above"><a href="#">Run All Above</a></li>
111 112 <li id="run_all_cells_below"><a href="#">Run All Below</a></li>
112 113 <hr/>
113 114 <li id="to_code"><a href="#">Code</a></li>
114 115 <li id="to_markdown"><a href="#">Markdown </a></li>
115 116 <li id="to_raw"><a href="#">Raw Text</a></li>
116 117 <li id="to_heading1"><a href="#">Heading 1</a></li>
117 118 <li id="to_heading2"><a href="#">Heading 2</a></li>
118 119 <li id="to_heading3"><a href="#">Heading 3</a></li>
119 120 <li id="to_heading4"><a href="#">Heading 4</a></li>
120 121 <li id="to_heading5"><a href="#">Heading 5</a></li>
121 122 <li id="to_heading6"><a href="#">Heading 6</a></li>
122 123 <hr/>
123 124 <li id="toggle_output"><a href="#">Toggle Current Output</a></li>
124 125 <li id="all_outputs"><a href="#">All Output</a>
125 126 <ul>
126 127 <li id="expand_all_output"><a href="#">Expand</a></li>
127 128 <li id="scroll_all_output"><a href="#">Scroll Long</a></li>
128 129 <li id="collapse_all_output"><a href="#">Collapse</a></li>
129 130 <li id="clear_all_output"><a href="#">Clear</a></li>
130 131 </ul>
131 132 </li>
132 133 </ul>
133 134 </li>
134 135 <li><a href="#">Kernel</a>
135 136 <ul>
136 137 <li id="int_kernel"><a href="#">Interrupt</a></li>
137 138 <li id="restart_kernel"><a href="#">Restart</a></li>
138 139 </ul>
139 140 </li>
140 141 <li><a href="#">Help</a>
141 142 <ul>
142 143 <li><a href="http://ipython.org/documentation.html" target="_blank">IPython Help</a></li>
143 144 <li><a href="http://ipython.org/ipython-doc/stable/interactive/htmlnotebook.html" target="_blank">Notebook Help</a></li>
144 145 <li id="keyboard_shortcuts"><a href="#">Keyboard Shortcuts</a></li>
145 146 <hr/>
146 147 <li><a href="http://docs.python.org" target="_blank">Python</a></li>
147 148 <li><a href="http://docs.scipy.org/doc/numpy/reference/" target="_blank">NumPy</a></li>
148 149 <li><a href="http://docs.scipy.org/doc/scipy/reference/" target="_blank">SciPy</a></li>
149 150 <li><a href="http://docs.sympy.org/dev/index.html" target="_blank">SymPy</a></li>
150 151 <li><a href="http://matplotlib.sourceforge.net/" target="_blank">Matplotlib</a></li>
151 152 </ul>
152 153 </li>
153 154 </ul>
154 155
155 156 </div>
156 157 <div id="notification_area">
157 158 </div>
158 159 </div>
159 160
160 161
161 162 <div id="maintoolbar"></div>
162 163
163 164 <div id="main_app">
164 165
165 166 <div id="notebook_panel">
166 167 <div id="notebook"></div>
167 168 <div id="pager_splitter"></div>
168 169 <div id="pager_container">
169 170 <div id='pager_button_area'>
170 171 </div>
171 172 <div id="pager"></div>
172 173 </div>
173 174 </div>
174 175
175 176 </div>
176 177 <div id='tooltip' class='ipython_tooltip ui-corner-all' style='display:none'></div>
177 178
178 179
179 180 {% endblock %}
180 181
181 182
182 183 {% block script %}
183 184
184 185 <script src="{{ static_url("codemirror/lib/codemirror.js") }}" charset="utf-8"></script>
185 186 <script src="{{ static_url("codemirror/lib/util/loadmode.js") }}" charset="utf-8"></script>
186 187 <script src="{{ static_url("codemirror/lib/util/multiplex.js") }}" charset="utf-8"></script>
187 188 <script src="{{ static_url("codemirror/mode/python/python.js") }}" charset="utf-8"></script>
188 189 <script src="{{ static_url("codemirror/mode/htmlmixed/htmlmixed.js") }}" charset="utf-8"></script>
189 190 <script src="{{ static_url("codemirror/mode/xml/xml.js") }}" charset="utf-8"></script>
190 191 <script src="{{ static_url("codemirror/mode/javascript/javascript.js") }}" charset="utf-8"></script>
191 192 <script src="{{ static_url("codemirror/mode/css/css.js") }}" charset="utf-8"></script>
192 193 <script src="{{ static_url("codemirror/mode/rst/rst.js") }}" charset="utf-8"></script>
193 194 <script src="{{ static_url("codemirror/mode/markdown/markdown.js") }}" charset="utf-8"></script>
194 195
195 196 <script src="{{ static_url("pagedown/Markdown.Converter.js") }}" charset="utf-8"></script>
196 197
197 198 <script src="{{ static_url("prettify/prettify.js") }}" charset="utf-8"></script>
198 199 <script src="{{ static_url("dateformat/date.format.js") }}" charset="utf-8"></script>
199 200
200 201 <script src="{{ static_url("js/events.js") }}" type="text/javascript" charset="utf-8"></script>
201 202 <script src="{{ static_url("js/utils.js") }}" type="text/javascript" charset="utf-8"></script>
202 203 <script src="{{ static_url("js/layoutmanager.js") }}" type="text/javascript" charset="utf-8"></script>
203 204 <script src="{{ static_url("js/mathjaxutils.js") }}" type="text/javascript" charset="utf-8"></script>
204 205 <script src="{{ static_url("js/outputarea.js") }}" type="text/javascript" charset="utf-8"></script>
205 206 <script src="{{ static_url("js/cell.js") }}" type="text/javascript" charset="utf-8"></script>
207 <script src="{{ static_url("js/celltoolbar.js") }}" type="text/javascript" charset="utf-8"></script>
206 208 <script src="{{ static_url("js/codecell.js") }}" type="text/javascript" charset="utf-8"></script>
207 209 <script src="{{ static_url("js/completer.js") }}" type="text/javascript" charset="utf-8"></script>
208 210 <script src="{{ static_url("js/textcell.js") }}" type="text/javascript" charset="utf-8"></script>
209 211 <script src="{{ static_url("js/kernel.js") }}" type="text/javascript" charset="utf-8"></script>
210 212 <script src="{{ static_url("js/savewidget.js") }}" type="text/javascript" charset="utf-8"></script>
211 213 <script src="{{ static_url("js/quickhelp.js") }}" type="text/javascript" charset="utf-8"></script>
212 214 <script src="{{ static_url("js/pager.js") }}" type="text/javascript" charset="utf-8"></script>
213 215 <script src="{{ static_url("js/menubar.js") }}" type="text/javascript" charset="utf-8"></script>
214 216 <script src="{{ static_url("js/toolbar.js") }}" type="text/javascript" charset="utf-8"></script>
215 217 <script src="{{ static_url("js/maintoolbar.js") }}" type="text/javascript" charset="utf-8"></script>
216 218 <script src="{{ static_url("js/notebook.js") }}" type="text/javascript" charset="utf-8"></script>
217 219 <script src="{{ static_url("js/notificationwidget.js") }}" type="text/javascript" charset="utf-8"></script>
218 220 <script src="{{ static_url("js/notificationarea.js") }}" type="text/javascript" charset="utf-8"></script>
219 221 <script src="{{ static_url("js/tooltip.js") }}" type="text/javascript" charset="utf-8"></script>
220 222 <script src="{{ static_url("js/config.js") }}" type="text/javascript" charset="utf-8"></script>
221 223 <script src="{{ static_url("js/notebookmain.js") }}" type="text/javascript" charset="utf-8"></script>
222 224
223 225 <script src="{{ static_url("js/contexthint.js") }}" charset="utf-8"></script>
224 {% endblock %}
225
226 226
227 <script src="{{ static_url("js/celltoolbarpresets/default.js") }}" type="text/javascript" charset="utf-8"></script>
227 228
229 {% endblock %}
General Comments 0
You need to be logged in to leave comments. Login now