//---------------------------------------------------------------------------- // Copyright (C) 2012 The IPython Development Team // // Distributed under the terms of the BSD License. The full license is in // the file COPYING, distributed as part of this software. //---------------------------------------------------------------------------- //============================================================================ // CellToolbar //============================================================================ /** * A Module to control the per-cell toolbar. * @module IPython * @namespace IPython * @submodule CellToolbar */ var IPython = (function (IPython) { "use strict"; /** * @constructor * @class CellToolbar * @param {The cell to attach the metadata UI to} cell */ var CellToolbar = function (cell) { CellToolbar._instances.push(this); this.inner_element = $('<div/>'); this.cell = cell; this.element = $('<div/>').addClass('celltoolbar') .append(this.inner_element) this.rebuild(); return this; }; CellToolbar.dropdown_preset_element = $('<select/>') .attr('id','celltoolbar_selector') .append($('<option/>').attr('value','').text('-')) CellToolbar.dropdown_preset_element.change(function(){ var val = CellToolbar.dropdown_preset_element.val() if(val ==''){ $('body').removeClass('celltoolbar-on') } else { $('body').addClass('celltoolbar-on') CellToolbar.set_preset(val) } }) /** * Class variable that should contain a dict of all availlable callback * we need to think of wether or not we allow nested namespace * @property _callback_dict * @private */ CellToolbar._callback_dict = {}; /** * Class variable that should contain the reverse order list of the button * to add to the toolbar of each cell * @property _ui_controls_list * @private */ CellToolbar._ui_controls_list = []; /** * keep a list of all instances to * be able to llop over them... * but how to 'destroy' them ? * have to think about it... * or loop over the cells, and find their CellToolbar instances. * @private * @property _instances */ CellToolbar._instances =[] /** * keep a list of all the availlabel presets for the toolbar * @private * @property _presets */ CellToolbar._presets ={} // this is by design not a prototype. /** * Register a callback to create an UI element in a cell toolbar. * @method register_callback * @param name {String} name to use to refer to the callback. It is advised to use a prefix with the name * for easier sorting and avoid collision * @param callback {function(div, cell)} callback that will be called to generate the ui element * * * The callback will receive the following element : * * * a div in which to add element. * * the cell it is responsable from * * @example * * Example that create callback for a button that toggle between `true` and `false` label, * with the metadata under the key 'foo' to reflect the status of the button. * * // first param reference to a DOM div * // second param reference to the cell. * var toggle = function(div, cell) { * var button_container = $(div) * * // let's create a button that show the current value of the metadata * var button = $('<div/>').button({label:String(cell.metadata.foo)}); * * // On click, change the metadata value and update the button label * button.click(function(){ * var v = cell.metadata.foo; * cell.metadata.foo = !v; * button.button("option","label",String(!v)); * }) * * // add the button to the DOM div. * button_container.append(button); * } * * // now we register the callback under the name `foo` to give the * // user the ability to use it later * CellToolbar.register_callback('foo',toggle); */ CellToolbar.register_callback = function(name, callback){ // what do we do if name already exist ? CellToolbar._callback_dict[name] = callback; }; /** * Register a preset of UI element in a cell toolbar. * Not supported Yet. * @method register_preset * @param name {String} name to use to refer to the preset. It is advised to use a prefix with the name * for easier sorting and avoid collision * @param preset_list {List of String} reverse order of the button in the toolbar. Each String of the list * should correspond to a name of a registerd callback. * * @private * @example * * CellToolbar.register_callback('foo.c1',function(div,cell){...}); * CellToolbar.register_callback('foo.c2',function(div,cell){...}); * CellToolbar.register_callback('foo.c3',function(div,cell){...}); * CellToolbar.register_callback('foo.c4',function(div,cell){...}); * CellToolbar.register_callback('foo.c5',function(div,cell){...}); * * CellToolbar.register_preset('foo.foo_preset1',['foo.c1','foo.c2','foo.c5']) * CellToolbar.register_preset('foo.foo_preset2',['foo.c4','foo.c5']) */ CellToolbar.register_preset = function(name, preset_list){ CellToolbar._presets[name] = preset_list CellToolbar.dropdown_preset_element.append( $('<option/>').attr('value',name).text(name) ) } /** * set an UI preset from `register_preset` * @method set_preset * @param preset_name {String} string corresponding to the preset name * * @static * @private * @example * * CellToolbar.set_preset('foo.foo_preset1'); */ CellToolbar.set_preset= function(preset_name){ var preset = CellToolbar._presets[preset_name]; if(preset != undefined){ CellToolbar._ui_controls_list = preset; CellToolbar.rebuild_all(); } } // this is by design not a prototype. /** * This should be called on the class and not on a instance as it will trigger * rebuild of all the instances. * @method rebuild_all * @static * */ CellToolbar.rebuild_all = function(){ for(var i in CellToolbar._instances){ CellToolbar._instances[i].rebuild(); } } /** * Rebuild all the button on the toolbar to update it's state. * @method rebuild */ CellToolbar.prototype.rebuild = function(){ // strip evrything from the div // which is probabli metainner. // or this.element. this.inner_element.empty(); var cdict = CellToolbar._callback_dict; var preset = CellToolbar._ui_controls_list; // Yes we iterate on the class varaible, not the instance one. for ( var index in CellToolbar._ui_controls_list){ var local_div = $('<div/>').addClass('button_container'); // Note, // do this the other way, wrap in try/catch and don't append if any errors. this.inner_element.append(local_div) cdict[preset[index]](local_div,this.cell) } } /** */ CellToolbar.utils = {}; /** * A utility function to generate bindings between a checkbox and metadata * @method utils.checkbox_ui_generator * @static * * @param name {string} Label in front of the checkbox * @param setter {function( metadata_dict, newValue )} * A setter method to set the newValue of the metadata dictionnary * @param getter {function( metadata )} * A getter methods which return the current value of the metadata. * * @return callback {function( div, cell )} Callback to be passed to `register_callback` * * @example * * An exmple that bind the subkey `slideshow.isSectionStart` to a checkbox with a `New Slide` label * * var newSlide = CellToolbar.utils.checkbox_ui_generator('New Slide', * // setter * function(metadata,value){ * // we check that the slideshow namespace exist and create it if needed * if (metadata.slideshow == undefined){metadata.slideshow = {}} * // set the value * metadata.slideshow.isSectionStart = value * }, * //geter * function(metadata){ var ns = metadata.slideshow; * // if the slideshow namespace does not exist return `undefined` * // (will be interpreted as `false` by checkbox) otherwise * // return the value * return (ns == undefined)? undefined: ns.isSectionStart * } * ); * * CellToolbar.register_callback('newSlide', newSlide); * */ CellToolbar.utils.checkbox_ui_generator = function(name,setter,getter){ return function(div, cell) { var button_container = $(div) var chkb = $('<input/>').attr('type','checkbox'); var lbl = $('<label/>').append($('<span/>').text(name).css('font-size','77%')); lbl.append(chkb); chkb.attr("checked",getter(cell.metadata)); chkb.click(function(){ var v = getter(cell.metadata); setter(cell.metadata,!v); chkb.attr("checked",!v); }) button_container.append($('<div/>').append(lbl)); } } /** * A utility function to generate bindings between a dropdown list and metadata * @method utils.select_ui_generator * @static * * @param list_list {list of sublist} List of sublist of metadata value and name in the dropdown list. * subslit shoud contain 2 element each, first a string that woul be displayed in the dropdown list, * and second the corresponding value for the metadata to be passed to setter/return by getter. * @param setter {function( metadata_dict, newValue )} * A setter method to set the newValue of the metadata dictionnary * @param getter {function( metadata )} * A getter methods which return the current value of the metadata. * @param [label=""] {String} optionnal label for the dropdown menu * * @return callback {function( div, cell )} Callback to be passed to `register_callback` * * @example * * var select_type = CellToolbar.utils.select_ui_generator([ * ["-" ,undefined ], * ["Header Slide" ,"header_slide" ], * ["Slide" ,"slide" ], * ["Fragment" ,"fragment" ], * ["Skip" ,"skip" ], * ], * // setter * function(metadata,value){ * // we check that the slideshow namespace exist and create it if needed * if (metadata.slideshow == undefined){metadata.slideshow = {}} * // set the value * metadata.slideshow.slide_type = value * }, * //geter * function(metadata){ var ns = metadata.slideshow; * // if the slideshow namespace does not exist return `undefined` * // (will be interpreted as `false` by checkbox) otherwise * // return the value * return (ns == undefined)? undefined: ns.slide_type * } * CellToolbar.register_callback('slideshow.select',select_type); * */ CellToolbar.utils.select_ui_generator = function(list_list,setter, getter, label){ label= label? label: ""; return function(div, cell) { var button_container = $(div) var lbl = $("<label/>").append($('<span/>').text(label).css('font-size','77%')); var select = $('<select/>'); for(var itemn in list_list){ var opt = $('<option/>'); opt.attr('value',list_list[itemn][1]) opt.text(list_list[itemn][0]) select.append(opt); } select.val(getter(cell.metadata)); select.change(function(){ setter(cell.metadata,select.val()); }); button_container.append($('<div/>').append(lbl).append(select)); } }; IPython.CellToolbar = CellToolbar; return IPython; }(IPython));