##// END OF EJS Templates
rename _button_list to _ui_controls_list
Matthias BUSSONNIER -
Show More
@@ -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 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 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 25 * @class CellToolbar
26 26 * @param {The cell to attach the metadata UI to} cell
27 27 */
28 28 var CellToolbar = function (cell) {
29 29 CellToolbar._instances.push(this);
30 30 this.inner_element = $('<div/>');
31 31 this.cell = cell;
32 32 this.element = $('<div/>').addClass('celltoolbar')
33 33 .append(this.inner_element)
34 34 this.rebuild();
35 35 return this;
36 36 };
37 37
38 38 CellToolbar.dropdown_preset_element = $('<select/>')
39 39 .attr('id','celltoolbar_selector')
40 40 .append($('<option/>').attr('value','').text('-'))
41 41
42 42 CellToolbar.dropdown_preset_element.change(function(){
43 43 var val = CellToolbar.dropdown_preset_element.val()
44 44 if(val ==''){
45 45 $('body').removeClass('celltoolbar-on')
46 46 } else {
47 47 $('body').addClass('celltoolbar-on')
48 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 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 * @property _button_list
65 * @property _ui_controls_list
66 66 * @private
67 67 */
68 CellToolbar._button_list = [];
68 CellToolbar._ui_controls_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 75 * or loop over the cells, and find their CellToolbar instances.
76 76 * @private
77 77 * @property _instances
78 78 */
79 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 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 128 * CellToolbar.register_callback('foo',toggle);
129 129 */
130 130 CellToolbar.register_callback = function(name, callback){
131 131 // what do we do if name already exist ?
132 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 147 * CellToolbar.register_callback('foo.c1',function(div,cell){...});
148 148 * CellToolbar.register_callback('foo.c2',function(div,cell){...});
149 149 * CellToolbar.register_callback('foo.c3',function(div,cell){...});
150 150 * CellToolbar.register_callback('foo.c4',function(div,cell){...});
151 151 * CellToolbar.register_callback('foo.c5',function(div,cell){...});
152 152 *
153 153 * CellToolbar.register_preset('foo.foo_preset1',['foo.c1','foo.c2','foo.c5'])
154 154 * CellToolbar.register_preset('foo.foo_preset2',['foo.c4','foo.c5'])
155 155 */
156 156 CellToolbar.register_preset = function(name, preset_list){
157 157 CellToolbar._presets[name] = preset_list
158 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 171 * CellToolbar.set_preset('foo.foo_preset1');
172 172 */
173 173 CellToolbar.set_preset= function(preset_name){
174 174 var preset = CellToolbar._presets[preset_name];
175 175
176 176 if(preset != undefined){
177 CellToolbar._button_list = preset;
177 CellToolbar._ui_controls_list = preset;
178 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 191 CellToolbar.rebuild_all = function(){
192 192 for(var i in CellToolbar._instances){
193 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 201 CellToolbar.prototype.rebuild = function(){
202 202 // strip evrything from the div
203 203 // which is probabli metainner.
204 204 // or this.element.
205 205 this.inner_element.empty();
206 206 //this.add_raw_edit_button()
207 207
208 208
209 209 var cdict = CellToolbar._callback_dict;
210 var preset = CellToolbar._button_list;
210 var preset = CellToolbar._ui_controls_list;
211 211 // Yes we iterate on the class varaible, not the instance one.
212 for ( var index in CellToolbar._button_list){
212 for ( var index in CellToolbar._ui_controls_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 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 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 318 CellToolbar.register_callback('default.help',add_simple_dialog_button)
319 319 var default_preset = []
320 320 default_preset.push('default.help')
321 321 CellToolbar.register_preset('default',default_preset)
322 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 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 365 CellToolbar.register_callback('example.toggle',toggle_test);
366 366 example_preset.push('example.toggle');
367 367
368 368 /**
369 369 */
370 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 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 406 * CellToolbar.register_callback('newSlide', newSlide);
407 407 *
408 408 */
409 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 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 467 * CellToolbar.register_callback('slideshow.select',select_type);
468 468 *
469 469 */
470 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 493 IPython.CellToolbar = CellToolbar;
494 494
495 495 return IPython;
496 496 }(IPython));
General Comments 0
You need to be logged in to leave comments. Login now