##// END OF EJS Templates
rename ipevents to events for consistency
Matthias BUSSONNIER -
Show More
@@ -1,416 +1,416 b''
1 1 // Copyright (c) IPython Development Team.
2 2 // Distributed under the terms of the Modified BSD License.
3 3
4 4 define([
5 5 'base/js/namespace',
6 6 'jquery',
7 7 'base/js/events'
8 ], function(IPython, $, ipevents) {
8 ], function(IPython, $, events) {
9 9 "use strict";
10 10
11 11 var CellToolbar = function (options) {
12 12 // Constructor
13 13 //
14 14 // Parameters:
15 15 // options: dictionary
16 16 // Dictionary of keyword arguments.
17 17 // events: $(Events) instance
18 18 // cell: Cell instance
19 19 // notebook: Notebook instance
20 20 CellToolbar._instances.push(this);
21 21 this.notebook = options.notebook;
22 22 this.cell = options.cell;
23 23 this.create_element();
24 24 this.rebuild();
25 25 return this;
26 26 };
27 27
28 28
29 29 CellToolbar.prototype.create_element = function () {
30 30 this.inner_element = $('<div/>').addClass('celltoolbar');
31 31 this.element = $('<div/>').addClass('ctb_hideshow')
32 32 .append(this.inner_element);
33 33 };
34 34
35 35
36 36 // The default css style for the outer celltoolbar div
37 37 // (ctb_hideshow) is display: none.
38 38 // To show the cell toolbar, *both* of the following conditions must be met:
39 39 // - A parent container has class `ctb_global_show`
40 40 // - The celltoolbar has the class `ctb_show`
41 41 // This allows global show/hide, as well as per-cell show/hide.
42 42
43 43 CellToolbar.global_hide = function () {
44 44 $('body').removeClass('ctb_global_show');
45 45 };
46 46
47 47
48 48 CellToolbar.global_show = function () {
49 49 $('body').addClass('ctb_global_show');
50 50 };
51 51
52 52
53 53 CellToolbar.prototype.hide = function () {
54 54 this.element.removeClass('ctb_show');
55 55 };
56 56
57 57
58 58 CellToolbar.prototype.show = function () {
59 59 this.element.addClass('ctb_show');
60 60 };
61 61
62 62
63 63 /**
64 64 * Class variable that should contain a dict of all available callback
65 65 * we need to think of wether or not we allow nested namespace
66 66 * @property _callback_dict
67 67 * @private
68 68 * @static
69 69 * @type Dict
70 70 */
71 71 CellToolbar._callback_dict = {};
72 72
73 73
74 74 /**
75 75 * Class variable that should contain the reverse order list of the button
76 76 * to add to the toolbar of each cell
77 77 * @property _ui_controls_list
78 78 * @private
79 79 * @static
80 80 * @type List
81 81 */
82 82 CellToolbar._ui_controls_list = [];
83 83
84 84
85 85 /**
86 86 * Class variable that should contain the CellToolbar instances for each
87 87 * cell of the notebook
88 88 *
89 89 * @private
90 90 * @property _instances
91 91 * @static
92 92 * @type List
93 93 */
94 94 CellToolbar._instances = [];
95 95
96 96
97 97 /**
98 98 * keep a list of all the available presets for the toolbar
99 99 * @private
100 100 * @property _presets
101 101 * @static
102 102 * @type Dict
103 103 */
104 104 CellToolbar._presets = {};
105 105
106 106
107 107 // this is by design not a prototype.
108 108 /**
109 109 * Register a callback to create an UI element in a cell toolbar.
110 110 * @method register_callback
111 111 * @param name {String} name to use to refer to the callback. It is advised to use a prefix with the name
112 112 * for easier sorting and avoid collision
113 113 * @param callback {function(div, cell)} callback that will be called to generate the ui element
114 114 * @param [cell_types] {List of String|undefined} optional list of cell types. If present the UI element
115 115 * will be added only to cells of types in the list.
116 116 *
117 117 *
118 118 * The callback will receive the following element :
119 119 *
120 120 * * a div in which to add element.
121 121 * * the cell it is responsible from
122 122 *
123 123 * @example
124 124 *
125 125 * Example that create callback for a button that toggle between `true` and `false` label,
126 126 * with the metadata under the key 'foo' to reflect the status of the button.
127 127 *
128 128 * // first param reference to a DOM div
129 129 * // second param reference to the cell.
130 130 * var toggle = function(div, cell) {
131 131 * var button_container = $(div)
132 132 *
133 133 * // let's create a button that show the current value of the metadata
134 134 * var button = $('<div/>').button({label:String(cell.metadata.foo)});
135 135 *
136 136 * // On click, change the metadata value and update the button label
137 137 * button.click(function(){
138 138 * var v = cell.metadata.foo;
139 139 * cell.metadata.foo = !v;
140 140 * button.button("option", "label", String(!v));
141 141 * })
142 142 *
143 143 * // add the button to the DOM div.
144 144 * button_container.append(button);
145 145 * }
146 146 *
147 147 * // now we register the callback under the name `foo` to give the
148 148 * // user the ability to use it later
149 149 * CellToolbar.register_callback('foo', toggle);
150 150 */
151 151 CellToolbar.register_callback = function(name, callback, cell_types) {
152 152 // Overwrite if it already exists.
153 153 CellToolbar._callback_dict[name] = cell_types ? {callback: callback, cell_types: cell_types} : callback;
154 154 };
155 155
156 156
157 157 /**
158 158 * Register a preset of UI element in a cell toolbar.
159 159 * Not supported Yet.
160 160 * @method register_preset
161 161 * @param name {String} name to use to refer to the preset. It is advised to use a prefix with the name
162 162 * for easier sorting and avoid collision
163 163 * @param preset_list {List of String} reverse order of the button in the toolbar. Each String of the list
164 164 * should correspond to a name of a registerd callback.
165 165 *
166 166 * @private
167 167 * @example
168 168 *
169 169 * CellToolbar.register_callback('foo.c1', function(div, cell){...});
170 170 * CellToolbar.register_callback('foo.c2', function(div, cell){...});
171 171 * CellToolbar.register_callback('foo.c3', function(div, cell){...});
172 172 * CellToolbar.register_callback('foo.c4', function(div, cell){...});
173 173 * CellToolbar.register_callback('foo.c5', function(div, cell){...});
174 174 *
175 175 * CellToolbar.register_preset('foo.foo_preset1', ['foo.c1', 'foo.c2', 'foo.c5'])
176 176 * CellToolbar.register_preset('foo.foo_preset2', ['foo.c4', 'foo.c5'])
177 177 */
178 178 CellToolbar.register_preset = function(name, preset_list, notebook) {
179 179 CellToolbar._presets[name] = preset_list;
180 ipevents.trigger('preset_added.CellToolbar', {name: name});
180 events.trigger('preset_added.CellToolbar', {name: name});
181 181 // When "register_callback" is called by a custom extension, it may be executed after notebook is loaded.
182 182 // In that case, activate the preset if needed.
183 183 if (notebook && notebook.metadata && notebook.metadata.celltoolbar === name){
184 184 CellToolbar.activate_preset(name);
185 185 }
186 186 };
187 187
188 188
189 189 /**
190 190 * List the names of the presets that are currently registered.
191 191 *
192 192 * @method list_presets
193 193 * @static
194 194 */
195 195 CellToolbar.list_presets = function() {
196 196 var keys = [];
197 197 for (var k in CellToolbar._presets) {
198 198 keys.push(k);
199 199 }
200 200 return keys;
201 201 };
202 202
203 203
204 204 /**
205 205 * Activate an UI preset from `register_preset`
206 206 *
207 207 * This does not update the selection UI.
208 208 *
209 209 * @method activate_preset
210 210 * @param preset_name {String} string corresponding to the preset name
211 211 *
212 212 * @static
213 213 * @private
214 214 * @example
215 215 *
216 216 * CellToolbar.activate_preset('foo.foo_preset1');
217 217 */
218 218 CellToolbar.activate_preset = function(preset_name){
219 219 var preset = CellToolbar._presets[preset_name];
220 220
221 221 if(preset !== undefined){
222 222 CellToolbar._ui_controls_list = preset;
223 223 CellToolbar.rebuild_all();
224 224 }
225 225
226 ipevents.trigger('preset_activated.CellToolbar', {name: preset_name});
226 events.trigger('preset_activated.CellToolbar', {name: preset_name});
227 227 };
228 228
229 229
230 230 /**
231 231 * This should be called on the class and not on a instance as it will trigger
232 232 * rebuild of all the instances.
233 233 * @method rebuild_all
234 234 * @static
235 235 *
236 236 */
237 237 CellToolbar.rebuild_all = function(){
238 238 for(var i=0; i < CellToolbar._instances.length; i++){
239 239 CellToolbar._instances[i].rebuild();
240 240 }
241 241 };
242 242
243 243 /**
244 244 * Rebuild all the button on the toolbar to update its state.
245 245 * @method rebuild
246 246 */
247 247 CellToolbar.prototype.rebuild = function(){
248 248 // strip evrything from the div
249 249 // which is probably inner_element
250 250 // or this.element.
251 251 this.inner_element.empty();
252 252 this.ui_controls_list = [];
253 253
254 254 var callbacks = CellToolbar._callback_dict;
255 255 var preset = CellToolbar._ui_controls_list;
256 256 // Yes we iterate on the class variable, not the instance one.
257 257 for (var i=0; i < preset.length; i++) {
258 258 var key = preset[i];
259 259 var callback = callbacks[key];
260 260 if (!callback) continue;
261 261
262 262 if (typeof callback === 'object') {
263 263 if (callback.cell_types.indexOf(this.cell.cell_type) === -1) continue;
264 264 callback = callback.callback;
265 265 }
266 266
267 267 var local_div = $('<div/>').addClass('button_container');
268 268 try {
269 269 callback(local_div, this.cell, this);
270 270 this.ui_controls_list.push(key);
271 271 } catch (e) {
272 272 console.log("Error in cell toolbar callback " + key, e);
273 273 continue;
274 274 }
275 275 // only append if callback succeeded.
276 276 this.inner_element.append(local_div);
277 277 }
278 278
279 279 // If there are no controls or the cell is a rendered TextCell hide the toolbar.
280 280 if (!this.ui_controls_list.length || (this.cell.cell_type != 'code' && this.cell.rendered)) {
281 281 this.hide();
282 282 } else {
283 283 this.show();
284 284 }
285 285 };
286 286
287 287
288 288 /**
289 289 */
290 290 CellToolbar.utils = {};
291 291
292 292
293 293 /**
294 294 * A utility function to generate bindings between a checkbox and cell/metadata
295 295 * @method utils.checkbox_ui_generator
296 296 * @static
297 297 *
298 298 * @param name {string} Label in front of the checkbox
299 299 * @param setter {function( cell, newValue )}
300 300 * A setter method to set the newValue
301 301 * @param getter {function( cell )}
302 302 * A getter methods which return the current value.
303 303 *
304 304 * @return callback {function( div, cell )} Callback to be passed to `register_callback`
305 305 *
306 306 * @example
307 307 *
308 308 * An exmple that bind the subkey `slideshow.isSectionStart` to a checkbox with a `New Slide` label
309 309 *
310 310 * var newSlide = CellToolbar.utils.checkbox_ui_generator('New Slide',
311 311 * // setter
312 312 * function(cell, value){
313 313 * // we check that the slideshow namespace exist and create it if needed
314 314 * if (cell.metadata.slideshow == undefined){cell.metadata.slideshow = {}}
315 315 * // set the value
316 316 * cell.metadata.slideshow.isSectionStart = value
317 317 * },
318 318 * //geter
319 319 * function(cell){ var ns = cell.metadata.slideshow;
320 320 * // if the slideshow namespace does not exist return `undefined`
321 321 * // (will be interpreted as `false` by checkbox) otherwise
322 322 * // return the value
323 323 * return (ns == undefined)? undefined: ns.isSectionStart
324 324 * }
325 325 * );
326 326 *
327 327 * CellToolbar.register_callback('newSlide', newSlide);
328 328 *
329 329 */
330 330 CellToolbar.utils.checkbox_ui_generator = function(name, setter, getter){
331 331 return function(div, cell, celltoolbar) {
332 332 var button_container = $(div);
333 333
334 334 var chkb = $('<input/>').attr('type', 'checkbox');
335 335 var lbl = $('<label/>').append($('<span/>').text(name));
336 336 lbl.append(chkb);
337 337 chkb.attr("checked", getter(cell));
338 338
339 339 chkb.click(function(){
340 340 var v = getter(cell);
341 341 setter(cell, !v);
342 342 chkb.attr("checked", !v);
343 343 });
344 344 button_container.append($('<span/>').append(lbl));
345 345 };
346 346 };
347 347
348 348
349 349 /**
350 350 * A utility function to generate bindings between a dropdown list cell
351 351 * @method utils.select_ui_generator
352 352 * @static
353 353 *
354 354 * @param list_list {list of sublist} List of sublist of metadata value and name in the dropdown list.
355 355 * subslit shoud contain 2 element each, first a string that woul be displayed in the dropdown list,
356 356 * and second the corresponding value to be passed to setter/return by getter. the corresponding value
357 357 * should not be "undefined" or behavior can be unexpected.
358 358 * @param setter {function( cell, newValue )}
359 359 * A setter method to set the newValue
360 360 * @param getter {function( cell )}
361 361 * A getter methods which return the current value of the metadata.
362 362 * @param [label=""] {String} optionnal label for the dropdown menu
363 363 *
364 364 * @return callback {function( div, cell )} Callback to be passed to `register_callback`
365 365 *
366 366 * @example
367 367 *
368 368 * var select_type = CellToolbar.utils.select_ui_generator([
369 369 * ["<None>" , "None" ],
370 370 * ["Header Slide" , "header_slide" ],
371 371 * ["Slide" , "slide" ],
372 372 * ["Fragment" , "fragment" ],
373 373 * ["Skip" , "skip" ],
374 374 * ],
375 375 * // setter
376 376 * function(cell, value){
377 377 * // we check that the slideshow namespace exist and create it if needed
378 378 * if (cell.metadata.slideshow == undefined){cell.metadata.slideshow = {}}
379 379 * // set the value
380 380 * cell.metadata.slideshow.slide_type = value
381 381 * },
382 382 * //geter
383 383 * function(cell){ var ns = cell.metadata.slideshow;
384 384 * // if the slideshow namespace does not exist return `undefined`
385 385 * // (will be interpreted as `false` by checkbox) otherwise
386 386 * // return the value
387 387 * return (ns == undefined)? undefined: ns.slide_type
388 388 * }
389 389 * CellToolbar.register_callback('slideshow.select', select_type);
390 390 *
391 391 */
392 392 CellToolbar.utils.select_ui_generator = function(list_list, setter, getter, label) {
393 393 label = label || "";
394 394 return function(div, cell, celltoolbar) {
395 395 var button_container = $(div);
396 396 var lbl = $("<label/>").append($('<span/>').text(label));
397 397 var select = $('<select/>').addClass('ui-widget ui-widget-content');
398 398 for(var i=0; i < list_list.length; i++){
399 399 var opt = $('<option/>')
400 400 .attr('value', list_list[i][1])
401 401 .text(list_list[i][0]);
402 402 select.append(opt);
403 403 }
404 404 select.val(getter(cell));
405 405 select.change(function(){
406 406 setter(cell, select.val());
407 407 });
408 408 button_container.append($('<span/>').append(lbl).append(select));
409 409 };
410 410 };
411 411
412 412 // Backwards compatability.
413 413 IPython.CellToolbar = CellToolbar;
414 414
415 415 return {'CellToolbar': CellToolbar};
416 416 });
General Comments 0
You need to be logged in to leave comments. Login now