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