##// END OF EJS Templates
rename metaui -> celltoolbar
Matthias BUSSONNIER -
Show More
@@ -1,54 +1,54 b''
1 1 /*Css for the metadata edit area*/
2 2
3 .metaedit{
3 .celltoolbar{
4 4 border:thin solid #DDD;
5 5 margin-left:81px;
6 6 border-bottom:none;
7 7 background : #EEE;
8 8 border-top-right-radius: 3px;
9 9 border-top-left-radius: 3px;
10 10 display:none;
11 11 }
12 12
13 .code_cell .metaedit{
13 .code_cell .celltoolbar{
14 14 margin-left:81px;
15 15 }
16 16
17 .text_cell .metaedit{
17 .text_cell .celltoolbar{
18 18 margin-left:0px;
19 19 }
20 20
21 .editmetaon div.input_area , .editmetaon div.text_cell_input{
21 .celltoolbar-on div.input_area , .celltoolbar-on div.text_cell_input{
22 22 border-top-right-radius: 0px;
23 23 border-top-left-radius: 0px;
24 24 }
25 25
26 .editmetaon .metaedit {
26 .celltoolbar-on .celltoolbar {
27 27 display:block;
28 28 }
29 29
30 .metaedit ui-button {
30 .celltoolbar ui-button {
31 31 border :none;
32 32 }
33 33
34 34 .button_container {
35 35 float:right;
36 36 /*width:60px;*/
37 37 }
38 38
39 39 .button_container .ui-state-default, .button_container .ui-state-hover, .button_container .ui-state-hover span{
40 40 border-radius : 0 0 0 0;
41 41 border : none;
42 42 }
43 43
44 .metaedit select {
44 .celltoolbar select {
45 45 margin:10px;
46 46 margin-top:0px;
47 47 margin-bottom:0px;
48 48 }
49 49
50 .metaedit input[type=checkbox] {
50 .celltoolbar input[type=checkbox] {
51 51 margin-bottom:1px;
52 52
53 53 }
54 54
@@ -1,313 +1,313 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 53 Cell.prototype.create_element = function () {};
54 54
55 55
56 56 /**
57 57 * Subclasses can implement override bind_events.
58 58 * Be carefull to call the parent method when overwriting as it fires event.
59 59 * this will be triggerd after create_element in constructor.
60 60 * @method bind_events
61 61 */
62 62 Cell.prototype.bind_events = function () {
63 63 var that = this;
64 64 // We trigger events so that Cell doesn't have to depend on Notebook.
65 65 that.element.click(function (event) {
66 66 if (that.selected === false) {
67 67 $([IPython.events]).trigger('select.Cell', {'cell':that});
68 68 }
69 69 });
70 70 that.element.focusin(function (event) {
71 71 if (that.selected === false) {
72 72 $([IPython.events]).trigger('select.Cell', {'cell':that});
73 73 }
74 74 });
75 75 };
76 76
77 77 /**
78 78 * Triger typsetting of math by mathjax on current cell element
79 79 * @method typeset
80 80 */
81 81 Cell.prototype.typeset = function () {
82 82 if (window.MathJax){
83 83 var cell_math = this.element.get(0);
84 84 MathJax.Hub.Queue(["Typeset",MathJax.Hub,cell_math]);
85 85 }
86 86 };
87 87
88 88 /**
89 89 * should be triggerd when cell is selected
90 90 * @method select
91 91 */
92 92 Cell.prototype.select = function () {
93 93 this.element.addClass('ui-widget-content ui-corner-all');
94 94 this.selected = true;
95 95 };
96 96
97 97
98 98 /**
99 99 * should be triggerd when cell is unselected
100 100 * @method unselect
101 101 */
102 102 Cell.prototype.unselect = function () {
103 103 this.element.removeClass('ui-widget-content ui-corner-all');
104 104 this.selected = false;
105 105 };
106 106
107 107 /**
108 108 * should be overritten by subclass
109 109 * @method get_text
110 110 */
111 111 Cell.prototype.get_text = function () {
112 112 };
113 113
114 114 /**
115 115 * should be overritten by subclass
116 116 * @method set_text
117 117 * @param {string} text
118 118 */
119 119 Cell.prototype.set_text = function (text) {
120 120 };
121 121
122 122 /**
123 123 * Refresh codemirror instance
124 124 * @method refresh
125 125 */
126 126 Cell.prototype.refresh = function () {
127 127 this.code_mirror.refresh();
128 128 };
129 129
130 130
131 131 /**
132 132 * should be overritten by subclass
133 133 * @method edit
134 134 **/
135 135 Cell.prototype.edit = function () {
136 136 };
137 137
138 138
139 139 /**
140 140 * should be overritten by subclass
141 141 * @method render
142 142 **/
143 143 Cell.prototype.render = function () {
144 144 };
145 145
146 146 /**
147 147 * should be overritten by subclass
148 148 * serialise cell to json.
149 149 * @method toJSON
150 150 **/
151 151 Cell.prototype.toJSON = function () {
152 152 var data = {};
153 153 data.metadata = this.metadata;
154 154 return data;
155 155 };
156 156
157 157
158 158 /**
159 159 * should be overritten by subclass
160 160 * @method fromJSON
161 161 **/
162 162 Cell.prototype.fromJSON = function (data) {
163 163 if (data.metadata !== undefined) {
164 164 this.metadata = data.metadata;
165 165 }
166 this.metaui.rebuild();
166 this.celltoolbar.rebuild();
167 167 };
168 168
169 169
170 170 /**
171 171 * can the cell be splitted in 2 cells.
172 172 * @method is_splittable
173 173 **/
174 174 Cell.prototype.is_splittable = function () {
175 175 return true;
176 176 };
177 177
178 178
179 179 /**
180 180 * @return {String} - the text before the cursor
181 181 * @method get_pre_cursor
182 182 **/
183 183 Cell.prototype.get_pre_cursor = function () {
184 184 var cursor = this.code_mirror.getCursor();
185 185 var text = this.code_mirror.getRange({line:0,ch:0}, cursor);
186 186 text = text.replace(/^\n+/, '').replace(/\n+$/, '');
187 187 return text;
188 188 }
189 189
190 190
191 191 /**
192 192 * @return {String} - the text after the cursor
193 193 * @method get_post_cursor
194 194 **/
195 195 Cell.prototype.get_post_cursor = function () {
196 196 var cursor = this.code_mirror.getCursor();
197 197 var last_line_num = this.code_mirror.lineCount()-1;
198 198 var last_line_len = this.code_mirror.getLine(last_line_num).length;
199 199 var end = {line:last_line_num, ch:last_line_len}
200 200 var text = this.code_mirror.getRange(cursor, end);
201 201 text = text.replace(/^\n+/, '').replace(/\n+$/, '');
202 202 return text;
203 203 };
204 204
205 205
206 206 /** Grow the cell by hand. This is used upon reloading from JSON, when the
207 207 * autogrow handler is not called.
208 208 *
209 209 * could be made static
210 210 *
211 211 * @param {Dom element} - element
212 212 * @method grow
213 213 **/
214 214 Cell.prototype.grow = function(element) {
215 215 var dom = element.get(0);
216 216 var lines_count = 0;
217 217 // modified split rule from
218 218 // http://stackoverflow.com/questions/2035910/how-to-get-the-number-of-lines-in-a-textarea/2036424#2036424
219 219 var lines = dom.value.split(/\r|\r\n|\n/);
220 220 lines_count = lines.length;
221 221 if (lines_count >= 1) {
222 222 dom.rows = lines_count;
223 223 } else {
224 224 dom.rows = 1;
225 225 }
226 226 };
227 227
228 228 /**
229 229 * Toggle CodeMirror LineNumber
230 230 * @method toggle_line_numbers
231 231 **/
232 232 Cell.prototype.toggle_line_numbers = function () {
233 233 if (this.code_mirror.getOption('lineNumbers') == false) {
234 234 this.code_mirror.setOption('lineNumbers', true);
235 235 } else {
236 236 this.code_mirror.setOption('lineNumbers', false);
237 237 }
238 238 this.code_mirror.refresh();
239 239 };
240 240
241 241 /**
242 242 * force codemirror highlight mode
243 243 * @method force_highlight
244 244 * @param {object} - CodeMirror mode
245 245 **/
246 246 Cell.prototype.force_highlight = function(mode) {
247 247 this.user_highlight = mode;
248 248 this.auto_highlight();
249 249 };
250 250
251 251 /**
252 252 * Try to autodetect cell highlight mode, or use selected mode
253 253 * @methods _auto_highlight
254 254 * @private
255 255 * @param {String|object|undefined} - CodeMirror mode | 'auto'
256 256 **/
257 257 Cell.prototype._auto_highlight = function (modes) {
258 258 //Here we handle manually selected modes
259 259 if( this.user_highlight != undefined && this.user_highlight != 'auto' )
260 260 {
261 261 var mode = this.user_highlight;
262 262 CodeMirror.autoLoadMode(this.code_mirror, mode);
263 263 this.code_mirror.setOption('mode', mode);
264 264 return;
265 265 }
266 266 var first_line = this.code_mirror.getLine(0);
267 267 // loop on every pairs
268 268 for( var mode in modes) {
269 269 var regs = modes[mode]['reg'];
270 270 // only one key every time but regexp can't be keys...
271 271 for(var reg in regs ) {
272 272 // here we handle non magic_modes
273 273 if(first_line.match(regs[reg]) != null) {
274 274 if (mode.search('magic_') != 0) {
275 275 this.code_mirror.setOption('mode',mode);
276 276 CodeMirror.autoLoadMode(this.code_mirror, mode);
277 277 return;
278 278 }
279 279 var open = modes[mode]['open']|| "%%";
280 280 var close = modes[mode]['close']|| "%%end";
281 281 var mmode = mode;
282 282 mode = mmode.substr(6);
283 283 CodeMirror.autoLoadMode(this.code_mirror, mode);
284 284 // create on the fly a mode that swhitch between
285 285 // plain/text and smth else otherwise `%%` is
286 286 // source of some highlight issues.
287 287 // we use patchedGetMode to circumvent a bug in CM
288 288 CodeMirror.defineMode(mmode , function(config) {
289 289 return CodeMirror.multiplexingMode(
290 290 CodeMirror.patchedGetMode(config, 'text/plain'),
291 291 // always set someting on close
292 292 {open: open, close: close,
293 293 mode: CodeMirror.patchedGetMode(config, mode),
294 294 delimStyle: "delimit"
295 295 }
296 296 );
297 297 });
298 298 this.code_mirror.setOption('mode', mmode);
299 299 return;
300 300 }
301 301 }
302 302 }
303 303 // fallback on default (python)
304 304 var default_mode = this.default_mode || 'text/plain';
305 305 this.code_mirror.setOption('mode', default_mode);
306 306 };
307 307
308 308 IPython.Cell = Cell;
309 309
310 310 return IPython;
311 311
312 312 }(IPython));
313 313
@@ -1,381 +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 this.metaui = new IPython.MetaUI(this);
61 this.celltoolbar = new IPython.CellToolbar(this);
62 62
63 63 var cell = $('<div></div>').addClass('cell border-box-sizing code_cell vbox');
64 cell.append(this.metaui.$element);
64 cell.append(this.celltoolbar.element);
65 65 cell.attr('tabindex','2');
66 66 var input = $('<div></div>').addClass('input hbox');
67 67 input.append($('<div/>').addClass('prompt input_prompt'));
68 68 var input_area = $('<div/>').addClass('input_area box-flex1');
69 69 this.code_mirror = CodeMirror(input_area.get(0), {
70 70 indentUnit : 4,
71 71 mode: 'python',
72 72 theme: 'ipython',
73 73 readOnly: this.read_only,
74 74 extraKeys: {"Tab": "indentMore","Shift-Tab" : "indentLess",'Backspace':"delSpaceToPrevTabStop"},
75 75 onKeyEvent: $.proxy(this.handle_codemirror_keyevent,this),
76 76 matchBrackets: true
77 77 });
78 78 input.append(input_area);
79 79 var output = $('<div></div>');
80 80 cell.append(input).append(output);
81 81 this.element = cell;
82 82 this.output_area = new IPython.OutputArea(output, true);
83 83
84 84 // construct a completer only if class exist
85 85 // otherwise no print view
86 86 if (IPython.Completer !== undefined)
87 87 {
88 88 this.completer = new IPython.Completer(this);
89 89 }
90 90 };
91 91
92 92 /**
93 93 * This method gets called in CodeMirror's onKeyDown/onKeyPress
94 94 * handlers and is used to provide custom key handling. Its return
95 95 * value is used to determine if CodeMirror should ignore the event:
96 96 * true = ignore, false = don't ignore.
97 97 * @method handle_codemirror_keyevent
98 98 */
99 99 CodeCell.prototype.handle_codemirror_keyevent = function (editor, event) {
100 100
101 101 if (this.read_only){
102 102 return false;
103 103 }
104 104
105 105 var that = this;
106 106 // whatever key is pressed, first, cancel the tooltip request before
107 107 // they are sent, and remove tooltip if any, except for tab again
108 108 if (event.type === 'keydown' && event.which != key.TAB ) {
109 109 IPython.tooltip.remove_and_cancel_tooltip();
110 110 };
111 111
112 112 var cur = editor.getCursor();
113 113 if (event.keyCode === key.ENTER){
114 114 this.auto_highlight();
115 115 }
116 116
117 117 if (event.keyCode === key.ENTER && (event.shiftKey || event.ctrlKey)) {
118 118 // Always ignore shift-enter in CodeMirror as we handle it.
119 119 return true;
120 120 } else if (event.which === 40 && event.type === 'keypress' && IPython.tooltip.time_before_tooltip >= 0) {
121 121 // triger on keypress (!) otherwise inconsistent event.which depending on plateform
122 122 // browser and keyboard layout !
123 123 // Pressing '(' , request tooltip, don't forget to reappend it
124 124 IPython.tooltip.pending(that);
125 125 } else if (event.which === key.UPARROW && event.type === 'keydown') {
126 126 // If we are not at the top, let CM handle the up arrow and
127 127 // prevent the global keydown handler from handling it.
128 128 if (!that.at_top()) {
129 129 event.stop();
130 130 return false;
131 131 } else {
132 132 return true;
133 133 };
134 134 } else if (event.which === key.ESC) {
135 135 IPython.tooltip.remove_and_cancel_tooltip(true);
136 136 return true;
137 137 } else if (event.which === key.DOWNARROW && event.type === 'keydown') {
138 138 // If we are not at the bottom, let CM handle the down arrow and
139 139 // prevent the global keydown handler from handling it.
140 140 if (!that.at_bottom()) {
141 141 event.stop();
142 142 return false;
143 143 } else {
144 144 return true;
145 145 };
146 146 } else if (event.keyCode === key.TAB && event.type == 'keydown' && event.shiftKey) {
147 147 if (editor.somethingSelected()){
148 148 var anchor = editor.getCursor("anchor");
149 149 var head = editor.getCursor("head");
150 150 if( anchor.line != head.line){
151 151 return false;
152 152 }
153 153 }
154 154 IPython.tooltip.request(that);
155 155 event.stop();
156 156 return true;
157 157 } else if (event.keyCode === key.TAB && event.type == 'keydown') {
158 158 // Tab completion.
159 159 //Do not trim here because of tooltip
160 160 if (editor.somethingSelected()){return false}
161 161 var pre_cursor = editor.getRange({line:cur.line,ch:0},cur);
162 162 if (pre_cursor.trim() === "") {
163 163 // Don't autocomplete if the part of the line before the cursor
164 164 // is empty. In this case, let CodeMirror handle indentation.
165 165 return false;
166 166 } else if ((pre_cursor.substr(-1) === "("|| pre_cursor.substr(-1) === " ") && IPython.config.tooltip_on_tab ) {
167 167 IPython.tooltip.request(that);
168 168 // Prevent the event from bubbling up.
169 169 event.stop();
170 170 // Prevent CodeMirror from handling the tab.
171 171 return true;
172 172 } else {
173 173 event.stop();
174 174 this.completer.startCompletion();
175 175 return true;
176 176 };
177 177 } else {
178 178 // keypress/keyup also trigger on TAB press, and we don't want to
179 179 // use those to disable tab completion.
180 180 return false;
181 181 };
182 182 return false;
183 183 };
184 184
185 185
186 186 // Kernel related calls.
187 187
188 188 CodeCell.prototype.set_kernel = function (kernel) {
189 189 this.kernel = kernel;
190 190 }
191 191
192 192 /**
193 193 * Execute current code cell to the kernel
194 194 * @method execute
195 195 */
196 196 CodeCell.prototype.execute = function () {
197 197 this.output_area.clear_output(true, true, true);
198 198 this.set_input_prompt('*');
199 199 this.element.addClass("running");
200 200 var callbacks = {
201 201 'execute_reply': $.proxy(this._handle_execute_reply, this),
202 202 'output': $.proxy(this.output_area.handle_output, this.output_area),
203 203 'clear_output': $.proxy(this.output_area.handle_clear_output, this.output_area),
204 204 'set_next_input': $.proxy(this._handle_set_next_input, this)
205 205 };
206 206 var msg_id = this.kernel.execute(this.get_text(), callbacks, {silent: false});
207 207 };
208 208
209 209 /**
210 210 * @method _handle_execute_reply
211 211 * @private
212 212 */
213 213 CodeCell.prototype._handle_execute_reply = function (content) {
214 214 this.set_input_prompt(content.execution_count);
215 215 this.element.removeClass("running");
216 216 $([IPython.events]).trigger('set_dirty.Notebook', {'value': true});
217 217 }
218 218
219 219 CodeCell.prototype._handle_set_next_input = function (text) {
220 220 var data = {'cell': this, 'text': text}
221 221 $([IPython.events]).trigger('set_next_input.Notebook', data);
222 222 }
223 223
224 224 // Basic cell manipulation.
225 225
226 226 CodeCell.prototype.select = function () {
227 227 IPython.Cell.prototype.select.apply(this);
228 228 this.code_mirror.refresh();
229 229 this.code_mirror.focus();
230 230 this.auto_highlight();
231 231 // We used to need an additional refresh() after the focus, but
232 232 // it appears that this has been fixed in CM. This bug would show
233 233 // up on FF when a newly loaded markdown cell was edited.
234 234 };
235 235
236 236
237 237 CodeCell.prototype.select_all = function () {
238 238 var start = {line: 0, ch: 0};
239 239 var nlines = this.code_mirror.lineCount();
240 240 var last_line = this.code_mirror.getLine(nlines-1);
241 241 var end = {line: nlines-1, ch: last_line.length};
242 242 this.code_mirror.setSelection(start, end);
243 243 };
244 244
245 245
246 246 CodeCell.prototype.collapse = function () {
247 247 this.collapsed = true;
248 248 this.output_area.collapse();
249 249 };
250 250
251 251
252 252 CodeCell.prototype.expand = function () {
253 253 this.collapsed = false;
254 254 this.output_area.expand();
255 255 };
256 256
257 257
258 258 CodeCell.prototype.toggle_output = function () {
259 259 this.collapsed = Boolean(1 - this.collapsed);
260 260 this.output_area.toggle_output();
261 261 };
262 262
263 263
264 264 CodeCell.prototype.toggle_output_scroll = function () {
265 265 this.output_area.toggle_scroll();
266 266 };
267 267
268 268
269 269 CodeCell.input_prompt_classical = function (prompt_value, lines_number) {
270 270 var ns = prompt_value || "&nbsp;";
271 271 return 'In&nbsp;[' + ns + ']:'
272 272 };
273 273
274 274 CodeCell.input_prompt_continuation = function (prompt_value, lines_number) {
275 275 var html = [CodeCell.input_prompt_classical(prompt_value, lines_number)];
276 276 for(var i=1; i < lines_number; i++){html.push(['...:'])};
277 277 return html.join('</br>')
278 278 };
279 279
280 280 CodeCell.input_prompt_function = CodeCell.input_prompt_classical;
281 281
282 282
283 283 CodeCell.prototype.set_input_prompt = function (number) {
284 284 var nline = 1
285 285 if( this.code_mirror != undefined) {
286 286 nline = this.code_mirror.lineCount();
287 287 }
288 288 this.input_prompt_number = number;
289 289 var prompt_html = CodeCell.input_prompt_function(this.input_prompt_number, nline);
290 290 this.element.find('div.input_prompt').html(prompt_html);
291 291 };
292 292
293 293
294 294 CodeCell.prototype.clear_input = function () {
295 295 this.code_mirror.setValue('');
296 296 };
297 297
298 298
299 299 CodeCell.prototype.get_text = function () {
300 300 return this.code_mirror.getValue();
301 301 };
302 302
303 303
304 304 CodeCell.prototype.set_text = function (code) {
305 305 return this.code_mirror.setValue(code);
306 306 };
307 307
308 308
309 309 CodeCell.prototype.at_top = function () {
310 310 var cursor = this.code_mirror.getCursor();
311 311 if (cursor.line === 0 && cursor.ch === 0) {
312 312 return true;
313 313 } else {
314 314 return false;
315 315 }
316 316 };
317 317
318 318
319 319 CodeCell.prototype.at_bottom = function () {
320 320 var cursor = this.code_mirror.getCursor();
321 321 if (cursor.line === (this.code_mirror.lineCount()-1) && cursor.ch === this.code_mirror.getLine(cursor.line).length) {
322 322 return true;
323 323 } else {
324 324 return false;
325 325 }
326 326 };
327 327
328 328
329 329 CodeCell.prototype.clear_output = function (stdout, stderr, other) {
330 330 this.output_area.clear_output(stdout, stderr, other);
331 331 };
332 332
333 333
334 334 // JSON serialization
335 335
336 336 CodeCell.prototype.fromJSON = function (data) {
337 337 IPython.Cell.prototype.fromJSON.apply(this, arguments);
338 338 if (data.cell_type === 'code') {
339 339 if (data.input !== undefined) {
340 340 this.set_text(data.input);
341 341 // make this value the starting point, so that we can only undo
342 342 // to this state, instead of a blank cell
343 343 this.code_mirror.clearHistory();
344 344 this.auto_highlight();
345 345 }
346 346 if (data.prompt_number !== undefined) {
347 347 this.set_input_prompt(data.prompt_number);
348 348 } else {
349 349 this.set_input_prompt();
350 350 };
351 351 this.output_area.fromJSON(data.outputs);
352 352 if (data.collapsed !== undefined) {
353 353 if (data.collapsed) {
354 354 this.collapse();
355 355 } else {
356 356 this.expand();
357 357 };
358 358 };
359 359 };
360 360 };
361 361
362 362
363 363 CodeCell.prototype.toJSON = function () {
364 364 var data = IPython.Cell.prototype.toJSON.apply(this);
365 365 data.input = this.get_text();
366 366 data.cell_type = 'code';
367 367 if (this.input_prompt_number) {
368 368 data.prompt_number = this.input_prompt_number;
369 369 };
370 370 var outputs = this.output_area.toJSON();
371 371 data.outputs = outputs;
372 372 data.language = 'python';
373 373 data.collapsed = this.collapsed;
374 374 return data;
375 375 };
376 376
377 377
378 378 IPython.CodeCell = CodeCell;
379 379
380 380 return IPython;
381 381 }(IPython));
@@ -1,47 +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 31 * Example :
32 32 *
33 33 * Use `jQuery.getScript(url [, success(script, textStatus, jqXHR)] );`
34 34 * to load custom script into the notebook.
35 35 *
36 36 * // to load the metadata ui extension example.
37 * $.getScript('/static/js/examples/metaui.example.js');
37 * $.getScript('/static/js/examples/celltoolbar.example.js');
38 38 * // or
39 39 * // to load the metadata ui extension to control slideshow mode / reveal js for nbconvert
40 * $.getScript('/static/js/examples/metaui.slideshow.js');
40 * $.getScript('/static/js/examples/celltoolbar.slideshow.js');
41 41 *
42 42 *
43 43 * @module IPython
44 44 * @namespace IPython
45 45 * @class customjs
46 46 * @static
47 47 */
@@ -1,184 +1,184 b''
1 1 //----------------------------------------------------------------------------
2 2 // Copyright (C) 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 // MetaUI Example
9 // CellToolbar Example
10 10 //============================================================================
11 11
12 12 /**
13 * Example Use for the MetaUI library
13 * Example Use for the CellToolbar library
14 14 * add the following to your custom.js to load
15 * metadata UI for slideshow
15 * Celltoolbar UI for slideshow
16 16 *
17 17 * ```
18 * $.getScript('/static/js/examples/metaui.example.js');
18 * $.getScript('/static/js/examples/celltoolbar.example.js');
19 19 * ```
20 20 */
21 21 // IIFE without asignement, we don't modifiy the IPython namespace
22 22 (function (IPython) {
23 23 "use strict";
24 24
25 var MetaUI = IPython.MetaUI;
25 var CellToolbar = IPython.CellToolbar;
26 26
27 27
28 28 var raw_edit = function(cell){
29 29
30 30 var md = cell.metadata
31 31
32 32 var textarea = $('<textarea/>')
33 33 .attr('rows','13')
34 34 .attr('cols','75')
35 35 .attr('name','metadata')
36 36 .text(JSON.stringify(md, null,4)||'');
37 37 var dialogform = $('<div/>').attr('title','Edit the metadata')
38 38 .append(
39 39 $('<form/>').append(
40 40 $('<fieldset/>').append(
41 41 $('<label/>')
42 42 .attr('for','metadata')
43 43 .text("Metadata (I know what I'm dooing and I won't complain if it breaks my notebook)")
44 44 )
45 45 .append($('<br/>'))
46 46 .append(
47 47 textarea
48 48 )
49 49 )
50 50 );
51 51 var editor = CodeMirror.fromTextArea(textarea[0], {
52 52 lineNumbers: true,
53 53 matchBrackets: true,
54 54 });
55 55 $(dialogform).dialog({
56 56 autoOpen: true,
57 57 height: 300,
58 58 width: 650,
59 59 modal: true,
60 60 buttons: {
61 61 "Ok": function() {
62 62 //validate json and set it
63 63 try {
64 64 var json = JSON.parse(editor.getValue());
65 65 cell.metadata = json;
66 66 $( this ).dialog( "close" );
67 67 }
68 68 catch(e)
69 69 {
70 70 alert('invalid json');
71 71 }
72 72 },
73 73 Cancel: function() {
74 74 $( this ).dialog( "close" );
75 75 }
76 76 },
77 77 close: function() {
78 78 //cleanup on close
79 79 $(this).remove();
80 80 }
81 81 });
82 82 editor.refresh();
83 83 }
84 84
85 85 var add_raw_edit_button = function(div, cell) {
86 86 var button_container = $(div)
87 87 var button = $('<div/>').button({label:'Raw Edit'})
88 88 .click(function(){raw_edit(cell); return false;})
89 89 button_container.append(button);
90 90 }
91 91
92 MetaUI.register_callback('example.rawedit',add_raw_edit_button);
92 CellToolbar.register_callback('example.rawedit',add_raw_edit_button);
93 93 var example_preset = []
94 94 example_preset.push('example.rawedit');
95 95
96 96
97 97 var simple_button = function(div, cell) {
98 98 var button_container = $(div);
99 99 var button = $('<div/>').button({icons:{primary:'ui-icon-locked'}});
100 100 var fun = function(value){
101 101 try{
102 102 if(value){
103 103 cell.code_mirror.setOption('readOnly','nocursor')
104 104 button.button('option','icons',{primary:'ui-icon-locked'})
105 105 } else {
106 106 cell.code_mirror.setOption('readOnly','false')
107 107 button.button('option','icons',{primary:'ui-icon-unlocked'})
108 108 }
109 109 } catch(e){}
110 110
111 111 }
112 112 fun(cell.metadata.ro)
113 113 button.click(function(){
114 114 var v = cell.metadata.ro;
115 115 var locked = !v;
116 116 cell.metadata.ro = locked;
117 117 fun(locked)
118 118 })
119 119 .css('height','16px')
120 120 .css('width','35px');
121 121 button_container.append(button);
122 122 }
123 123
124 MetaUI.register_callback('example.lock',simple_button);
124 CellToolbar.register_callback('example.lock',simple_button);
125 125 example_preset.push('example.lock');
126 126
127 127 var toggle_test = function(div, cell) {
128 128 var button_container = $(div)
129 129 var button = $('<div/>').button({label:String(cell.metadata.foo)});
130 130 button.click(function(){
131 131 var v = cell.metadata.foo;
132 132 cell.metadata.foo = !v;
133 133 button.button("option","label",String(!v));
134 134 })
135 135 button_container.append(button);
136 136 }
137 137
138 MetaUI.register_callback('example.toggle',toggle_test);
138 CellToolbar.register_callback('example.toggle',toggle_test);
139 139 example_preset.push('example.toggle');
140 140
141 141 var checkbox_test = function(div, cell) {
142 142 var button_container = $(div)
143 143
144 144 var chkb = $('<input/>').attr('type','checkbox');
145 145 var lbl = $('<label/>').append($('<span/>').text('bar :').css('font-size','77%'));
146 146 lbl.append(chkb);
147 147 chkb.attr("checked",cell.metadata.bar);
148 148 chkb.click(function(){
149 149 var v = cell.metadata.bar;
150 150 cell.metadata.bar = !v;
151 151 chkb.attr("checked",!v);
152 152 })
153 153 button_container.append($('<div/>').append(lbl));
154 154
155 155 }
156 156
157 MetaUI.register_callback('example.checkbox',checkbox_test);
157 CellToolbar.register_callback('example.checkbox',checkbox_test);
158 158 example_preset.push('example.checkbox');
159 159
160 160 var select_test = function(div, cell) {
161 161 var button_container = $(div)
162 162
163 163 var select = $('<select/>');
164 164
165 165 select.append($('<option/>').attr('value','foo').text('foo'));
166 166 select.append($('<option/>').attr('value','bar').text('bar'));
167 167 select.append($('<option/>').attr('value','qux').text('qux'));
168 168 select.append($('<option/>').attr('value','zip').text('zip'));
169 169 select.val(cell.metadata.option);
170 170 select.change(function(){
171 171 cell.metadata.option = select.val();
172 172 });
173 173 button_container.append($('<div/>').append(select));
174 174
175 175 }
176 176
177 MetaUI.register_callback('example.select',select_test);
177 CellToolbar.register_callback('example.select',select_test);
178 178 example_preset.push('example.select');
179 179
180 MetaUI.register_preset('example',example_preset);
181 MetaUI.set_preset('example');
180 CellToolbar.register_preset('example',example_preset);
181 CellToolbar.set_preset('example');
182 182 console.log('Example extension for metadata editting loaded.');
183 183
184 184 }(IPython));
@@ -1,178 +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 20 $(this.selector)
21 .append($('<label/>').text('MetaUI'))
22 .append(IPython.MetaUI.$dropdown_preset_selector)
21 .append($('<label/>').text('CellToolbar'))
22 .append(IPython.CellToolbar.dropdown_preset_element)
23 23 };
24 24
25 25 MainToolBar.prototype = new IPython.ToolBar();
26 26
27 27 MainToolBar.prototype.construct = function () {
28 28 this.add_buttons_group([
29 29 {
30 30 id : 'save_b',
31 31 label : 'Save',
32 32 icon : 'ui-icon-disk',
33 33 callback : function () {
34 34 IPython.notebook.save_notebook();
35 35 }
36 36 }
37 37 ]);
38 38 this.add_buttons_group([
39 39 {
40 40 id : 'cut_b',
41 41 label : 'Cut Cell',
42 42 icon : 'ui-icon-scissors',
43 43 callback : function () {
44 44 IPython.notebook.cut_cell();
45 45 }
46 46 },
47 47 {
48 48 id : 'copy_b',
49 49 label : 'Copy Cell',
50 50 icon : 'ui-icon-copy',
51 51 callback : function () {
52 52 IPython.notebook.copy_cell();
53 53 }
54 54 },
55 55 {
56 56 id : 'paste_b',
57 57 label : 'Paste Cell Below',
58 58 icon : 'ui-icon-clipboard',
59 59 callback : function () {
60 60 IPython.notebook.paste_cell_below();
61 61 }
62 62 }
63 63 ],'cut_copy_paste');
64 64
65 65 this.add_buttons_group([
66 66 {
67 67 id : 'move_up_b',
68 68 label : 'Move Cell Up',
69 69 icon : 'ui-icon-arrowthick-1-n',
70 70 callback : function () {
71 71 IPython.notebook.move_cell_up();
72 72 }
73 73 },
74 74 {
75 75 id : 'move_down_b',
76 76 label : 'Move Cell Down',
77 77 icon : 'ui-icon-arrowthick-1-s',
78 78 callback : function () {
79 79 IPython.notebook.move_cell_down();
80 80 }
81 81 }
82 82 ],'move_up_down');
83 83
84 84 this.add_buttons_group([
85 85 {
86 86 id : 'insert_above_b',
87 87 label : 'Insert Cell Above',
88 88 icon : 'ui-icon-arrowthickstop-1-n',
89 89 callback : function () {
90 90 IPython.notebook.insert_cell_above('code');
91 91 }
92 92 },
93 93 {
94 94 id : 'insert_below_b',
95 95 label : 'Insert Cell Below',
96 96 icon : 'ui-icon-arrowthickstop-1-s',
97 97 callback : function () {
98 98 IPython.notebook.insert_cell_below('code');
99 99 }
100 100 }
101 101 ],'insert_above_below');
102 102
103 103 this.add_buttons_group([
104 104 {
105 105 id : 'run_b',
106 106 label : 'Run Cell',
107 107 icon : 'ui-icon-play',
108 108 callback : function () {
109 109 IPython.notebook.execute_selected_cell();
110 110 }
111 111 },
112 112 {
113 113 id : 'interrupt_b',
114 114 label : 'Interrupt',
115 115 icon : 'ui-icon-stop',
116 116 callback : function () {
117 117 IPython.notebook.kernel.interrupt();
118 118 }
119 119 }
120 120 ],'run_int');
121 121 };
122 122
123 123 MainToolBar.prototype.add_drop_down_list = function () {
124 124 var select = $(this.selector)
125 125 .append($('<select/>')
126 126 .attr('id','cell_type')
127 127 .addClass('ui-widget ui-widget-content')
128 128 .append($('<option/>').attr('value','code').text('Code'))
129 129 .append($('<option/>').attr('value','markdown').text('Markdown'))
130 130 .append($('<option/>').attr('value','raw').text('Raw Text'))
131 131 .append($('<option/>').attr('value','heading1').text('Heading 1'))
132 132 .append($('<option/>').attr('value','heading2').text('Heading 2'))
133 133 .append($('<option/>').attr('value','heading3').text('Heading 3'))
134 134 .append($('<option/>').attr('value','heading4').text('Heading 4'))
135 135 .append($('<option/>').attr('value','heading5').text('Heading 5'))
136 136 .append($('<option/>').attr('value','heading6').text('Heading 6'))
137 137 );
138 138 };
139 139
140 140 MainToolBar.prototype.bind_events = function () {
141 141 var that = this;
142 142
143 143 this.element.find('#cell_type').change(function () {
144 144 var cell_type = $(this).val();
145 145 if (cell_type === 'code') {
146 146 IPython.notebook.to_code();
147 147 } else if (cell_type === 'markdown') {
148 148 IPython.notebook.to_markdown();
149 149 } else if (cell_type === 'raw') {
150 150 IPython.notebook.to_raw();
151 151 } else if (cell_type === 'heading1') {
152 152 IPython.notebook.to_heading(undefined, 1);
153 153 } else if (cell_type === 'heading2') {
154 154 IPython.notebook.to_heading(undefined, 2);
155 155 } else if (cell_type === 'heading3') {
156 156 IPython.notebook.to_heading(undefined, 3);
157 157 } else if (cell_type === 'heading4') {
158 158 IPython.notebook.to_heading(undefined, 4);
159 159 } else if (cell_type === 'heading5') {
160 160 IPython.notebook.to_heading(undefined, 5);
161 161 } else if (cell_type === 'heading6') {
162 162 IPython.notebook.to_heading(undefined, 6);
163 163 }
164 164 });
165 165 $([IPython.events]).on('selected_cell_type_changed.Notebook', function (event, data) {
166 166 if (data.cell_type === 'heading') {
167 167 that.element.find('#cell_type').val(data.cell_type+data.level);
168 168 } else {
169 169 that.element.find('#cell_type').val(data.cell_type);
170 170 }
171 171 });
172 172 };
173 173
174 174 IPython.MainToolBar = MainToolBar;
175 175
176 176 return IPython;
177 177
178 178 }(IPython));
@@ -1,496 +1,496 b''
1 1 //----------------------------------------------------------------------------
2 2 // Copyright (C) 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 // MetaUI
9 // CellToolbar
10 10 //============================================================================
11 11
12 12
13 13 /**
14 14 * A Module to control the per-cell toolbar.
15 15 * @module IPython
16 16 * @namespace IPython
17 * @submodule MetaUI
17 * @submodule CellToolbar
18 18 */
19 19 var IPython = (function (IPython) {
20 20 "use strict";
21 21
22 22
23 23 /**
24 24 * @constructor
25 * @class MetaUI
25 * @class CellToolbar
26 26 * @param {The cell to attach the metadata UI to} cell
27 27 */
28 var MetaUI = function (cell) {
29 MetaUI._instances.push(this);
30 this.$metainner = $('<div/>');
28 var CellToolbar = function (cell) {
29 CellToolbar._instances.push(this);
30 this.inner_element = $('<div/>');
31 31 this.cell = cell;
32 this.$element = $('<div/>').addClass('metaedit')
33 .append(this.$metainner)
32 this.element = $('<div/>').addClass('celltoolbar')
33 .append(this.inner_element)
34 34 this.rebuild();
35 35 return this;
36 36 };
37 37
38 MetaUI.$dropdown_preset_selector = $('<select/>')
39 .attr('id','metaui_selector')
38 CellToolbar.dropdown_preset_element = $('<select/>')
39 .attr('id','celltoolbar_selector')
40 40 .append($('<option/>').attr('value','').text('-'))
41 41
42 MetaUI.$dropdown_preset_selector.change(function(){
43 var val = MetaUI.$dropdown_preset_selector.val()
42 CellToolbar.dropdown_preset_element.change(function(){
43 var val = CellToolbar.dropdown_preset_element.val()
44 44 if(val ==''){
45 $('body').removeClass('editmetaon')
45 $('body').removeClass('celltoolbar-on')
46 46 } else {
47 $('body').addClass('editmetaon')
48 MetaUI.set_preset(val)
47 $('body').addClass('celltoolbar-on')
48 CellToolbar.set_preset(val)
49 49 }
50 50 })
51 51
52 52
53 53
54 54 /**
55 55 * Class variable that should contain a dict of all availlable callback
56 56 * we need to think of wether or not we allow nested namespace
57 57 * @property _callback_dict
58 58 * @private
59 59 */
60 MetaUI._callback_dict = {};
60 CellToolbar._callback_dict = {};
61 61
62 62 /**
63 63 * Class variable that should contain the reverse order list of the button
64 64 * to add to the toolbar of each cell
65 65 * @property _button_list
66 66 * @private
67 67 */
68 MetaUI._button_list = [];
68 CellToolbar._button_list = [];
69 69
70 70 /**
71 71 * keep a list of all instances to
72 72 * be able to llop over them...
73 73 * but how to 'destroy' them ?
74 74 * have to think about it...
75 * or loop over the cells, and find their MetaUI instances.
75 * or loop over the cells, and find their CellToolbar instances.
76 76 * @private
77 77 * @property _instances
78 78 */
79 MetaUI._instances =[]
79 CellToolbar._instances =[]
80 80
81 81 /**
82 82 * keep a list of all the availlabel presets for the toolbar
83 83 * @private
84 84 * @property _presets
85 85 */
86 MetaUI._presets ={}
86 CellToolbar._presets ={}
87 87
88 88 // this is by design not a prototype.
89 89 /**
90 90 * Register a callback to create an UI element in a cell toolbar.
91 91 * @method register_callback
92 92 * @param name {String} name to use to refer to the callback. It is advised to use a prefix with the name
93 93 * for easier sorting and avoid collision
94 94 * @param callback {function(div, cell)} callback that will be called to generate the ui element
95 95 *
96 96 *
97 97 * The callback will receive the following element :
98 98 *
99 99 * * a div in which to add element.
100 100 * * the cell it is responsable from
101 101 *
102 102 * @example
103 103 *
104 104 * Example that create callback for a button that toggle between `true` and `false` label,
105 105 * with the metadata under the key 'foo' to reflect the status of the button.
106 106 *
107 107 * // first param reference to a DOM div
108 108 * // second param reference to the cell.
109 109 * var toggle = function(div, cell) {
110 110 * var button_container = $(div)
111 111 *
112 112 * // let's create a button that show the current value of the metadata
113 113 * var button = $('<div/>').button({label:String(cell.metadata.foo)});
114 114 *
115 115 * // On click, change the metadata value and update the button label
116 116 * button.click(function(){
117 117 * var v = cell.metadata.foo;
118 118 * cell.metadata.foo = !v;
119 119 * button.button("option","label",String(!v));
120 120 * })
121 121 *
122 122 * // add the button to the DOM div.
123 123 * button_container.append(button);
124 124 * }
125 125 *
126 126 * // now we register the callback under the name `foo` to give the
127 127 * // user the ability to use it later
128 * MetaUI.register_callback('foo',toggle);
128 * CellToolbar.register_callback('foo',toggle);
129 129 */
130 MetaUI.register_callback = function(name, callback){
130 CellToolbar.register_callback = function(name, callback){
131 131 // what do we do if name already exist ?
132 MetaUI._callback_dict[name] = callback;
132 CellToolbar._callback_dict[name] = callback;
133 133 };
134 134
135 135 /**
136 136 * Register a preset of UI element in a cell toolbar.
137 137 * Not supported Yet.
138 138 * @method register_preset
139 139 * @param name {String} name to use to refer to the preset. It is advised to use a prefix with the name
140 140 * for easier sorting and avoid collision
141 141 * @param preset_list {List of String} reverse order of the button in the toolbar. Each String of the list
142 142 * should correspond to a name of a registerd callback.
143 143 *
144 144 * @private
145 145 * @example
146 146 *
147 * MetaUI.register_callback('foo.c1',function(div,cell){...});
148 * MetaUI.register_callback('foo.c2',function(div,cell){...});
149 * MetaUI.register_callback('foo.c3',function(div,cell){...});
150 * MetaUI.register_callback('foo.c4',function(div,cell){...});
151 * MetaUI.register_callback('foo.c5',function(div,cell){...});
147 * CellToolbar.register_callback('foo.c1',function(div,cell){...});
148 * CellToolbar.register_callback('foo.c2',function(div,cell){...});
149 * CellToolbar.register_callback('foo.c3',function(div,cell){...});
150 * CellToolbar.register_callback('foo.c4',function(div,cell){...});
151 * CellToolbar.register_callback('foo.c5',function(div,cell){...});
152 152 *
153 * MetaUI.register_preset('foo.foo_preset1',['foo.c1','foo.c2','foo.c5'])
154 * MetaUI.register_preset('foo.foo_preset2',['foo.c4','foo.c5'])
153 * CellToolbar.register_preset('foo.foo_preset1',['foo.c1','foo.c2','foo.c5'])
154 * CellToolbar.register_preset('foo.foo_preset2',['foo.c4','foo.c5'])
155 155 */
156 MetaUI.register_preset = function(name, preset_list){
157 MetaUI._presets[name] = preset_list
158 MetaUI.$dropdown_preset_selector.append(
156 CellToolbar.register_preset = function(name, preset_list){
157 CellToolbar._presets[name] = preset_list
158 CellToolbar.dropdown_preset_element.append(
159 159 $('<option/>').attr('value',name).text(name)
160 160 )
161 161 }
162 162 /**
163 163 * set an UI preset from `register_preset`
164 164 * @method set_preset
165 165 * @param preset_name {String} string corresponding to the preset name
166 166 *
167 167 * @static
168 168 * @private
169 169 * @example
170 170 *
171 * MetaUI.set_preset('foo.foo_preset1');
171 * CellToolbar.set_preset('foo.foo_preset1');
172 172 */
173 MetaUI.set_preset= function(preset_name){
174 var preset = MetaUI._presets[preset_name];
173 CellToolbar.set_preset= function(preset_name){
174 var preset = CellToolbar._presets[preset_name];
175 175
176 176 if(preset != undefined){
177 MetaUI._button_list = preset;
178 MetaUI.rebuild_all();
177 CellToolbar._button_list = preset;
178 CellToolbar.rebuild_all();
179 179 }
180 180 }
181 181
182 182
183 183 // this is by design not a prototype.
184 184 /**
185 185 * This should be called on the class and not on a instance as it will trigger
186 186 * rebuild of all the instances.
187 187 * @method rebuild_all
188 188 * @static
189 189 *
190 190 */
191 MetaUI.rebuild_all = function(){
192 for(var i in MetaUI._instances){
193 MetaUI._instances[i].rebuild();
191 CellToolbar.rebuild_all = function(){
192 for(var i in CellToolbar._instances){
193 CellToolbar._instances[i].rebuild();
194 194 }
195 195 }
196 196
197 197 /**
198 198 * Rebuild all the button on the toolbar to update it's state.
199 199 * @method rebuild
200 200 */
201 MetaUI.prototype.rebuild = function(){
201 CellToolbar.prototype.rebuild = function(){
202 202 // strip evrything from the div
203 203 // which is probabli metainner.
204 // or this.$element.
205 this.$metainner.empty();
204 // or this.element.
205 this.inner_element.empty();
206 206 //this.add_raw_edit_button()
207 207
208 208
209 var cdict = MetaUI._callback_dict;
210 var preset = MetaUI._button_list;
209 var cdict = CellToolbar._callback_dict;
210 var preset = CellToolbar._button_list;
211 211 // Yes we iterate on the class varaible, not the instance one.
212 for ( var index in MetaUI._button_list){
212 for ( var index in CellToolbar._button_list){
213 213 var local_div = $('<div/>').addClass('button_container');
214 214 // Note,
215 215 // do this the other way, wrap in try/catch and don't append if any errors.
216 this.$metainner.append(local_div)
216 this.inner_element.append(local_div)
217 217 cdict[preset[index]](local_div,this.cell)
218 218 }
219 219
220 220 }
221 221
222 222 var raw_edit = function(cell){
223 223
224 224 var md = cell.metadata
225 225
226 226 var textarea = $('<textarea/>')
227 227 .attr('rows','13')
228 228 .attr('cols','75')
229 229 .attr('name','metadata')
230 230 .text(JSON.stringify(md, null,4)||'');
231 231 var dialogform = $('<div/>').attr('title','Edit the metadata')
232 232 .append(
233 233 $('<form/>').append(
234 234 $('<fieldset/>').append(
235 235 $('<label/>')
236 236 .attr('for','metadata')
237 237 .text("Metadata (I know what I'm dooing and I won't complain if it breaks my notebook)")
238 238 )
239 239 .append($('<br/>'))
240 240 .append(
241 241 textarea
242 242 )
243 243 )
244 244 );
245 245 var editor = CodeMirror.fromTextArea(textarea[0], {
246 246 lineNumbers: true,
247 247 matchBrackets: true,
248 248 });
249 249 $(dialogform).dialog({
250 250 autoOpen: true,
251 251 height: 300,
252 252 width: 650,
253 253 modal: true,
254 254 buttons: {
255 255 "Ok": function() {
256 256 //validate json and set it
257 257 try {
258 258 var json = JSON.parse(editor.getValue());
259 259 cell.metadata = json;
260 260 $( this ).dialog( "close" );
261 261 }
262 262 catch(e)
263 263 {
264 264 alert('invalid json');
265 265 }
266 266 },
267 267 Cancel: function() {
268 268 $( this ).dialog( "close" );
269 269 }
270 270 },
271 271 close: function() {
272 272 //cleanup on close
273 273 $(this).remove();
274 274 }
275 275 });
276 276 editor.refresh();
277 277 }
278 278
279 279
280 280 var add_raw_edit_button = function(div, cell) {
281 281 var button_container = $(div)
282 282 var button = $('<div/>').button({label:'Raw Edit'})
283 283 .click(function(){raw_edit(cell); return false;})
284 284 button_container.append(button);
285 285 }
286 286
287 MetaUI.register_callback('example.rawedit',add_raw_edit_button);
287 CellToolbar.register_callback('example.rawedit',add_raw_edit_button);
288 288 var example_preset = []
289 289 example_preset.push('example.rawedit');
290 290
291 291 var simple_dialog = function(title,text){
292 292 var dlg = $('<div/>').attr('title',title)
293 293 .append($('<p/>').text(text))
294 294 $(dlg).dialog({
295 295 autoOpen: true,
296 296 height: 300,
297 297 width: 650,
298 298 modal: true,
299 299 close: function() {
300 300 //cleanup on close
301 301 $(this).remove();
302 302 }
303 303 });
304 304 }
305 305
306 306 var add_simple_dialog_button = function(div, cell) {
307 307 var help_text = ["This is the Metadata editting UI.",
308 308 "It heavily rely on plugin to work ",
309 309 "and is still under developpement. You shouldn't wait too long before",
310 310 " seeing some customisable buttons in those toolbar."
311 311 ].join('\n')
312 312 var button_container = $(div)
313 313 var button = $('<div/>').button({label:'?'})
314 314 .click(function(){simple_dialog('help',help_text); return false;})
315 315 button_container.append(button);
316 316 }
317 317
318 MetaUI.register_callback('default.help',add_simple_dialog_button)
318 CellToolbar.register_callback('default.help',add_simple_dialog_button)
319 319 var default_preset = []
320 320 default_preset.push('default.help')
321 MetaUI.register_preset('default',default_preset)
322 MetaUI.set_preset('default')
321 CellToolbar.register_preset('default',default_preset)
322 CellToolbar.set_preset('default')
323 323
324 324 var simple_button = function(div, cell) {
325 325 var button_container = $(div);
326 326 var button = $('<div/>').button({icons:{primary:'ui-icon-locked'}});
327 327 var fun = function(value){
328 328 try{
329 329 if(value){
330 330 cell.code_mirror.setOption('readOnly','nocursor')
331 331 button.button('option','icons',{primary:'ui-icon-locked'})
332 332 } else {
333 333 cell.code_mirror.setOption('readOnly','false')
334 334 button.button('option','icons',{primary:'ui-icon-unlocked'})
335 335 }
336 336 } catch(e){}
337 337
338 338 }
339 339 fun(cell.metadata.ro)
340 340 button.click(function(){
341 341 var v = cell.metadata.ro;
342 342 var locked = !v;
343 343 cell.metadata.ro = locked;
344 344 fun(locked)
345 345 })
346 346 .css('height','16px')
347 347 .css('width','35px');
348 348 button_container.append(button);
349 349 }
350 350
351 MetaUI.register_callback('example.lock',simple_button);
351 CellToolbar.register_callback('example.lock',simple_button);
352 352 example_preset.push('example.lock');
353 353
354 354 var toggle_test = function(div, cell) {
355 355 var button_container = $(div)
356 356 var button = $('<div/>').button({label:String(cell.metadata.foo)});
357 357 button.click(function(){
358 358 var v = cell.metadata.foo;
359 359 cell.metadata.foo = !v;
360 360 button.button("option","label",String(!v));
361 361 })
362 362 button_container.append(button);
363 363 }
364 364
365 MetaUI.register_callback('example.toggle',toggle_test);
365 CellToolbar.register_callback('example.toggle',toggle_test);
366 366 example_preset.push('example.toggle');
367 367
368 368 /**
369 369 */
370 MetaUI.utils = {};
370 CellToolbar.utils = {};
371 371
372 372 /**
373 373 * A utility function to generate bindings between a checkbox and metadata
374 374 * @method utils.checkbox_ui_generator
375 375 * @static
376 376 *
377 377 * @param name {string} Label in front of the checkbox
378 378 * @param setter {function( metadata_dict, newValue )}
379 379 * A setter method to set the newValue of the metadata dictionnary
380 380 * @param getter {function( metadata )}
381 381 * A getter methods which return the current value of the metadata.
382 382 *
383 383 * @return callback {function( div, cell )} Callback to be passed to `register_callback`
384 384 *
385 385 * @example
386 386 *
387 387 * An exmple that bind the subkey `slideshow.isSectionStart` to a checkbox with a `New Slide` label
388 388 *
389 * var newSlide = MetaUI.utils.checkbox_ui_generator('New Slide',
389 * var newSlide = CellToolbar.utils.checkbox_ui_generator('New Slide',
390 390 * // setter
391 391 * function(metadata,value){
392 392 * // we check that the slideshow namespace exist and create it if needed
393 393 * if (metadata.slideshow == undefined){metadata.slideshow = {}}
394 394 * // set the value
395 395 * metadata.slideshow.isSectionStart = value
396 396 * },
397 397 * //geter
398 398 * function(metadata){ var ns = metadata.slideshow;
399 399 * // if the slideshow namespace does not exist return `undefined`
400 400 * // (will be interpreted as `false` by checkbox) otherwise
401 401 * // return the value
402 402 * return (ns == undefined)? undefined: ns.isSectionStart
403 403 * }
404 404 * );
405 405 *
406 * MetaUI.register_callback('newSlide', newSlide);
406 * CellToolbar.register_callback('newSlide', newSlide);
407 407 *
408 408 */
409 MetaUI.utils.checkbox_ui_generator = function(name,setter,getter){
409 CellToolbar.utils.checkbox_ui_generator = function(name,setter,getter){
410 410 return function(div, cell) {
411 411 var button_container = $(div)
412 412
413 413 var chkb = $('<input/>').attr('type','checkbox');
414 414 var lbl = $('<label/>').append($('<span/>').text(name).css('font-size','77%'));
415 415 lbl.append(chkb);
416 416 chkb.attr("checked",getter(cell.metadata));
417 417
418 418 chkb.click(function(){
419 419 var v = getter(cell.metadata);
420 420 setter(cell.metadata,!v);
421 421 chkb.attr("checked",!v);
422 422 })
423 423 button_container.append($('<div/>').append(lbl));
424 424
425 425 }
426 426 }
427 427
428 428 /**
429 429 * A utility function to generate bindings between a dropdown list and metadata
430 430 * @method utils.select_ui_generator
431 431 * @static
432 432 *
433 433 * @param list_list {list of sublist} List of sublist of metadata value and name in the dropdown list.
434 434 * subslit shoud contain 2 element each, first a string that woul be displayed in the dropdown list,
435 435 * and second the corresponding value for the metadata to be passed to setter/return by getter.
436 436 * @param setter {function( metadata_dict, newValue )}
437 437 * A setter method to set the newValue of the metadata dictionnary
438 438 * @param getter {function( metadata )}
439 439 * A getter methods which return the current value of the metadata.
440 440 * @param [label=""] {String} optionnal label for the dropdown menu
441 441 *
442 442 * @return callback {function( div, cell )} Callback to be passed to `register_callback`
443 443 *
444 444 * @example
445 445 *
446 * var select_type = MetaUI.utils.select_ui_generator([
446 * var select_type = CellToolbar.utils.select_ui_generator([
447 447 * ["-" ,undefined ],
448 448 * ["Header Slide" ,"header_slide" ],
449 449 * ["Slide" ,"slide" ],
450 450 * ["Fragment" ,"fragment" ],
451 451 * ["Skip" ,"skip" ],
452 452 * ],
453 453 * // setter
454 454 * function(metadata,value){
455 455 * // we check that the slideshow namespace exist and create it if needed
456 456 * if (metadata.slideshow == undefined){metadata.slideshow = {}}
457 457 * // set the value
458 458 * metadata.slideshow.slide_type = value
459 459 * },
460 460 * //geter
461 461 * function(metadata){ var ns = metadata.slideshow;
462 462 * // if the slideshow namespace does not exist return `undefined`
463 463 * // (will be interpreted as `false` by checkbox) otherwise
464 464 * // return the value
465 465 * return (ns == undefined)? undefined: ns.slide_type
466 466 * }
467 * MetaUI.register_callback('slideshow.select',select_type);
467 * CellToolbar.register_callback('slideshow.select',select_type);
468 468 *
469 469 */
470 MetaUI.utils.select_ui_generator = function(list_list,setter, getter, label){
470 CellToolbar.utils.select_ui_generator = function(list_list,setter, getter, label){
471 471 label= label? label: "";
472 472 return function(div, cell) {
473 473 var button_container = $(div)
474 474 var lbl = $("<label/>").append($('<span/>').text(label).css('font-size','77%'));
475 475 var select = $('<select/>');
476 476 for(var itemn in list_list){
477 477 var opt = $('<option/>');
478 478 opt.attr('value',list_list[itemn][1])
479 479 opt.text(list_list[itemn][0])
480 480 select.append(opt);
481 481 }
482 482 select.val(getter(cell.metadata));
483 483
484 484 select.change(function(){
485 485 setter(cell.metadata,select.val());
486 486 });
487 487 button_container.append($('<div/>').append(lbl).append(select));
488 488
489 489 }
490 490 };
491 491
492 492
493 IPython.MetaUI = MetaUI;
493 IPython.CellToolbar = CellToolbar;
494 494
495 495 return IPython;
496 496 }(IPython));
@@ -1,533 +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 45 var cell = $("<div>").addClass('cell text_cell border-box-sizing vbox');
46 this.metaui = new IPython.MetaUI(this);
47 cell.append(this.metaui.$element);
46 this.celltoolbar = new IPython.CellToolbar(this);
47 cell.append(this.celltoolbar.element);
48 48 cell.attr('tabindex','2');
49 49 var input_area = $('<div/>').addClass('text_cell_input border-box-sizing');
50 50 this.code_mirror = CodeMirror(input_area.get(0), {
51 51 indentUnit : 4,
52 52 mode: this.code_mirror_mode,
53 53 theme: 'default',
54 54 value: this.placeholder,
55 55 readOnly: this.read_only,
56 56 lineWrapping : true,
57 57 extraKeys: {"Tab": "indentMore","Shift-Tab" : "indentLess"},
58 58 onKeyEvent: $.proxy(this.handle_codemirror_keyevent,this)
59 59 });
60 60 // The tabindex=-1 makes this div focusable.
61 61 var render_area = $('<div/>').addClass('text_cell_render border-box-sizing').
62 62 addClass('rendered_html').attr('tabindex','-1');
63 63 cell.append(input_area).append(render_area);
64 64 this.element = cell;
65 65 };
66 66
67 67
68 68 /**
69 69 * Bind the DOM evet to cell actions
70 70 * Need to be called after TextCell.create_element
71 71 * @private
72 72 * @method bind_event
73 73 */
74 74 TextCell.prototype.bind_events = function () {
75 75 IPython.Cell.prototype.bind_events.apply(this);
76 76 var that = this;
77 77 this.element.keydown(function (event) {
78 78 if (event.which === 13 && !event.shiftKey) {
79 79 if (that.rendered) {
80 80 that.edit();
81 81 return false;
82 82 };
83 83 };
84 84 });
85 85 this.element.dblclick(function () {
86 86 that.edit();
87 87 });
88 88 };
89 89
90 90 /**
91 91 * This method gets called in CodeMirror's onKeyDown/onKeyPress
92 92 * handlers and is used to provide custom key handling.
93 93 *
94 94 * Subclass should override this method to have custom handeling
95 95 *
96 96 * @method handle_codemirror_keyevent
97 97 * @param {CodeMirror} editor - The codemirror instance bound to the cell
98 98 * @param {event} event -
99 99 * @return {Boolean} `true` if CodeMirror should ignore the event, `false` Otherwise
100 100 */
101 101 TextCell.prototype.handle_codemirror_keyevent = function (editor, event) {
102 102
103 103 if (event.keyCode === 13 && (event.shiftKey || event.ctrlKey)) {
104 104 // Always ignore shift-enter in CodeMirror as we handle it.
105 105 return true;
106 106 }
107 107 return false;
108 108 };
109 109
110 110 /**
111 111 * Select the current cell and trigger 'focus'
112 112 * @method select
113 113 */
114 114 TextCell.prototype.select = function () {
115 115 IPython.Cell.prototype.select.apply(this);
116 116 var output = this.element.find("div.text_cell_render");
117 117 output.trigger('focus');
118 118 };
119 119
120 120 /**
121 121 * unselect the current cell and `render` it
122 122 * @method unselect
123 123 */
124 124 TextCell.prototype.unselect = function() {
125 125 // render on selection of another cell
126 126 this.render();
127 127 IPython.Cell.prototype.unselect.apply(this);
128 128 };
129 129
130 130 /**
131 131 *
132 132 * put the current cell in edition mode
133 133 * @method edit
134 134 */
135 135 TextCell.prototype.edit = function () {
136 136 if ( this.read_only ) return;
137 137 if (this.rendered === true) {
138 138 var text_cell = this.element;
139 139 var output = text_cell.find("div.text_cell_render");
140 140 output.hide();
141 141 text_cell.find('div.text_cell_input').show();
142 142 this.code_mirror.refresh();
143 143 this.code_mirror.focus();
144 144 // We used to need an additional refresh() after the focus, but
145 145 // it appears that this has been fixed in CM. This bug would show
146 146 // up on FF when a newly loaded markdown cell was edited.
147 147 this.rendered = false;
148 148 if (this.get_text() === this.placeholder) {
149 149 this.set_text('');
150 150 this.refresh();
151 151 }
152 152 }
153 153 };
154 154
155 155
156 156 /**
157 157 * Empty, Subclasses must define render.
158 158 * @method render
159 159 */
160 160 TextCell.prototype.render = function () {};
161 161
162 162
163 163 /**
164 164 * setter: {{#crossLink "TextCell/set_text"}}{{/crossLink}}
165 165 * @method get_text
166 166 * @retrun {string} CodeMirror current text value
167 167 */
168 168 TextCell.prototype.get_text = function() {
169 169 return this.code_mirror.getValue();
170 170 };
171 171
172 172 /**
173 173 * @param {string} text - Codemiror text value
174 174 * @see TextCell#get_text
175 175 * @method set_text
176 176 * */
177 177 TextCell.prototype.set_text = function(text) {
178 178 this.code_mirror.setValue(text);
179 179 this.code_mirror.refresh();
180 180 };
181 181
182 182 /**
183 183 * setter :{{#crossLink "TextCell/set_rendered"}}{{/crossLink}}
184 184 * @method get_rendered
185 185 * @return {html} html of rendered element
186 186 * */
187 187 TextCell.prototype.get_rendered = function() {
188 188 return this.element.find('div.text_cell_render').html();
189 189 };
190 190
191 191 /**
192 192 * @method set_rendered
193 193 */
194 194 TextCell.prototype.set_rendered = function(text) {
195 195 this.element.find('div.text_cell_render').html(text);
196 196 };
197 197
198 198 /**
199 199 * not deprecated, but implementation wrong
200 200 * @method at_top
201 201 * @deprecated
202 202 * @return {Boolean} true is cell rendered, false otherwise
203 203 * I doubt this is what it is supposed to do
204 204 * this implementation is completly false
205 205 */
206 206 TextCell.prototype.at_top = function () {
207 207 if (this.rendered) {
208 208 return true;
209 209 } else {
210 210 return false;
211 211 }
212 212 };
213 213
214 214
215 215 /**
216 216 * not deprecated, but implementation wrong
217 217 * @method at_bottom
218 218 * @deprecated
219 219 * @return {Boolean} true is cell rendered, false otherwise
220 220 * I doubt this is what it is supposed to do
221 221 * this implementation is completly false
222 222 * */
223 223 TextCell.prototype.at_bottom = function () {
224 224 if (this.rendered) {
225 225 return true;
226 226 } else {
227 227 return false;
228 228 }
229 229 };
230 230
231 231 /**
232 232 * Create Text cell from JSON
233 233 * @param {json} data - JSON serialized text-cell
234 234 * @method fromJSON
235 235 */
236 236 TextCell.prototype.fromJSON = function (data) {
237 237 IPython.Cell.prototype.fromJSON.apply(this, arguments);
238 238 if (data.cell_type === this.cell_type) {
239 239 if (data.source !== undefined) {
240 240 this.set_text(data.source);
241 241 // make this value the starting point, so that we can only undo
242 242 // to this state, instead of a blank cell
243 243 this.code_mirror.clearHistory();
244 244 this.set_rendered(data.rendered || '');
245 245 this.rendered = false;
246 246 this.render();
247 247 }
248 248 }
249 249 };
250 250
251 251 /** Generate JSON from cell
252 252 * @return {object} cell data serialised to json
253 253 */
254 254 TextCell.prototype.toJSON = function () {
255 255 var data = IPython.Cell.prototype.toJSON.apply(this);
256 256 data.cell_type = this.cell_type;
257 257 data.source = this.get_text();
258 258 return data;
259 259 };
260 260
261 261
262 262 /**
263 263 * @constructor HtmlCell
264 264 * @class HtmlCell
265 265 * @extends Ipython.TextCell
266 266 */
267 267 var HTMLCell = function () {
268 268 this.placeholder = "Type <strong>HTML</strong> and LaTeX: $\\alpha^2$";
269 269 IPython.TextCell.apply(this, arguments);
270 270 this.cell_type = 'html';
271 271 };
272 272
273 273
274 274 HTMLCell.prototype = new TextCell();
275 275
276 276 /**
277 277 * @method render
278 278 */
279 279 HTMLCell.prototype.render = function () {
280 280 if (this.rendered === false) {
281 281 var text = this.get_text();
282 282 if (text === "") { text = this.placeholder; }
283 283 this.set_rendered(text);
284 284 this.typeset();
285 285 this.element.find('div.text_cell_input').hide();
286 286 this.element.find("div.text_cell_render").show();
287 287 this.rendered = true;
288 288 }
289 289 };
290 290
291 291
292 292 /**
293 293 * @class MarkdownCell
294 294 * @constructor MarkdownCell
295 295 * @extends Ipython.HtmlCell
296 296 */
297 297 var MarkdownCell = function () {
298 298 this.placeholder = "Type *Markdown* and LaTeX: $\\alpha^2$";
299 299 IPython.TextCell.apply(this, arguments);
300 300 this.cell_type = 'markdown';
301 301 };
302 302
303 303
304 304 MarkdownCell.prototype = new TextCell();
305 305
306 306 /**
307 307 * @method render
308 308 */
309 309 MarkdownCell.prototype.render = function () {
310 310 if (this.rendered === false) {
311 311 var text = this.get_text();
312 312 if (text === "") { text = this.placeholder; }
313 313 text = IPython.mathjaxutils.remove_math(text)
314 314 var html = IPython.markdown_converter.makeHtml(text);
315 315 html = IPython.mathjaxutils.replace_math(html)
316 316 try {
317 317 this.set_rendered(html);
318 318 } catch (e) {
319 319 console.log("Error running Javascript in Markdown:");
320 320 console.log(e);
321 321 this.set_rendered($("<div/>").addClass("js-error").html(
322 322 "Error rendering Markdown!<br/>" + e.toString())
323 323 );
324 324 }
325 325 this.element.find('div.text_cell_input').hide();
326 326 this.element.find("div.text_cell_render").show();
327 327 var code_snippets = this.element.find("pre > code");
328 328 code_snippets.replaceWith(function () {
329 329 var code = $(this).html();
330 330 /* Substitute br for newlines and &nbsp; for spaces
331 331 before highlighting, since prettify doesn't
332 332 preserve those on all browsers */
333 333 code = code.replace(/(\r\n|\n|\r)/gm, "<br/>");
334 334 code = code.replace(/ /gm, '&nbsp;');
335 335 code = prettyPrintOne(code);
336 336
337 337 return '<code class="prettyprint">' + code + '</code>';
338 338 });
339 339 this.typeset()
340 340 this.rendered = true;
341 341 }
342 342 };
343 343
344 344
345 345 // RawCell
346 346
347 347 /**
348 348 * @class RawCell
349 349 * @constructor RawCell
350 350 * @extends Ipython.TextCell
351 351 */
352 352 var RawCell = function () {
353 353 this.placeholder = "Type plain text and LaTeX: $\\alpha^2$";
354 354 this.code_mirror_mode = 'rst';
355 355 IPython.TextCell.apply(this, arguments);
356 356 this.cell_type = 'raw';
357 357 var that = this
358 358
359 359 this.element.focusout(
360 360 function() { that.auto_highlight(); }
361 361 );
362 362 };
363 363
364 364
365 365 RawCell.prototype = new TextCell();
366 366
367 367 /**
368 368 * Trigger autodetection of highlight scheme for current cell
369 369 * @method auto_highlight
370 370 */
371 371 RawCell.prototype.auto_highlight = function () {
372 372 this._auto_highlight(IPython.config.raw_cell_highlight);
373 373 };
374 374
375 375 /** @method render **/
376 376 RawCell.prototype.render = function () {
377 377 this.rendered = true;
378 378 this.edit();
379 379 };
380 380
381 381
382 382 /** @method handle_codemirror_keyevent **/
383 383 RawCell.prototype.handle_codemirror_keyevent = function (editor, event) {
384 384
385 385 var that = this;
386 386 if (event.which === key.UPARROW && event.type === 'keydown') {
387 387 // If we are not at the top, let CM handle the up arrow and
388 388 // prevent the global keydown handler from handling it.
389 389 if (!that.at_top()) {
390 390 event.stop();
391 391 return false;
392 392 } else {
393 393 return true;
394 394 };
395 395 } else if (event.which === key.DOWNARROW && event.type === 'keydown') {
396 396 // If we are not at the bottom, let CM handle the down arrow and
397 397 // prevent the global keydown handler from handling it.
398 398 if (!that.at_bottom()) {
399 399 event.stop();
400 400 return false;
401 401 } else {
402 402 return true;
403 403 };
404 404 };
405 405 return false;
406 406 };
407 407
408 408 /** @method select **/
409 409 RawCell.prototype.select = function () {
410 410 IPython.Cell.prototype.select.apply(this);
411 411 this.code_mirror.refresh();
412 412 this.code_mirror.focus();
413 413 };
414 414
415 415 /** @method at_top **/
416 416 RawCell.prototype.at_top = function () {
417 417 var cursor = this.code_mirror.getCursor();
418 418 if (cursor.line === 0 && cursor.ch === 0) {
419 419 return true;
420 420 } else {
421 421 return false;
422 422 }
423 423 };
424 424
425 425
426 426 /** @method at_bottom **/
427 427 RawCell.prototype.at_bottom = function () {
428 428 var cursor = this.code_mirror.getCursor();
429 429 if (cursor.line === (this.code_mirror.lineCount()-1) && cursor.ch === this.code_mirror.getLine(cursor.line).length) {
430 430 return true;
431 431 } else {
432 432 return false;
433 433 }
434 434 };
435 435
436 436
437 437 /**
438 438 * @class HeadingCell
439 439 * @extends Ipython.TextCell
440 440 */
441 441
442 442 /**
443 443 * @constructor HeadingCell
444 444 * @extends Ipython.TextCell
445 445 */
446 446 var HeadingCell = function () {
447 447 this.placeholder = "Type Heading Here";
448 448 IPython.TextCell.apply(this, arguments);
449 449 /**
450 450 * heading level of the cell, use getter and setter to access
451 451 * @property level
452 452 */
453 453 this.level = 1;
454 454 this.cell_type = 'heading';
455 455 };
456 456
457 457
458 458 HeadingCell.prototype = new TextCell();
459 459
460 460 /** @method fromJSON */
461 461 HeadingCell.prototype.fromJSON = function (data) {
462 462 if (data.level != undefined){
463 463 this.level = data.level;
464 464 }
465 465 IPython.TextCell.prototype.fromJSON.apply(this, arguments);
466 466 };
467 467
468 468
469 469 /** @method toJSON */
470 470 HeadingCell.prototype.toJSON = function () {
471 471 var data = IPython.TextCell.prototype.toJSON.apply(this);
472 472 data.level = this.get_level();
473 473 return data;
474 474 };
475 475
476 476
477 477 /**
478 478 * Change heading level of cell, and re-render
479 479 * @method set_level
480 480 */
481 481 HeadingCell.prototype.set_level = function (level) {
482 482 this.level = level;
483 483 if (this.rendered) {
484 484 this.rendered = false;
485 485 this.render();
486 486 };
487 487 };
488 488
489 489 /** The depth of header cell, based on html (h1 to h6)
490 490 * @method get_level
491 491 * @return {integer} level - for 1 to 6
492 492 */
493 493 HeadingCell.prototype.get_level = function () {
494 494 return this.level;
495 495 };
496 496
497 497
498 498 HeadingCell.prototype.set_rendered = function (text) {
499 499 var r = this.element.find("div.text_cell_render");
500 500 r.empty();
501 501 r.append($('<h'+this.level+'/>').html(text));
502 502 };
503 503
504 504
505 505 HeadingCell.prototype.get_rendered = function () {
506 506 var r = this.element.find("div.text_cell_render");
507 507 return r.children().first().html();
508 508 };
509 509
510 510
511 511 HeadingCell.prototype.render = function () {
512 512 if (this.rendered === false) {
513 513 var text = this.get_text();
514 514 if (text === "") { text = this.placeholder; }
515 515 this.set_rendered(text);
516 516 this.typeset();
517 517 this.element.find('div.text_cell_input').hide();
518 518 this.element.find("div.text_cell_render").show();
519 519 this.rendered = true;
520 520 };
521 521 };
522 522
523 523 IPython.TextCell = TextCell;
524 524 IPython.HTMLCell = HTMLCell;
525 525 IPython.MarkdownCell = MarkdownCell;
526 526 IPython.RawCell = RawCell;
527 527 IPython.HeadingCell = HeadingCell;
528 528
529 529
530 530 return IPython;
531 531
532 532 }(IPython));
533 533
General Comments 0
You need to be logged in to leave comments. Login now