##// END OF EJS Templates
change set_preset to activate_preset...
Matthias BUSSONNIER -
Show More
@@ -1,349 +1,358
1 //----------------------------------------------------------------------------
1 //----------------------------------------------------------------------------
2 // Copyright (C) 2012 The IPython Development Team
2 // Copyright (C) 2012 The IPython Development Team
3 //
3 //
4 // Distributed under the terms of the BSD License. The full license is in
4 // Distributed under the terms of the BSD License. The full license is in
5 // the file COPYING, distributed as part of this software.
5 // the file COPYING, distributed as part of this software.
6 //----------------------------------------------------------------------------
6 //----------------------------------------------------------------------------
7
7
8 //============================================================================
8 //============================================================================
9 // CellToolbar
9 // CellToolbar
10 //============================================================================
10 //============================================================================
11
11
12
12
13 /**
13 /**
14 * A Module to control the per-cell toolbar.
14 * A Module to control the per-cell toolbar.
15 * @module IPython
15 * @module IPython
16 * @namespace IPython
16 * @namespace IPython
17 * @submodule CellToolbar
17 * @submodule CellToolbar
18 */
18 */
19 var IPython = (function (IPython) {
19 var IPython = (function (IPython) {
20 "use strict";
20 "use strict";
21
21
22
22
23 /**
23 /**
24 * @constructor
24 * @constructor
25 * @class CellToolbar
25 * @class CellToolbar
26 * @param {The cell to attach the metadata UI to} cell
26 * @param {The cell to attach the metadata UI to} cell
27 */
27 */
28 var CellToolbar = function (cell) {
28 var CellToolbar = function (cell) {
29 CellToolbar._instances.push(this);
29 CellToolbar._instances.push(this);
30 this.inner_element = $('<div/>');
30 this.inner_element = $('<div/>');
31 this.cell = cell;
31 this.cell = cell;
32 this.element = $('<div/>').addClass('celltoolbar')
32 this.element = $('<div/>').addClass('celltoolbar')
33 .append(this.inner_element)
33 .append(this.inner_element)
34 this.rebuild();
34 this.rebuild();
35 return this;
35 return this;
36 };
36 };
37
37
38 CellToolbar.dropdown_preset_element = $('<select/>')
38 CellToolbar.dropdown_preset_element = $('<select/>')
39 .addClass('ui-widget ui-widget-content')
39 .addClass('ui-widget ui-widget-content')
40 .attr('id', 'celltoolbar_selector')
40 .attr('id', 'celltoolbar_selector')
41 .append($('<option/>').attr('value', '').text('None'))
41 .append($('<option/>').attr('value', '').text('None'))
42
42
43 CellToolbar.dropdown_preset_element.change(function(){
43 CellToolbar.dropdown_preset_element.change(function(){
44 var val = CellToolbar.dropdown_preset_element.val()
44 var val = CellToolbar.dropdown_preset_element.val()
45 if(val ==''){
45 if(val ==''){
46 $('body').removeClass('celltoolbar-on')
46 $('body').removeClass('celltoolbar-on')
47 } else {
47 } else {
48 $('body').addClass('celltoolbar-on')
48 $('body').addClass('celltoolbar-on')
49 CellToolbar.set_preset(val)
49 CellToolbar.activate_preset(val)
50 }
50 }
51 })
51 })
52
52
53
53
54
54
55 /**
55 /**
56 * Class variable that should contain a dict of all availlable callback
56 * Class variable that should contain a dict of all availlable callback
57 * we need to think of wether or not we allow nested namespace
57 * we need to think of wether or not we allow nested namespace
58 * @property _callback_dict
58 * @property _callback_dict
59 * @private
59 * @private
60 * @static
61 * @type Dict
60 */
62 */
61 CellToolbar._callback_dict = {};
63 CellToolbar._callback_dict = {};
62
64
63 /**
65 /**
64 * Class variable that should contain the reverse order list of the button
66 * Class variable that should contain the reverse order list of the button
65 * to add to the toolbar of each cell
67 * to add to the toolbar of each cell
66 * @property _ui_controls_list
68 * @property _ui_controls_list
67 * @private
69 * @private
70 * @static
71 * @type List
68 */
72 */
69 CellToolbar._ui_controls_list = [];
73 CellToolbar._ui_controls_list = [];
70
74
71 /**
75 /**
72 * keep a list of all instances to
76 * Class variable that should contains the CellToolbar instances for each
73 * be able to llop over them...
77 * cell of the notebook
74 * but how to 'destroy' them ?
78 *
75 * have to think about it...
76 * or loop over the cells, and find their CellToolbar instances.
77 * @private
79 * @private
78 * @property _instances
80 * @property _instances
81 * @static
82 * @type List
79 */
83 */
80 CellToolbar._instances =[]
84 CellToolbar._instances =[]
81
85
82 /**
86 /**
83 * keep a list of all the availlabel presets for the toolbar
87 * keep a list of all the availlabel presets for the toolbar
84 * @private
88 * @private
85 * @property _presets
89 * @property _presets
90 * @static
91 * @type Dict
86 */
92 */
87 CellToolbar._presets ={}
93 CellToolbar._presets ={}
88
94
89 // this is by design not a prototype.
95 // this is by design not a prototype.
90 /**
96 /**
91 * Register a callback to create an UI element in a cell toolbar.
97 * Register a callback to create an UI element in a cell toolbar.
92 * @method register_callback
98 * @method register_callback
93 * @param name {String} name to use to refer to the callback. It is advised to use a prefix with the name
99 * @param name {String} name to use to refer to the callback. It is advised to use a prefix with the name
94 * for easier sorting and avoid collision
100 * for easier sorting and avoid collision
95 * @param callback {function(div, cell)} callback that will be called to generate the ui element
101 * @param callback {function(div, cell)} callback that will be called to generate the ui element
96 *
102 *
97 *
103 *
98 * The callback will receive the following element :
104 * The callback will receive the following element :
99 *
105 *
100 * * a div in which to add element.
106 * * a div in which to add element.
101 * * the cell it is responsable from
107 * * the cell it is responsible from
102 *
108 *
103 * @example
109 * @example
104 *
110 *
105 * Example that create callback for a button that toggle between `true` and `false` label,
111 * Example that create callback for a button that toggle between `true` and `false` label,
106 * with the metadata under the key 'foo' to reflect the status of the button.
112 * with the metadata under the key 'foo' to reflect the status of the button.
107 *
113 *
108 * // first param reference to a DOM div
114 * // first param reference to a DOM div
109 * // second param reference to the cell.
115 * // second param reference to the cell.
110 * var toggle = function(div, cell) {
116 * var toggle = function(div, cell) {
111 * var button_container = $(div)
117 * var button_container = $(div)
112 *
118 *
113 * // let's create a button that show the current value of the metadata
119 * // let's create a button that show the current value of the metadata
114 * var button = $('<div/>').button({label:String(cell.metadata.foo)});
120 * var button = $('<div/>').button({label:String(cell.metadata.foo)});
115 *
121 *
116 * // On click, change the metadata value and update the button label
122 * // On click, change the metadata value and update the button label
117 * button.click(function(){
123 * button.click(function(){
118 * var v = cell.metadata.foo;
124 * var v = cell.metadata.foo;
119 * cell.metadata.foo = !v;
125 * cell.metadata.foo = !v;
120 * button.button("option", "label", String(!v));
126 * button.button("option", "label", String(!v));
121 * })
127 * })
122 *
128 *
123 * // add the button to the DOM div.
129 * // add the button to the DOM div.
124 * button_container.append(button);
130 * button_container.append(button);
125 * }
131 * }
126 *
132 *
127 * // now we register the callback under the name `foo` to give the
133 * // now we register the callback under the name `foo` to give the
128 * // user the ability to use it later
134 * // user the ability to use it later
129 * CellToolbar.register_callback('foo', toggle);
135 * CellToolbar.register_callback('foo', toggle);
130 */
136 */
131 CellToolbar.register_callback = function(name, callback){
137 CellToolbar.register_callback = function(name, callback){
132 // what do we do if name already exist ?
138 // Overwrite if it already exists.
133 CellToolbar._callback_dict[name] = callback;
139 CellToolbar._callback_dict[name] = callback;
134 };
140 };
135
141
136 /**
142 /**
137 * Register a preset of UI element in a cell toolbar.
143 * Register a preset of UI element in a cell toolbar.
138 * Not supported Yet.
144 * Not supported Yet.
139 * @method register_preset
145 * @method register_preset
140 * @param name {String} name to use to refer to the preset. It is advised to use a prefix with the name
146 * @param name {String} name to use to refer to the preset. It is advised to use a prefix with the name
141 * for easier sorting and avoid collision
147 * for easier sorting and avoid collision
142 * @param preset_list {List of String} reverse order of the button in the toolbar. Each String of the list
148 * @param preset_list {List of String} reverse order of the button in the toolbar. Each String of the list
143 * should correspond to a name of a registerd callback.
149 * should correspond to a name of a registerd callback.
144 *
150 *
145 * @private
151 * @private
146 * @example
152 * @example
147 *
153 *
148 * CellToolbar.register_callback('foo.c1', function(div, cell){...});
154 * CellToolbar.register_callback('foo.c1', function(div, cell){...});
149 * CellToolbar.register_callback('foo.c2', function(div, cell){...});
155 * CellToolbar.register_callback('foo.c2', function(div, cell){...});
150 * CellToolbar.register_callback('foo.c3', function(div, cell){...});
156 * CellToolbar.register_callback('foo.c3', function(div, cell){...});
151 * CellToolbar.register_callback('foo.c4', function(div, cell){...});
157 * CellToolbar.register_callback('foo.c4', function(div, cell){...});
152 * CellToolbar.register_callback('foo.c5', function(div, cell){...});
158 * CellToolbar.register_callback('foo.c5', function(div, cell){...});
153 *
159 *
154 * CellToolbar.register_preset('foo.foo_preset1', ['foo.c1', 'foo.c2', 'foo.c5'])
160 * CellToolbar.register_preset('foo.foo_preset1', ['foo.c1', 'foo.c2', 'foo.c5'])
155 * CellToolbar.register_preset('foo.foo_preset2', ['foo.c4', 'foo.c5'])
161 * CellToolbar.register_preset('foo.foo_preset2', ['foo.c4', 'foo.c5'])
156 */
162 */
157 CellToolbar.register_preset = function(name, preset_list){
163 CellToolbar.register_preset = function(name, preset_list){
158 CellToolbar._presets[name] = preset_list
164 CellToolbar._presets[name] = preset_list
159 CellToolbar.dropdown_preset_element.append(
165 CellToolbar.dropdown_preset_element.append(
160 $('<option/>').attr('value', name).text(name)
166 $('<option/>').attr('value', name).text(name)
161 )
167 )
162 }
168 }
163 /**
169 /**
164 * set an UI preset from `register_preset`
170 * Activate an UI preset from `register_preset`
165 * @method set_preset
171 *
172 * This does not update the selection UI.
173 *
174 * @method activate_preset
166 * @param preset_name {String} string corresponding to the preset name
175 * @param preset_name {String} string corresponding to the preset name
167 *
176 *
168 * @static
177 * @static
169 * @private
178 * @private
170 * @example
179 * @example
171 *
180 *
172 * CellToolbar.set_preset('foo.foo_preset1');
181 * CellToolbar.activate_preset('foo.foo_preset1');
173 */
182 */
174 CellToolbar.set_preset= function(preset_name){
183 CellToolbar.activate_preset= function(preset_name){
175 var preset = CellToolbar._presets[preset_name];
184 var preset = CellToolbar._presets[preset_name];
176
185
177 if(preset != undefined){
186 if(preset != undefined){
178 CellToolbar._ui_controls_list = preset;
187 CellToolbar._ui_controls_list = preset;
179 CellToolbar.rebuild_all();
188 CellToolbar.rebuild_all();
180 }
189 }
181 }
190 }
182
191
183
192
184 // this is by design not a prototype.
193 // this is by design not a prototype.
185 /**
194 /**
186 * This should be called on the class and not on a instance as it will trigger
195 * This should be called on the class and not on a instance as it will trigger
187 * rebuild of all the instances.
196 * rebuild of all the instances.
188 * @method rebuild_all
197 * @method rebuild_all
189 * @static
198 * @static
190 *
199 *
191 */
200 */
192 CellToolbar.rebuild_all = function(){
201 CellToolbar.rebuild_all = function(){
193 for(var i in CellToolbar._instances){
202 for(var i in CellToolbar._instances){
194 CellToolbar._instances[i].rebuild();
203 CellToolbar._instances[i].rebuild();
195 }
204 }
196 }
205 }
197
206
198 /**
207 /**
199 * Rebuild all the button on the toolbar to update it's state.
208 * Rebuild all the button on the toolbar to update it's state.
200 * @method rebuild
209 * @method rebuild
201 */
210 */
202 CellToolbar.prototype.rebuild = function(){
211 CellToolbar.prototype.rebuild = function(){
203 // strip evrything from the div
212 // strip evrything from the div
204 // which is probabli metainner.
213 // which is probabli metainner.
205 // or this.element.
214 // or this.element.
206 this.inner_element.empty();
215 this.inner_element.empty();
207
216
208 var cdict = CellToolbar._callback_dict;
217 var cdict = CellToolbar._callback_dict;
209 var preset = CellToolbar._ui_controls_list;
218 var preset = CellToolbar._ui_controls_list;
210 // Yes we iterate on the class varaible, not the instance one.
219 // Yes we iterate on the class varaible, not the instance one.
211 for ( var index in CellToolbar._ui_controls_list){
220 for ( var index in CellToolbar._ui_controls_list){
212 var local_div = $('<div/>').addClass('button_container');
221 var local_div = $('<div/>').addClass('button_container');
213 // Note,
222 // Note,
214 // do this the other way, wrap in try/catch and don't append if any errors.
223 // do this the other way, wrap in try/catch and don't append if any errors.
215 this.inner_element.append(local_div)
224 this.inner_element.append(local_div)
216 cdict[preset[index]](local_div, this.cell)
225 cdict[preset[index]](local_div, this.cell)
217 }
226 }
218
227
219 }
228 }
220
229
221
230
222 /**
231 /**
223 */
232 */
224 CellToolbar.utils = {};
233 CellToolbar.utils = {};
225
234
226 /**
235 /**
227 * A utility function to generate bindings between a checkbox and cell/metadata
236 * A utility function to generate bindings between a checkbox and cell/metadata
228 * @method utils.checkbox_ui_generator
237 * @method utils.checkbox_ui_generator
229 * @static
238 * @static
230 *
239 *
231 * @param name {string} Label in front of the checkbox
240 * @param name {string} Label in front of the checkbox
232 * @param setter {function( cell, newValue )}
241 * @param setter {function( cell, newValue )}
233 * A setter method to set the newValue
242 * A setter method to set the newValue
234 * @param getter {function( cell )}
243 * @param getter {function( cell )}
235 * A getter methods which return the current value.
244 * A getter methods which return the current value.
236 *
245 *
237 * @return callback {function( div, cell )} Callback to be passed to `register_callback`
246 * @return callback {function( div, cell )} Callback to be passed to `register_callback`
238 *
247 *
239 * @example
248 * @example
240 *
249 *
241 * An exmple that bind the subkey `slideshow.isSectionStart` to a checkbox with a `New Slide` label
250 * An exmple that bind the subkey `slideshow.isSectionStart` to a checkbox with a `New Slide` label
242 *
251 *
243 * var newSlide = CellToolbar.utils.checkbox_ui_generator('New Slide',
252 * var newSlide = CellToolbar.utils.checkbox_ui_generator('New Slide',
244 * // setter
253 * // setter
245 * function(cell, value){
254 * function(cell, value){
246 * // we check that the slideshow namespace exist and create it if needed
255 * // we check that the slideshow namespace exist and create it if needed
247 * if (cell.metadata.slideshow == undefined){cell.metadata.slideshow = {}}
256 * if (cell.metadata.slideshow == undefined){cell.metadata.slideshow = {}}
248 * // set the value
257 * // set the value
249 * cell.metadata.slideshow.isSectionStart = value
258 * cell.metadata.slideshow.isSectionStart = value
250 * },
259 * },
251 * //geter
260 * //geter
252 * function(cell){ var ns = cell.metadata.slideshow;
261 * function(cell){ var ns = cell.metadata.slideshow;
253 * // if the slideshow namespace does not exist return `undefined`
262 * // if the slideshow namespace does not exist return `undefined`
254 * // (will be interpreted as `false` by checkbox) otherwise
263 * // (will be interpreted as `false` by checkbox) otherwise
255 * // return the value
264 * // return the value
256 * return (ns == undefined)? undefined: ns.isSectionStart
265 * return (ns == undefined)? undefined: ns.isSectionStart
257 * }
266 * }
258 * );
267 * );
259 *
268 *
260 * CellToolbar.register_callback('newSlide', newSlide);
269 * CellToolbar.register_callback('newSlide', newSlide);
261 *
270 *
262 */
271 */
263 CellToolbar.utils.checkbox_ui_generator = function(name, setter, getter){
272 CellToolbar.utils.checkbox_ui_generator = function(name, setter, getter){
264 return function(div, cell) {
273 return function(div, cell) {
265 var button_container = $(div)
274 var button_container = $(div)
266
275
267 var chkb = $('<input/>').attr('type', 'checkbox');
276 var chkb = $('<input/>').attr('type', 'checkbox');
268 var lbl = $('<label/>').append($('<span/>').text(name).css('font-size', '77%'));
277 var lbl = $('<label/>').append($('<span/>').text(name).css('font-size', '77%'));
269 lbl.append(chkb);
278 lbl.append(chkb);
270 chkb.attr("checked", getter(cell));
279 chkb.attr("checked", getter(cell));
271
280
272 chkb.click(function(){
281 chkb.click(function(){
273 var v = getter(cell);
282 var v = getter(cell);
274 setter(cell, !v);
283 setter(cell, !v);
275 chkb.attr("checked", !v);
284 chkb.attr("checked", !v);
276 })
285 })
277 button_container.append($('<div/>').append(lbl));
286 button_container.append($('<div/>').append(lbl));
278
287
279 }
288 }
280 }
289 }
281
290
282 /**
291 /**
283 * A utility function to generate bindings between a dropdown list cell
292 * A utility function to generate bindings between a dropdown list cell
284 * @method utils.select_ui_generator
293 * @method utils.select_ui_generator
285 * @static
294 * @static
286 *
295 *
287 * @param list_list {list of sublist} List of sublist of metadata value and name in the dropdown list.
296 * @param list_list {list of sublist} List of sublist of metadata value and name in the dropdown list.
288 * subslit shoud contain 2 element each, first a string that woul be displayed in the dropdown list,
297 * subslit shoud contain 2 element each, first a string that woul be displayed in the dropdown list,
289 * and second the corresponding value to be passed to setter/return by getter.
298 * and second the corresponding value to be passed to setter/return by getter.
290 * @param setter {function( cell, newValue )}
299 * @param setter {function( cell, newValue )}
291 * A setter method to set the newValue
300 * A setter method to set the newValue
292 * @param getter {function( cell )}
301 * @param getter {function( cell )}
293 * A getter methods which return the current value of the metadata.
302 * A getter methods which return the current value of the metadata.
294 * @param [label=""] {String} optionnal label for the dropdown menu
303 * @param [label=""] {String} optionnal label for the dropdown menu
295 *
304 *
296 * @return callback {function( div, cell )} Callback to be passed to `register_callback`
305 * @return callback {function( div, cell )} Callback to be passed to `register_callback`
297 *
306 *
298 * @example
307 * @example
299 *
308 *
300 * var select_type = CellToolbar.utils.select_ui_generator([
309 * var select_type = CellToolbar.utils.select_ui_generator([
301 * ["<None>" , undefined ],
310 * ["<None>" , undefined ],
302 * ["Header Slide" , "header_slide" ],
311 * ["Header Slide" , "header_slide" ],
303 * ["Slide" , "slide" ],
312 * ["Slide" , "slide" ],
304 * ["Fragment" , "fragment" ],
313 * ["Fragment" , "fragment" ],
305 * ["Skip" , "skip" ],
314 * ["Skip" , "skip" ],
306 * ],
315 * ],
307 * // setter
316 * // setter
308 * function(cell, value){
317 * function(cell, value){
309 * // we check that the slideshow namespace exist and create it if needed
318 * // we check that the slideshow namespace exist and create it if needed
310 * if (cell.metadata.slideshow == undefined){cell.metadata.slideshow = {}}
319 * if (cell.metadata.slideshow == undefined){cell.metadata.slideshow = {}}
311 * // set the value
320 * // set the value
312 * cell.metadata.slideshow.slide_type = value
321 * cell.metadata.slideshow.slide_type = value
313 * },
322 * },
314 * //geter
323 * //geter
315 * function(cell){ var ns = cell.metadata.slideshow;
324 * function(cell){ var ns = cell.metadata.slideshow;
316 * // if the slideshow namespace does not exist return `undefined`
325 * // if the slideshow namespace does not exist return `undefined`
317 * // (will be interpreted as `false` by checkbox) otherwise
326 * // (will be interpreted as `false` by checkbox) otherwise
318 * // return the value
327 * // return the value
319 * return (ns == undefined)? undefined: ns.slide_type
328 * return (ns == undefined)? undefined: ns.slide_type
320 * }
329 * }
321 * CellToolbar.register_callback('slideshow.select', select_type);
330 * CellToolbar.register_callback('slideshow.select', select_type);
322 *
331 *
323 */
332 */
324 CellToolbar.utils.select_ui_generator = function(list_list, setter, getter, label){
333 CellToolbar.utils.select_ui_generator = function(list_list, setter, getter, label){
325 label= label? label: "";
334 label= label? label: "";
326 return function(div, cell) {
335 return function(div, cell) {
327 var button_container = $(div)
336 var button_container = $(div)
328 var lbl = $("<label/>").append($('<span/>').text(label).css('font-size', '77%'));
337 var lbl = $("<label/>").append($('<span/>').text(label).css('font-size', '77%'));
329 var select = $('<select/>');
338 var select = $('<select/>');
330 for(var itemn in list_list){
339 for(var itemn in list_list){
331 var opt = $('<option/>');
340 var opt = $('<option/>');
332 opt.attr('value', list_list[itemn][1])
341 opt.attr('value', list_list[itemn][1])
333 opt.text(list_list[itemn][0])
342 opt.text(list_list[itemn][0])
334 select.append(opt);
343 select.append(opt);
335 }
344 }
336 select.val(getter(cell));
345 select.val(getter(cell));
337 select.change(function(){
346 select.change(function(){
338 setter(cell, select.val());
347 setter(cell, select.val());
339 });
348 });
340 button_container.append($('<div/>').append(lbl).append(select));
349 button_container.append($('<div/>').append(lbl).append(select));
341
350
342 }
351 }
343 };
352 };
344
353
345
354
346 IPython.CellToolbar = CellToolbar;
355 IPython.CellToolbar = CellToolbar;
347
356
348 return IPython;
357 return IPython;
349 }(IPython));
358 }(IPython));
General Comments 0
You need to be logged in to leave comments. Login now