##// END OF EJS Templates
enable dropdown preset change
Matthias BUSSONNIER -
Show More
@@ -1,187 +1,178
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('MetaUI'))
22 .append(IPython.MetaUI.dropdown_preset_selector)
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 this.add_buttons_group([
120 {
121 id : 'show_meta',
122 label : 'Show Per Cell Toolbar',
123 icon : 'ui-icon-image',
124 callback : function () {
125 $('body').toggleClass('editmetaon');
126 }
127 }
128 ],'meta_on');
129
130 121 };
131 122
132 123 MainToolBar.prototype.add_drop_down_list = function () {
133 124 var select = $(this.selector)
134 125 .append($('<select/>')
135 126 .attr('id','cell_type')
136 127 .addClass('ui-widget ui-widget-content')
137 128 .append($('<option/>').attr('value','code').text('Code'))
138 129 .append($('<option/>').attr('value','markdown').text('Markdown'))
139 130 .append($('<option/>').attr('value','raw').text('Raw Text'))
140 131 .append($('<option/>').attr('value','heading1').text('Heading 1'))
141 132 .append($('<option/>').attr('value','heading2').text('Heading 2'))
142 133 .append($('<option/>').attr('value','heading3').text('Heading 3'))
143 134 .append($('<option/>').attr('value','heading4').text('Heading 4'))
144 135 .append($('<option/>').attr('value','heading5').text('Heading 5'))
145 136 .append($('<option/>').attr('value','heading6').text('Heading 6'))
146 137 );
147 138 };
148 139
149 140 MainToolBar.prototype.bind_events = function () {
150 141 var that = this;
151 142
152 143 this.element.find('#cell_type').change(function () {
153 144 var cell_type = $(this).val();
154 145 if (cell_type === 'code') {
155 146 IPython.notebook.to_code();
156 147 } else if (cell_type === 'markdown') {
157 148 IPython.notebook.to_markdown();
158 149 } else if (cell_type === 'raw') {
159 150 IPython.notebook.to_raw();
160 151 } else if (cell_type === 'heading1') {
161 152 IPython.notebook.to_heading(undefined, 1);
162 153 } else if (cell_type === 'heading2') {
163 154 IPython.notebook.to_heading(undefined, 2);
164 155 } else if (cell_type === 'heading3') {
165 156 IPython.notebook.to_heading(undefined, 3);
166 157 } else if (cell_type === 'heading4') {
167 158 IPython.notebook.to_heading(undefined, 4);
168 159 } else if (cell_type === 'heading5') {
169 160 IPython.notebook.to_heading(undefined, 5);
170 161 } else if (cell_type === 'heading6') {
171 162 IPython.notebook.to_heading(undefined, 6);
172 163 }
173 164 });
174 165 $([IPython.events]).on('selected_cell_type_changed.Notebook', function (event, data) {
175 166 if (data.cell_type === 'heading') {
176 167 that.element.find('#cell_type').val(data.cell_type+data.level);
177 168 } else {
178 169 that.element.find('#cell_type').val(data.cell_type);
179 170 }
180 171 });
181 172 };
182 173
183 174 IPython.MainToolBar = MainToolBar;
184 175
185 176 return IPython;
186 177
187 178 }(IPython));
@@ -1,476 +1,496
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 9 // MetaUI
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 17 * @submodule MetaUI
18 18 */
19 19 var IPython = (function (IPython) {
20 20 "use strict";
21 21
22 22
23 23 /**
24 24 * @constructor
25 25 * @class MetaUI
26 26 * @param {The cell to attach the metadata UI to} cell
27 27 */
28 28 var MetaUI = function (cell) {
29 29 MetaUI._instances.push(this);
30 30 this.metainner = $('<div/>');
31 31 this.cell = cell;
32 32 this.element = $('<div/>').addClass('metaedit')
33 33 .append(this.metainner)
34 34 this.rebuild();
35 35 return this;
36 36 };
37 37
38 MetaUI.dropdown_preset_selector = $('<select/>')
39 .attr('id','metaui_selector')
40 .append($('<option/>').attr('value','').text('-'))
41
42 MetaUI.dropdown_preset_selector.change(function(){
43 var val = MetaUI.dropdown_preset_selector.val()
44 if(val ==''){
45 $('body').removeClass('editmetaon')
46 } else {
47 $('body').addClass('editmetaon')
48 MetaUI.set_preset(val)
49 }
50 })
51
52
53
38 54 /**
39 55 * Class variable that should contain a dict of all availlable callback
40 56 * we need to think of wether or not we allow nested namespace
41 57 * @property _callback_dict
42 58 * @private
43 59 */
44 60 MetaUI._callback_dict = {};
45 61
46 62 /**
47 63 * Class variable that should contain the reverse order list of the button
48 64 * to add to the toolbar of each cell
49 65 * @property _button_list
50 66 * @private
51 67 */
52 68 MetaUI._button_list = [];
53 69
54 70 /**
55 71 * keep a list of all instances to
56 72 * be able to llop over them...
57 73 * but how to 'destroy' them ?
58 74 * have to think about it...
59 75 * or loop over the cells, and find their MetaUI instances.
60 76 * @private
61 77 * @property _instances
62 78 */
63 79 MetaUI._instances =[]
64 80
65 81 /**
66 82 * keep a list of all the availlabel presets for the toolbar
67 83 * @private
68 84 * @property _presets
69 85 */
70 86 MetaUI._presets ={}
71 87
72 88 // this is by design not a prototype.
73 89 /**
74 90 * Register a callback to create an UI element in a cell toolbar.
75 91 * @method register_callback
76 92 * @param name {String} name to use to refer to the callback. It is advised to use a prefix with the name
77 93 * for easier sorting and avoid collision
78 94 * @param callback {function(div, cell)} callback that will be called to generate the ui element
79 95 *
80 96 *
81 97 * The callback will receive the following element :
82 98 *
83 99 * * a div in which to add element.
84 100 * * the cell it is responsable from
85 101 *
86 102 * @example
87 103 *
88 104 * Example that create callback for a button that toggle between `true` and `false` label,
89 105 * with the metadata under the key 'foo' to reflect the status of the button.
90 106 *
91 107 * // first param reference to a DOM div
92 108 * // second param reference to the cell.
93 109 * var toggle = function(div, cell) {
94 110 * var button_container = $(div)
95 111 *
96 112 * // let's create a button that show the current value of the metadata
97 113 * var button = $('<div/>').button({label:String(cell.metadata.foo)});
98 114 *
99 115 * // On click, change the metadata value and update the button label
100 116 * button.click(function(){
101 117 * var v = cell.metadata.foo;
102 118 * cell.metadata.foo = !v;
103 119 * button.button("option","label",String(!v));
104 120 * })
105 121 *
106 122 * // add the button to the DOM div.
107 123 * button_container.append(button);
108 124 * }
109 125 *
110 126 * // now we register the callback under the name `foo` to give the
111 127 * // user the ability to use it later
112 128 * MetaUI.register_callback('foo',toggle);
113 129 */
114 130 MetaUI.register_callback = function(name, callback){
115 131 // what do we do if name already exist ?
116 132 MetaUI._callback_dict[name] = callback;
117 133 };
118 134
119 135 /**
120 136 * Register a preset of UI element in a cell toolbar.
121 137 * Not supported Yet.
122 138 * @method register_preset
123 139 * @param name {String} name to use to refer to the preset. It is advised to use a prefix with the name
124 140 * for easier sorting and avoid collision
125 141 * @param preset_list {List of String} reverse order of the button in the toolbar. Each String of the list
126 142 * should correspond to a name of a registerd callback.
127 143 *
128 144 * @private
129 145 * @example
130 146 *
131 147 * MetaUI.register_callback('foo.c1',function(div,cell){...});
132 148 * MetaUI.register_callback('foo.c2',function(div,cell){...});
133 149 * MetaUI.register_callback('foo.c3',function(div,cell){...});
134 150 * MetaUI.register_callback('foo.c4',function(div,cell){...});
135 151 * MetaUI.register_callback('foo.c5',function(div,cell){...});
136 152 *
137 153 * MetaUI.register_preset('foo.foo_preset1',['foo.c1','foo.c2','foo.c5'])
138 154 * MetaUI.register_preset('foo.foo_preset2',['foo.c4','foo.c5'])
139 155 */
140 156 MetaUI.register_preset = function(name, preset_list){
141 157 MetaUI._presets[name] = preset_list
158 MetaUI.dropdown_preset_selector.append(
159 $('<option/>').attr('value',name).text(name)
160 )
142 161 }
143 162 /**
144 163 * set an UI preset from `register_preset`
145 164 * @method set_preset
146 165 * @param preset_name {String} string corresponding to the preset name
147 166 *
148 167 * @static
149 168 * @private
150 169 * @example
151 170 *
152 171 * MetaUI.set_preset('foo.foo_preset1');
153 172 */
154 173 MetaUI.set_preset= function(preset_name){
155 174 var preset = MetaUI._presets[preset_name];
156 175
157 176 if(preset != undefined){
158 177 MetaUI._button_list = preset;
159 178 MetaUI.rebuild_all();
160 179 }
161 180 }
162 181
182
163 183 // this is by design not a prototype.
164 184 /**
165 185 * This should be called on the class and not on a instance as it will trigger
166 186 * rebuild of all the instances.
167 187 * @method rebuild_all
168 188 * @static
169 189 *
170 190 */
171 191 MetaUI.rebuild_all = function(){
172 192 for(var i in MetaUI._instances){
173 193 MetaUI._instances[i].rebuild();
174 194 }
175 195 }
176 196
177 197 /**
178 198 * Rebuild all the button on the toolbar to update it's state.
179 199 * @method rebuild
180 200 */
181 201 MetaUI.prototype.rebuild = function(){
182 202 // strip evrything from the div
183 203 // which is probabli metainner.
184 204 // or this.element.
185 205 this.metainner.empty();
186 206 //this.add_raw_edit_button()
187 207
188 208
189 209 var cdict = MetaUI._callback_dict;
190 210 var preset = MetaUI._button_list;
191 211 // Yes we iterate on the class varaible, not the instance one.
192 212 for ( var index in MetaUI._button_list){
193 213 var local_div = $('<div/>').addClass('button_container');
194 214 // Note,
195 215 // do this the other way, wrap in try/catch and don't append if any errors.
196 216 this.metainner.append(local_div)
197 217 cdict[preset[index]](local_div,this.cell)
198 218 }
199 219
200 220 }
201 221
202 222 var raw_edit = function(cell){
203 223
204 224 var md = cell.metadata
205 225
206 226 var textarea = $('<textarea/>')
207 227 .attr('rows','13')
208 228 .attr('cols','75')
209 229 .attr('name','metadata')
210 230 .text(JSON.stringify(md, null,4)||'');
211 231 var dialogform = $('<div/>').attr('title','Edit the metadata')
212 232 .append(
213 233 $('<form/>').append(
214 234 $('<fieldset/>').append(
215 235 $('<label/>')
216 236 .attr('for','metadata')
217 237 .text("Metadata (I know what I'm dooing and I won't complain if it breaks my notebook)")
218 238 )
219 239 .append($('<br/>'))
220 240 .append(
221 241 textarea
222 242 )
223 243 )
224 244 );
225 245 var editor = CodeMirror.fromTextArea(textarea[0], {
226 246 lineNumbers: true,
227 247 matchBrackets: true,
228 248 });
229 249 $(dialogform).dialog({
230 250 autoOpen: true,
231 251 height: 300,
232 252 width: 650,
233 253 modal: true,
234 254 buttons: {
235 255 "Ok": function() {
236 256 //validate json and set it
237 257 try {
238 258 var json = JSON.parse(editor.getValue());
239 259 cell.metadata = json;
240 260 $( this ).dialog( "close" );
241 261 }
242 262 catch(e)
243 263 {
244 264 alert('invalid json');
245 265 }
246 266 },
247 267 Cancel: function() {
248 268 $( this ).dialog( "close" );
249 269 }
250 270 },
251 271 close: function() {
252 272 //cleanup on close
253 273 $(this).remove();
254 274 }
255 275 });
256 276 editor.refresh();
257 277 }
258 278
259 279
260 280 var add_raw_edit_button = function(div, cell) {
261 281 var button_container = $(div)
262 282 var button = $('<div/>').button({label:'Raw Edit'})
263 283 .click(function(){raw_edit(cell); return false;})
264 284 button_container.append(button);
265 285 }
266 286
267 287 MetaUI.register_callback('example.rawedit',add_raw_edit_button);
268 288 var example_preset = []
269 289 example_preset.push('example.rawedit');
270 290
271 291 var simple_dialog = function(title,text){
272 292 var dlg = $('<div/>').attr('title',title)
273 293 .append($('<p/>').text(text))
274 294 $(dlg).dialog({
275 295 autoOpen: true,
276 296 height: 300,
277 297 width: 650,
278 298 modal: true,
279 299 close: function() {
280 300 //cleanup on close
281 301 $(this).remove();
282 302 }
283 303 });
284 304 }
285 305
286 306 var add_simple_dialog_button = function(div, cell) {
287 307 var help_text = ["This is the Metadata editting UI.",
288 308 "It heavily rely on plugin to work ",
289 309 "and is still under developpement. You shouldn't wait too long before",
290 310 " seeing some customisable buttons in those toolbar."
291 311 ].join('\n')
292 312 var button_container = $(div)
293 313 var button = $('<div/>').button({label:'?'})
294 314 .click(function(){simple_dialog('help',help_text); return false;})
295 315 button_container.append(button);
296 316 }
297 317
298 318 MetaUI.register_callback('default.help',add_simple_dialog_button)
299 319 var default_preset = []
300 320 default_preset.push('default.help')
301 321 MetaUI.register_preset('default',default_preset)
302 322 MetaUI.set_preset('default')
303 323
304 324 var simple_button = function(div, cell) {
305 325 var button_container = $(div);
306 326 var button = $('<div/>').button({icons:{primary:'ui-icon-locked'}});
307 327 var fun = function(value){
308 328 try{
309 329 if(value){
310 330 cell.code_mirror.setOption('readOnly','nocursor')
311 331 button.button('option','icons',{primary:'ui-icon-locked'})
312 332 } else {
313 333 cell.code_mirror.setOption('readOnly','false')
314 334 button.button('option','icons',{primary:'ui-icon-unlocked'})
315 335 }
316 336 } catch(e){}
317 337
318 338 }
319 339 fun(cell.metadata.ro)
320 340 button.click(function(){
321 341 var v = cell.metadata.ro;
322 342 var locked = !v;
323 343 cell.metadata.ro = locked;
324 344 fun(locked)
325 345 })
326 346 .css('height','16px')
327 347 .css('width','35px');
328 348 button_container.append(button);
329 349 }
330 350
331 351 MetaUI.register_callback('example.lock',simple_button);
332 352 example_preset.push('example.lock');
333 353
334 354 var toggle_test = function(div, cell) {
335 355 var button_container = $(div)
336 356 var button = $('<div/>').button({label:String(cell.metadata.foo)});
337 357 button.click(function(){
338 358 var v = cell.metadata.foo;
339 359 cell.metadata.foo = !v;
340 360 button.button("option","label",String(!v));
341 361 })
342 362 button_container.append(button);
343 363 }
344 364
345 365 MetaUI.register_callback('example.toggle',toggle_test);
346 366 example_preset.push('example.toggle');
347 367
348 368 /**
349 369 */
350 370 MetaUI.utils = {};
351 371
352 372 /**
353 373 * A utility function to generate bindings between a checkbox and metadata
354 374 * @method utils.checkbox_ui_generator
355 375 * @static
356 376 *
357 377 * @param name {string} Label in front of the checkbox
358 378 * @param setter {function( metadata_dict, newValue )}
359 379 * A setter method to set the newValue of the metadata dictionnary
360 380 * @param getter {function( metadata )}
361 381 * A getter methods which return the current value of the metadata.
362 382 *
363 383 * @return callback {function( div, cell )} Callback to be passed to `register_callback`
364 384 *
365 385 * @example
366 386 *
367 387 * An exmple that bind the subkey `slideshow.isSectionStart` to a checkbox with a `New Slide` label
368 388 *
369 389 * var newSlide = MetaUI.utils.checkbox_ui_generator('New Slide',
370 390 * // setter
371 391 * function(metadata,value){
372 392 * // we check that the slideshow namespace exist and create it if needed
373 393 * if (metadata.slideshow == undefined){metadata.slideshow = {}}
374 394 * // set the value
375 395 * metadata.slideshow.isSectionStart = value
376 396 * },
377 397 * //geter
378 398 * function(metadata){ var ns = metadata.slideshow;
379 399 * // if the slideshow namespace does not exist return `undefined`
380 400 * // (will be interpreted as `false` by checkbox) otherwise
381 401 * // return the value
382 402 * return (ns == undefined)? undefined: ns.isSectionStart
383 403 * }
384 404 * );
385 405 *
386 406 * MetaUI.register_callback('newSlide', newSlide);
387 407 *
388 408 */
389 409 MetaUI.utils.checkbox_ui_generator = function(name,setter,getter){
390 410 return function(div, cell) {
391 411 var button_container = $(div)
392 412
393 413 var chkb = $('<input/>').attr('type','checkbox');
394 414 var lbl = $('<label/>').append($('<span/>').text(name).css('font-size','77%'));
395 415 lbl.append(chkb);
396 416 chkb.attr("checked",getter(cell.metadata));
397 417
398 418 chkb.click(function(){
399 419 var v = getter(cell.metadata);
400 420 setter(cell.metadata,!v);
401 421 chkb.attr("checked",!v);
402 422 })
403 423 button_container.append($('<div/>').append(lbl));
404 424
405 425 }
406 426 }
407 427
408 428 /**
409 429 * A utility function to generate bindings between a dropdown list and metadata
410 430 * @method utils.select_ui_generator
411 431 * @static
412 432 *
413 433 * @param list_list {list of sublist} List of sublist of metadata value and name in the dropdown list.
414 434 * subslit shoud contain 2 element each, first a string that woul be displayed in the dropdown list,
415 435 * and second the corresponding value for the metadata to be passed to setter/return by getter.
416 436 * @param setter {function( metadata_dict, newValue )}
417 437 * A setter method to set the newValue of the metadata dictionnary
418 438 * @param getter {function( metadata )}
419 439 * A getter methods which return the current value of the metadata.
420 440 * @param [label=""] {String} optionnal label for the dropdown menu
421 441 *
422 442 * @return callback {function( div, cell )} Callback to be passed to `register_callback`
423 443 *
424 444 * @example
425 445 *
426 446 * var select_type = MetaUI.utils.select_ui_generator([
427 447 * ["-" ,undefined ],
428 448 * ["Header Slide" ,"header_slide" ],
429 449 * ["Slide" ,"slide" ],
430 450 * ["Fragment" ,"fragment" ],
431 451 * ["Skip" ,"skip" ],
432 452 * ],
433 453 * // setter
434 454 * function(metadata,value){
435 455 * // we check that the slideshow namespace exist and create it if needed
436 456 * if (metadata.slideshow == undefined){metadata.slideshow = {}}
437 457 * // set the value
438 458 * metadata.slideshow.slide_type = value
439 459 * },
440 460 * //geter
441 461 * function(metadata){ var ns = metadata.slideshow;
442 462 * // if the slideshow namespace does not exist return `undefined`
443 463 * // (will be interpreted as `false` by checkbox) otherwise
444 464 * // return the value
445 465 * return (ns == undefined)? undefined: ns.slide_type
446 466 * }
447 467 * MetaUI.register_callback('slideshow.select',select_type);
448 468 *
449 469 */
450 470 MetaUI.utils.select_ui_generator = function(list_list,setter, getter, label){
451 471 label= label? label: "";
452 472 return function(div, cell) {
453 473 var button_container = $(div)
454 474 var lbl = $("<label/>").append($('<span/>').text(label).css('font-size','77%'));
455 475 var select = $('<select/>');
456 476 for(var itemn in list_list){
457 477 var opt = $('<option/>');
458 478 opt.attr('value',list_list[itemn][1])
459 479 opt.text(list_list[itemn][0])
460 480 select.append(opt);
461 481 }
462 482 select.val(getter(cell.metadata));
463 483
464 484 select.change(function(){
465 485 setter(cell.metadata,select.val());
466 486 });
467 487 button_container.append($('<div/>').append(lbl).append(select));
468 488
469 489 }
470 490 };
471 491
472 492
473 493 IPython.MetaUI = MetaUI;
474 494
475 495 return IPython;
476 496 }(IPython));
General Comments 0
You need to be logged in to leave comments. Login now