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