##// END OF EJS Templates
Add a per cell toolbar....
Matthias BUSSONNIER -
Show More
@@ -0,0 +1,54 b''
1 /*Css for the metadata edit area*/
2
3 .metaedit{
4 border:thin solid #DDD;
5 margin-left:81px;
6 border-bottom:none;
7 background : #EEE;
8 border-top-right-radius: 3px;
9 border-top-left-radius: 3px;
10 display:none;
11 }
12
13 .code_cell .metaedit{
14 margin-left:81px;
15 }
16
17 .text_cell .metaedit{
18 margin-left:0px;
19 }
20
21 .editmetaon div.input_area , .editmetaon div.text_cell_input{
22 border-top-right-radius: 0px;
23 border-top-left-radius: 0px;
24 }
25
26 .editmetaon .metaedit {
27 display:block;
28 }
29
30 .metaedit ui-button {
31 border :none;
32 }
33
34 .button_container {
35 float:right;
36 /*width:60px;*/
37 }
38
39 .button_container .ui-state-default, .button_container .ui-state-hover, .button_container .ui-state-hover span{
40 border-radius : 0 0 0 0;
41 border : none;
42 }
43
44 .metaedit select {
45 margin:10px;
46 margin-top:0px;
47 margin-bottom:0px;
48 }
49
50 .metaedit input[type=checkbox] {
51 margin-bottom:1px;
52
53 }
54
@@ -0,0 +1,359 b''
1 //----------------------------------------------------------------------------
2 // Copyright (C) 2012 The IPython Development Team
3 //
4 // Distributed under the terms of the BSD License. The full license is in
5 // the file COPYING, distributed as part of this software.
6 //----------------------------------------------------------------------------
7
8 //============================================================================
9 // MetaUI
10 //============================================================================
11
12
13 /**
14 * A Module to control the per-cell toolbar.
15 * @module IPython
16 * @namespace IPython
17 * @submodule MetaUI
18 */
19 var IPython = (function (IPython) {
20 "use strict";
21
22
23 /**
24 * @constructor
25 * @class MetaUI
26 * @param {The cell to attach the metadata UI to} cell
27 */
28 var MetaUI = function (cell) {
29 MetaUI._instances.push(this);
30 this.metainner = $('<div/>');
31 this.cell = cell;
32 this.element = $('<div/>').addClass('metaedit')
33 .append(this.metainner)
34 this.rebuild();
35 return this;
36 };
37
38 /**
39 * Class variable that should contain a dict of all availlable callback
40 * we need to think of wether or not we allow nested namespace
41 * @property _callback_dict
42 * @private
43 */
44 MetaUI._callback_dict = {};
45
46 /**
47 * Class variable that should contain the reverse order list of the button
48 * to add to the toolbar of each cell
49 * @property _button_list
50 * @private
51 */
52 MetaUI._button_list = [];
53
54 /**
55 * keep a list of all instances to
56 * be able to llop over them...
57 * but how to 'destroy' them ?
58 * have to think about it...
59 * or loop over the cells, and find their MetaUI instances.
60 * @private
61 * @property _instances
62 */
63 MetaUI._instances =[]
64
65 /**
66 * keep a list of all the availlabel presets for the toolbar
67 * @private
68 * @property _presets
69 */
70 MetaUI._presets ={}
71
72 // this is by design not a prototype.
73 /**
74 * Register a callback to create an UI element in a cell toolbar.
75 * @method register_callback
76 * @param name {String} name to use to refer to the callback. It is advised to use a prefix with the name
77 * for easier sorting and avoid collision
78 * @param callback {function(div, cell)} callback that will be called to generate the ui element
79 *
80 *
81 * The callback will receive the following element :
82 *
83 * * a div in which to add element.
84 * * the cell it is responsable from
85 *
86 * @example
87 *
88 * Example that create callback for a button that toggle between `true` and `false` label,
89 * with the metadata under the key 'foo' to reflect the status of the button.
90 *
91 * // first param reference to a DOM div
92 * // second param reference to the cell.
93 * var toggle = function(div, cell) {
94 * var button_container = $(div)
95 *
96 * // let's create a button that show the current value of the metadata
97 * var button = $('<div/>').button({label:String(cell.metadata.foo)});
98 *
99 * // On click, change the metadata value and update the button label
100 * button.click(function(){
101 * var v = cell.metadata.foo;
102 * cell.metadata.foo = !v;
103 * button.button("option","label",String(!v));
104 * })
105 *
106 * // add the button to the DOM div.
107 * button_container.append(button);
108 * }
109 *
110 * // now we register the callback under the name `foo` to give the
111 * // user the ability to use it later
112 * MetaUI.register_callback('foo',toggle);
113 */
114 MetaUI.register_callback = function(name, callback){
115 // what do we do if name already exist ?
116 MetaUI._callback_dict[name] = callback;
117 };
118
119 /**
120 * Register a preset of UI element in a cell toolbar.
121 * Not supported Yet.
122 * @method register_preset
123 * @param name {String} name to use to refer to the preset. It is advised to use a prefix with the name
124 * for easier sorting and avoid collision
125 * @param preset_list {List of String} reverse order of the button in the toolbar. Each String of the list
126 * should correspond to a name of a registerd callback.
127 *
128 * @private
129 * @example
130 *
131 * MetaUI.register_callback('foo.c1',function(div,cell){...});
132 * MetaUI.register_callback('foo.c2',function(div,cell){...});
133 * MetaUI.register_callback('foo.c3',function(div,cell){...});
134 * MetaUI.register_callback('foo.c4',function(div,cell){...});
135 * MetaUI.register_callback('foo.c5',function(div,cell){...});
136 *
137 * MetaUI.register_preset('foo.foo_preset1',['foo.c1','foo.c2','foo.c5'])
138 * MetaUI.register_preset('foo.foo_preset2',['foo.c4','foo.c5'])
139 */
140 MetaUI.register_preset = function(name, preset_list){
141 MetaUI._presets[name] = preset_list
142 }
143 /**
144 * set an UI preset from `register_preset`
145 * @method set_preset
146 * @param preset_name {String} string corresponding to the preset name
147 *
148 * @static
149 * @private
150 * @example
151 *
152 * MetaUI.set_preset('foo.foo_preset1');
153 */
154 MetaUI.set_preset= function(preset_name){
155 var preset = MetaUI._presets[preset_name];
156
157 if(preset != undefined){
158 MetaUI._button_list = preset;
159 MetaUI.rebuild_all();
160 }
161 }
162
163 // this is by design not a prototype.
164 /**
165 * This should be called on the class and not on a instance as it will trigger
166 * rebuild of all the instances.
167 * @method rebuild_all
168 * @static
169 *
170 */
171 MetaUI.rebuild_all = function(){
172 for(var i in MetaUI._instances){
173 MetaUI._instances[i].rebuild();
174 }
175 }
176
177 /**
178 * Rebuild all the button on the toolbar to update it's state.
179 * @method rebuild
180 */
181 MetaUI.prototype.rebuild = function(){
182 // strip evrything from the div
183 // which is probabli metainner.
184 // or this.element.
185 this.metainner.empty();
186 //this.add_raw_edit_button()
187
188
189 var cdict = MetaUI._callback_dict;
190 var preset = MetaUI._button_list;
191 // Yes we iterate on the class varaible, not the instance one.
192 for ( var index in MetaUI._button_list){
193 var local_div = $('<div/>').addClass('button_container');
194 this.metainner.append(local_div)
195 cdict[preset[index]](local_div,this.cell)
196 }
197
198 }
199
200 var raw_edit = function(cell){
201
202 var md = cell.metadata
203
204 var textarea = $('<textarea/>')
205 .attr('rows','13')
206 .attr('cols','75')
207 .attr('name','metadata')
208 .text(JSON.stringify(md, null,4)||'');
209 var dialogform = $('<div/>').attr('title','Edit the metadata')
210 .append(
211 $('<form/>').append(
212 $('<fieldset/>').append(
213 $('<label/>')
214 .attr('for','metadata')
215 .text("Metadata (I know what I'm dooing and I won't complain if it breaks my notebook)")
216 )
217 .append($('<br/>'))
218 .append(
219 textarea
220 )
221 )
222 );
223 var editor = CodeMirror.fromTextArea(textarea[0], {
224 lineNumbers: true,
225 matchBrackets: true,
226 });
227 $(dialogform).dialog({
228 autoOpen: true,
229 height: 300,
230 width: 650,
231 modal: true,
232 buttons: {
233 "Ok": function() {
234 //validate json and set it
235 try {
236 var json = JSON.parse(editor.getValue());
237 cell.metadata = json;
238 $( this ).dialog( "close" );
239 }
240 catch(e)
241 {
242 alert('invalid json');
243 }
244 },
245 Cancel: function() {
246 $( this ).dialog( "close" );
247 }
248 },
249 close: function() {
250 //cleanup on close
251 $(this).remove();
252 }
253 });
254 editor.refresh();
255 }
256
257 var add_raw_edit_button = function(div, cell) {
258 var button_container = $(div)
259 var button = $('<div/>').button({label:'Raw Edit'})
260 .click(function(){raw_edit(cell); return false;})
261 button_container.append(button);
262 }
263
264 MetaUI.register_callback('example.rawedit',add_raw_edit_button);
265 var example_preset = []
266 example_preset.push('example.rawedit');
267
268
269 var simple_button = function(div, cell) {
270 var button_container = $(div);
271 var button = $('<div/>').button({icons:{primary:'ui-icon-locked'}});
272 var fun = function(value){
273 try{
274 if(value){
275 cell.code_mirror.setOption('readOnly','nocursor')
276 button.button('option','icons',{primary:'ui-icon-locked'})
277 } else {
278 cell.code_mirror.setOption('readOnly','false')
279 button.button('option','icons',{primary:'ui-icon-unlocked'})
280 }
281 } catch(e){}
282
283 }
284 fun(cell.metadata.ro)
285 button.click(function(){
286 var v = cell.metadata.ro;
287 var locked = !v;
288 cell.metadata.ro = locked;
289 fun(locked)
290 })
291 .css('height','16px')
292 .css('width','35px');
293 button_container.append(button);
294 }
295
296 MetaUI.register_callback('example.lock',simple_button);
297 example_preset.push('example.lock');
298
299 var toggle_test = function(div, cell) {
300 var button_container = $(div)
301 var button = $('<div/>').button({label:String(cell.metadata.foo)});
302 button.click(function(){
303 var v = cell.metadata.foo;
304 cell.metadata.foo = !v;
305 button.button("option","label",String(!v));
306 })
307 button_container.append(button);
308 }
309
310 MetaUI.register_callback('example.toggle',toggle_test);
311 example_preset.push('example.toggle');
312
313 var checkbox_test = function(div, cell) {
314 var button_container = $(div)
315
316 var chkb = $('<input/>').attr('type','checkbox');
317 var lbl = $('<label/>').append($('<span/>').text('bar :').css('font-size','77%'));
318 lbl.append(chkb);
319 chkb.attr("checked",cell.metadata.bar);
320 chkb.click(function(){
321 var v = cell.metadata.bar;
322 cell.metadata.bar = !v;
323 chkb.attr("checked",!v);
324 })
325 button_container.append($('<div/>').append(lbl));
326
327 }
328
329 MetaUI.register_callback('example.checkbox',checkbox_test);
330 example_preset.push('example.checkbox');
331
332 var select_test = function(div, cell) {
333 var button_container = $(div)
334
335 var select = $('<select/>');
336
337 select.append($('<option/>').attr('value','foo').text('foo'));
338 select.append($('<option/>').attr('value','bar').text('bar'));
339 select.append($('<option/>').attr('value','qux').text('qux'));
340 select.append($('<option/>').attr('value','zip').text('zip'));
341 select.val(cell.metadata.option);
342 select.change(function(){
343 cell.metadata.option = select.val();
344 });
345 button_container.append($('<div/>').append(select));
346
347 }
348
349 MetaUI.register_callback('example.select',select_test);
350 example_preset.push('example.select');
351
352 MetaUI.register_preset('example',example_preset);
353 MetaUI.register_preset('foo',['example.select','example.select']);
354 MetaUI.set_preset('example');
355
356 IPython.MetaUI = MetaUI;
357
358 return IPython;
359 }(IPython));
@@ -29,6 +29,7 b' span#notebook_name {'
29 font-size: 146.5%;
29 font-size: 146.5%;
30 }
30 }
31
31
32
32 .ui-menubar-item .ui-button .ui-button-text {
33 .ui-menubar-item .ui-button .ui-button-text {
33 padding: 0.4em 1.0em;
34 padding: 0.4em 1.0em;
34 font-size: 100%;
35 font-size: 100%;
@@ -145,6 +146,7 b' div.ui-widget-content {'
145
146
146 .cell {
147 .cell {
147 border: 1px solid transparent;
148 border: 1px solid transparent;
149 position: relative;
148 }
150 }
149
151
150 div.cell {
152 div.cell {
@@ -163,6 +163,7 b' var IPython = (function (IPython) {'
163 if (data.metadata !== undefined) {
163 if (data.metadata !== undefined) {
164 this.metadata = data.metadata;
164 this.metadata = data.metadata;
165 }
165 }
166 this.metaui.rebuild();
166 };
167 };
167
168
168
169
@@ -58,7 +58,10 b' var IPython = (function (IPython) {'
58
58
59 /** @method create_element */
59 /** @method create_element */
60 CodeCell.prototype.create_element = function () {
60 CodeCell.prototype.create_element = function () {
61 this.metaui = new IPython.MetaUI(this);
62
61 var cell = $('<div></div>').addClass('cell border-box-sizing code_cell vbox');
63 var cell = $('<div></div>').addClass('cell border-box-sizing code_cell vbox');
64 cell.append(this.metaui.element);
62 cell.attr('tabindex','2');
65 cell.attr('tabindex','2');
63 var input = $('<div></div>').addClass('input hbox');
66 var input = $('<div></div>').addClass('input hbox');
64 input.append($('<div/>').addClass('prompt input_prompt'));
67 input.append($('<div/>').addClass('prompt input_prompt'));
@@ -116,6 +116,16 b' var IPython = (function (IPython) {'
116 }
116 }
117 ],'run_int');
117 ],'run_int');
118
118
119 this.add_buttons_group([
120 {
121 id : 'show_meta',
122 label : 'Show Per Cell Toolbar',
123 icon : 'ui-icon-image',
124 callback : function () {
125 $('body').toggleClass('editmetaon');
126 }
127 }
128 ],'meta_on');
119
129
120 };
130 };
121
131
@@ -42,7 +42,9 b' var IPython = (function (IPython) {'
42 * @private
42 * @private
43 */
43 */
44 TextCell.prototype.create_element = function () {
44 TextCell.prototype.create_element = function () {
45 var cell = $("<div>").addClass('cell text_cell border-box-sizing');
45 var cell = $("<div>").addClass('cell text_cell border-box-sizing vbox');
46 this.metaui = new IPython.MetaUI(this);
47 cell.append(this.metaui.element);
46 cell.attr('tabindex','2');
48 cell.attr('tabindex','2');
47 var input_area = $('<div/>').addClass('text_cell_input border-box-sizing');
49 var input_area = $('<div/>').addClass('text_cell_input border-box-sizing');
48 this.code_mirror = CodeMirror(input_area.get(0), {
50 this.code_mirror = CodeMirror(input_area.get(0), {
@@ -36,7 +36,7 b' var IPython = (function (IPython) {'
36 *
36 *
37 * @example
37 * @example
38 *
38 *
39 * IPython.toolbar.add_button_group([
39 * IPython.toolbar.add_buttons_group([
40 * {
40 * {
41 * label:'my button',
41 * label:'my button',
42 * icon:'ui-icon-disk',
42 * icon:'ui-icon-disk',
@@ -17,6 +17,7 b' window.mathjax_url = "{{mathjax_url}}";'
17 <link rel="stylesheet" href="{{ static_url("prettify/prettify.css") }}"/>
17 <link rel="stylesheet" href="{{ static_url("prettify/prettify.css") }}"/>
18
18
19 <link rel="stylesheet" href="{{ static_url("css/notebook.css") }}" type="text/css" />
19 <link rel="stylesheet" href="{{ static_url("css/notebook.css") }}" type="text/css" />
20 <link rel="stylesheet" href="{{ static_url("css/metaui.css") }}" type="text/css" />
20 <link rel="stylesheet" href="{{ static_url("css/tooltip.css") }}" type="text/css" />
21 <link rel="stylesheet" href="{{ static_url("css/tooltip.css") }}" type="text/css" />
21 <link rel="stylesheet" href="{{ static_url("css/renderedhtml.css") }}" type="text/css" />
22 <link rel="stylesheet" href="{{ static_url("css/renderedhtml.css") }}" type="text/css" />
22
23
@@ -203,6 +204,7 b' data-notebook-id={{notebook_id}}'
203 <script src="{{ static_url("js/mathjaxutils.js") }}" type="text/javascript" charset="utf-8"></script>
204 <script src="{{ static_url("js/mathjaxutils.js") }}" type="text/javascript" charset="utf-8"></script>
204 <script src="{{ static_url("js/outputarea.js") }}" type="text/javascript" charset="utf-8"></script>
205 <script src="{{ static_url("js/outputarea.js") }}" type="text/javascript" charset="utf-8"></script>
205 <script src="{{ static_url("js/cell.js") }}" type="text/javascript" charset="utf-8"></script>
206 <script src="{{ static_url("js/cell.js") }}" type="text/javascript" charset="utf-8"></script>
207 <script src="{{ static_url("js/metaui.js") }}" type="text/javascript" charset="utf-8"></script>
206 <script src="{{ static_url("js/codecell.js") }}" type="text/javascript" charset="utf-8"></script>
208 <script src="{{ static_url("js/codecell.js") }}" type="text/javascript" charset="utf-8"></script>
207 <script src="{{ static_url("js/completer.js") }}" type="text/javascript" charset="utf-8"></script>
209 <script src="{{ static_url("js/completer.js") }}" type="text/javascript" charset="utf-8"></script>
208 <script src="{{ static_url("js/textcell.js") }}" type="text/javascript" charset="utf-8"></script>
210 <script src="{{ static_url("js/textcell.js") }}" type="text/javascript" charset="utf-8"></script>
General Comments 0
You need to be logged in to leave comments. Login now