Show More
@@ -1,127 +1,128 b'' | |||||
1 | //---------------------------------------------------------------------------- |
|
1 | //---------------------------------------------------------------------------- | |
2 | // Copyright (C) 2011 The IPython Development Team |
|
2 | // Copyright (C) 2011 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 | // On document ready |
|
9 | // On document ready | |
10 | //============================================================================ |
|
10 | //============================================================================ | |
11 | "use strict"; |
|
11 | "use strict"; | |
12 |
|
12 | |||
13 | // for the time beeing, we have to pass marked as a parameter here, |
|
13 | // for the time beeing, we have to pass marked as a parameter here, | |
14 | // as injecting require.js make marked not to put itself in the globals, |
|
14 | // as injecting require.js make marked not to put itself in the globals, | |
15 | // which make both this file fail at setting marked configuration, and textcell.js |
|
15 | // which make both this file fail at setting marked configuration, and textcell.js | |
16 | // which search marked into global. |
|
16 | // which search marked into global. | |
17 |
require(['components/marked/lib/marked' |
|
17 | require(['components/marked/lib/marked', | |
|
18 | 'notebook/js/widgets/basic_widgets'], | |||
18 |
|
19 | |||
19 | function (marked) { |
|
20 | function (marked) { | |
20 |
|
21 | |||
21 | window.marked = marked |
|
22 | window.marked = marked | |
22 |
|
23 | |||
23 | // monkey patch CM to be able to syntax highlight cell magics |
|
24 | // monkey patch CM to be able to syntax highlight cell magics | |
24 | // bug reported upstream, |
|
25 | // bug reported upstream, | |
25 | // see https://github.com/marijnh/CodeMirror2/issues/670 |
|
26 | // see https://github.com/marijnh/CodeMirror2/issues/670 | |
26 | if(CodeMirror.getMode(1,'text/plain').indent == undefined ){ |
|
27 | if(CodeMirror.getMode(1,'text/plain').indent == undefined ){ | |
27 | console.log('patching CM for undefined indent'); |
|
28 | console.log('patching CM for undefined indent'); | |
28 | CodeMirror.modes.null = function() { |
|
29 | CodeMirror.modes.null = function() { | |
29 | return {token: function(stream) {stream.skipToEnd();},indent : function(){return 0}} |
|
30 | return {token: function(stream) {stream.skipToEnd();},indent : function(){return 0}} | |
30 | } |
|
31 | } | |
31 | } |
|
32 | } | |
32 |
|
33 | |||
33 | CodeMirror.patchedGetMode = function(config, mode){ |
|
34 | CodeMirror.patchedGetMode = function(config, mode){ | |
34 | var cmmode = CodeMirror.getMode(config, mode); |
|
35 | var cmmode = CodeMirror.getMode(config, mode); | |
35 | if(cmmode.indent == null) |
|
36 | if(cmmode.indent == null) | |
36 | { |
|
37 | { | |
37 | console.log('patch mode "' , mode, '" on the fly'); |
|
38 | console.log('patch mode "' , mode, '" on the fly'); | |
38 | cmmode.indent = function(){return 0}; |
|
39 | cmmode.indent = function(){return 0}; | |
39 | } |
|
40 | } | |
40 | return cmmode; |
|
41 | return cmmode; | |
41 | } |
|
42 | } | |
42 | // end monkey patching CodeMirror |
|
43 | // end monkey patching CodeMirror | |
43 |
|
44 | |||
44 | IPython.mathjaxutils.init(); |
|
45 | IPython.mathjaxutils.init(); | |
45 |
|
46 | |||
46 | $('#ipython-main-app').addClass('border-box-sizing'); |
|
47 | $('#ipython-main-app').addClass('border-box-sizing'); | |
47 | $('div#notebook_panel').addClass('border-box-sizing'); |
|
48 | $('div#notebook_panel').addClass('border-box-sizing'); | |
48 |
|
49 | |||
49 | var baseProjectUrl = $('body').data('baseProjectUrl'); |
|
50 | var baseProjectUrl = $('body').data('baseProjectUrl'); | |
50 | var notebookPath = $('body').data('notebookPath'); |
|
51 | var notebookPath = $('body').data('notebookPath'); | |
51 | var notebookName = $('body').data('notebookName'); |
|
52 | var notebookName = $('body').data('notebookName'); | |
52 | notebookName = decodeURIComponent(notebookName); |
|
53 | notebookName = decodeURIComponent(notebookName); | |
53 | notebookPath = decodeURIComponent(notebookPath); |
|
54 | notebookPath = decodeURIComponent(notebookPath); | |
54 | console.log(notebookName); |
|
55 | console.log(notebookName); | |
55 | if (notebookPath == 'None'){ |
|
56 | if (notebookPath == 'None'){ | |
56 | notebookPath = ""; |
|
57 | notebookPath = ""; | |
57 | } |
|
58 | } | |
58 |
|
59 | |||
59 | IPython.page = new IPython.Page(); |
|
60 | IPython.page = new IPython.Page(); | |
60 | IPython.layout_manager = new IPython.LayoutManager(); |
|
61 | IPython.layout_manager = new IPython.LayoutManager(); | |
61 | IPython.pager = new IPython.Pager('div#pager', 'div#pager_splitter'); |
|
62 | IPython.pager = new IPython.Pager('div#pager', 'div#pager_splitter'); | |
62 | IPython.quick_help = new IPython.QuickHelp(); |
|
63 | IPython.quick_help = new IPython.QuickHelp(); | |
63 | IPython.login_widget = new IPython.LoginWidget('span#login_widget',{baseProjectUrl:baseProjectUrl}); |
|
64 | IPython.login_widget = new IPython.LoginWidget('span#login_widget',{baseProjectUrl:baseProjectUrl}); | |
64 | IPython.notebook = new IPython.Notebook('div#notebook',{baseProjectUrl:baseProjectUrl, notebookPath:notebookPath, notebookName:notebookName}); |
|
65 | IPython.notebook = new IPython.Notebook('div#notebook',{baseProjectUrl:baseProjectUrl, notebookPath:notebookPath, notebookName:notebookName}); | |
65 | IPython.keyboard_manager = new IPython.KeyboardManager(); |
|
66 | IPython.keyboard_manager = new IPython.KeyboardManager(); | |
66 | IPython.save_widget = new IPython.SaveWidget('span#save_widget'); |
|
67 | IPython.save_widget = new IPython.SaveWidget('span#save_widget'); | |
67 | IPython.menubar = new IPython.MenuBar('#menubar',{baseProjectUrl:baseProjectUrl, notebookPath: notebookPath}) |
|
68 | IPython.menubar = new IPython.MenuBar('#menubar',{baseProjectUrl:baseProjectUrl, notebookPath: notebookPath}) | |
68 | IPython.toolbar = new IPython.MainToolBar('#maintoolbar-container') |
|
69 | IPython.toolbar = new IPython.MainToolBar('#maintoolbar-container') | |
69 | IPython.tooltip = new IPython.Tooltip() |
|
70 | IPython.tooltip = new IPython.Tooltip() | |
70 | IPython.notification_area = new IPython.NotificationArea('#notification_area') |
|
71 | IPython.notification_area = new IPython.NotificationArea('#notification_area') | |
71 | IPython.notification_area.init_notification_widgets(); |
|
72 | IPython.notification_area.init_notification_widgets(); | |
72 |
|
73 | |||
73 | IPython.layout_manager.do_resize(); |
|
74 | IPython.layout_manager.do_resize(); | |
74 |
|
75 | |||
75 | $('body').append('<div id="fonttest"><pre><span id="test1">x</span>'+ |
|
76 | $('body').append('<div id="fonttest"><pre><span id="test1">x</span>'+ | |
76 | '<span id="test2" style="font-weight: bold;">x</span>'+ |
|
77 | '<span id="test2" style="font-weight: bold;">x</span>'+ | |
77 | '<span id="test3" style="font-style: italic;">x</span></pre></div>') |
|
78 | '<span id="test3" style="font-style: italic;">x</span></pre></div>') | |
78 | var nh = $('#test1').innerHeight(); |
|
79 | var nh = $('#test1').innerHeight(); | |
79 | var bh = $('#test2').innerHeight(); |
|
80 | var bh = $('#test2').innerHeight(); | |
80 | var ih = $('#test3').innerHeight(); |
|
81 | var ih = $('#test3').innerHeight(); | |
81 | if(nh != bh || nh != ih) { |
|
82 | if(nh != bh || nh != ih) { | |
82 | $('head').append('<style>.CodeMirror span { vertical-align: bottom; }</style>'); |
|
83 | $('head').append('<style>.CodeMirror span { vertical-align: bottom; }</style>'); | |
83 | } |
|
84 | } | |
84 | $('#fonttest').remove(); |
|
85 | $('#fonttest').remove(); | |
85 |
|
86 | |||
86 | IPython.page.show(); |
|
87 | IPython.page.show(); | |
87 |
|
88 | |||
88 | IPython.layout_manager.do_resize(); |
|
89 | IPython.layout_manager.do_resize(); | |
89 | var first_load = function () { |
|
90 | var first_load = function () { | |
90 | IPython.layout_manager.do_resize(); |
|
91 | IPython.layout_manager.do_resize(); | |
91 | var hash = document.location.hash; |
|
92 | var hash = document.location.hash; | |
92 | if (hash) { |
|
93 | if (hash) { | |
93 | document.location.hash = ''; |
|
94 | document.location.hash = ''; | |
94 | document.location.hash = hash; |
|
95 | document.location.hash = hash; | |
95 | } |
|
96 | } | |
96 | IPython.notebook.set_autosave_interval(IPython.notebook.minimum_autosave_interval); |
|
97 | IPython.notebook.set_autosave_interval(IPython.notebook.minimum_autosave_interval); | |
97 | // only do this once |
|
98 | // only do this once | |
98 | $([IPython.events]).off('notebook_loaded.Notebook', first_load); |
|
99 | $([IPython.events]).off('notebook_loaded.Notebook', first_load); | |
99 | }; |
|
100 | }; | |
100 |
|
101 | |||
101 | $([IPython.events]).on('notebook_loaded.Notebook', first_load); |
|
102 | $([IPython.events]).on('notebook_loaded.Notebook', first_load); | |
102 | $([IPython.events]).trigger('app_initialized.NotebookApp'); |
|
103 | $([IPython.events]).trigger('app_initialized.NotebookApp'); | |
103 | IPython.notebook.load_notebook(notebookName, notebookPath); |
|
104 | IPython.notebook.load_notebook(notebookName, notebookPath); | |
104 |
|
105 | |||
105 | if (marked) { |
|
106 | if (marked) { | |
106 | marked.setOptions({ |
|
107 | marked.setOptions({ | |
107 | gfm : true, |
|
108 | gfm : true, | |
108 | tables: true, |
|
109 | tables: true, | |
109 | langPrefix: "language-", |
|
110 | langPrefix: "language-", | |
110 | highlight: function(code, lang) { |
|
111 | highlight: function(code, lang) { | |
111 | if (!lang) { |
|
112 | if (!lang) { | |
112 | // no language, no highlight |
|
113 | // no language, no highlight | |
113 | return code; |
|
114 | return code; | |
114 | } |
|
115 | } | |
115 | var highlighted; |
|
116 | var highlighted; | |
116 | try { |
|
117 | try { | |
117 | highlighted = hljs.highlight(lang, code, false); |
|
118 | highlighted = hljs.highlight(lang, code, false); | |
118 | } catch(err) { |
|
119 | } catch(err) { | |
119 | highlighted = hljs.highlightAuto(code); |
|
120 | highlighted = hljs.highlightAuto(code); | |
120 | } |
|
121 | } | |
121 | return highlighted.value; |
|
122 | return highlighted.value; | |
122 | } |
|
123 | } | |
123 | }) |
|
124 | }) | |
124 | } |
|
125 | } | |
125 | } |
|
126 | } | |
126 |
|
127 | |||
127 | ); |
|
128 | ); |
@@ -1,2213 +1,2215 b'' | |||||
1 | //---------------------------------------------------------------------------- |
|
1 | //---------------------------------------------------------------------------- | |
2 | // Copyright (C) 2011 The IPython Development Team |
|
2 | // Copyright (C) 2011 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 | // Notebook |
|
9 | // Notebook | |
10 | //============================================================================ |
|
10 | //============================================================================ | |
11 |
|
11 | |||
12 | var IPython = (function (IPython) { |
|
12 | var IPython = (function (IPython) { | |
13 | "use strict"; |
|
13 | "use strict"; | |
14 |
|
14 | |||
15 | var utils = IPython.utils; |
|
15 | var utils = IPython.utils; | |
16 |
|
16 | |||
17 | /** |
|
17 | /** | |
18 | * A notebook contains and manages cells. |
|
18 | * A notebook contains and manages cells. | |
19 | * |
|
19 | * | |
20 | * @class Notebook |
|
20 | * @class Notebook | |
21 | * @constructor |
|
21 | * @constructor | |
22 | * @param {String} selector A jQuery selector for the notebook's DOM element |
|
22 | * @param {String} selector A jQuery selector for the notebook's DOM element | |
23 | * @param {Object} [options] A config object |
|
23 | * @param {Object} [options] A config object | |
24 | */ |
|
24 | */ | |
25 | var Notebook = function (selector, options) { |
|
25 | var Notebook = function (selector, options) { | |
26 | var options = options || {}; |
|
26 | var options = options || {}; | |
27 | this._baseProjectUrl = options.baseProjectUrl; |
|
27 | this._baseProjectUrl = options.baseProjectUrl; | |
28 | this.notebook_path = options.notebookPath; |
|
28 | this.notebook_path = options.notebookPath; | |
29 | this.notebook_name = options.notebookName; |
|
29 | this.notebook_name = options.notebookName; | |
30 | this.element = $(selector); |
|
30 | this.element = $(selector); | |
31 | this.element.scroll(); |
|
31 | this.element.scroll(); | |
32 | this.element.data("notebook", this); |
|
32 | this.element.data("notebook", this); | |
33 | this.next_prompt_number = 1; |
|
33 | this.next_prompt_number = 1; | |
34 | this.session = null; |
|
34 | this.session = null; | |
35 | this.kernel = null; |
|
35 | this.kernel = null; | |
36 | this.clipboard = null; |
|
36 | this.clipboard = null; | |
37 | this.undelete_backup = null; |
|
37 | this.undelete_backup = null; | |
38 | this.undelete_index = null; |
|
38 | this.undelete_index = null; | |
39 | this.undelete_below = false; |
|
39 | this.undelete_below = false; | |
40 | this.paste_enabled = false; |
|
40 | this.paste_enabled = false; | |
41 | // It is important to start out in command mode to match the intial mode |
|
41 | // It is important to start out in command mode to match the intial mode | |
42 | // of the KeyboardManager. |
|
42 | // of the KeyboardManager. | |
43 | this.mode = 'command'; |
|
43 | this.mode = 'command'; | |
44 | this.set_dirty(false); |
|
44 | this.set_dirty(false); | |
45 | this.metadata = {}; |
|
45 | this.metadata = {}; | |
46 | this._checkpoint_after_save = false; |
|
46 | this._checkpoint_after_save = false; | |
47 | this.last_checkpoint = null; |
|
47 | this.last_checkpoint = null; | |
48 | this.checkpoints = []; |
|
48 | this.checkpoints = []; | |
49 | this.autosave_interval = 0; |
|
49 | this.autosave_interval = 0; | |
50 | this.autosave_timer = null; |
|
50 | this.autosave_timer = null; | |
51 | // autosave *at most* every two minutes |
|
51 | // autosave *at most* every two minutes | |
52 | this.minimum_autosave_interval = 120000; |
|
52 | this.minimum_autosave_interval = 120000; | |
53 | // single worksheet for now |
|
53 | // single worksheet for now | |
54 | this.worksheet_metadata = {}; |
|
54 | this.worksheet_metadata = {}; | |
55 | this.notebook_name_blacklist_re = /[\/\\:]/; |
|
55 | this.notebook_name_blacklist_re = /[\/\\:]/; | |
56 | this.nbformat = 3 // Increment this when changing the nbformat |
|
56 | this.nbformat = 3 // Increment this when changing the nbformat | |
57 | this.nbformat_minor = 0 // Increment this when changing the nbformat |
|
57 | this.nbformat_minor = 0 // Increment this when changing the nbformat | |
58 | this.style(); |
|
58 | this.style(); | |
59 | this.create_elements(); |
|
59 | this.create_elements(); | |
60 | this.bind_events(); |
|
60 | this.bind_events(); | |
61 | }; |
|
61 | }; | |
62 |
|
62 | |||
63 | /** |
|
63 | /** | |
64 | * Tweak the notebook's CSS style. |
|
64 | * Tweak the notebook's CSS style. | |
65 | * |
|
65 | * | |
66 | * @method style |
|
66 | * @method style | |
67 | */ |
|
67 | */ | |
68 | Notebook.prototype.style = function () { |
|
68 | Notebook.prototype.style = function () { | |
69 | $('div#notebook').addClass('border-box-sizing'); |
|
69 | $('div#notebook').addClass('border-box-sizing'); | |
70 | }; |
|
70 | }; | |
71 |
|
71 | |||
72 | /** |
|
72 | /** | |
73 | * Get the root URL of the notebook server. |
|
73 | * Get the root URL of the notebook server. | |
74 | * |
|
74 | * | |
75 | * @method baseProjectUrl |
|
75 | * @method baseProjectUrl | |
76 | * @return {String} The base project URL |
|
76 | * @return {String} The base project URL | |
77 | */ |
|
77 | */ | |
78 | Notebook.prototype.baseProjectUrl = function() { |
|
78 | Notebook.prototype.baseProjectUrl = function() { | |
79 | return this._baseProjectUrl || $('body').data('baseProjectUrl'); |
|
79 | return this._baseProjectUrl || $('body').data('baseProjectUrl'); | |
80 | }; |
|
80 | }; | |
81 |
|
81 | |||
82 | Notebook.prototype.notebookName = function() { |
|
82 | Notebook.prototype.notebookName = function() { | |
83 | return $('body').data('notebookName'); |
|
83 | return $('body').data('notebookName'); | |
84 | }; |
|
84 | }; | |
85 |
|
85 | |||
86 | Notebook.prototype.notebookPath = function() { |
|
86 | Notebook.prototype.notebookPath = function() { | |
87 | return $('body').data('notebookPath'); |
|
87 | return $('body').data('notebookPath'); | |
88 | }; |
|
88 | }; | |
89 |
|
89 | |||
90 | /** |
|
90 | /** | |
91 | * Create an HTML and CSS representation of the notebook. |
|
91 | * Create an HTML and CSS representation of the notebook. | |
92 | * |
|
92 | * | |
93 | * @method create_elements |
|
93 | * @method create_elements | |
94 | */ |
|
94 | */ | |
95 | Notebook.prototype.create_elements = function () { |
|
95 | Notebook.prototype.create_elements = function () { | |
96 | var that = this; |
|
96 | var that = this; | |
97 | this.element.attr('tabindex','-1'); |
|
97 | this.element.attr('tabindex','-1'); | |
98 | this.container = $("<div/>").addClass("container").attr("id", "notebook-container"); |
|
98 | this.container = $("<div/>").addClass("container").attr("id", "notebook-container"); | |
99 | // We add this end_space div to the end of the notebook div to: |
|
99 | // We add this end_space div to the end of the notebook div to: | |
100 | // i) provide a margin between the last cell and the end of the notebook |
|
100 | // i) provide a margin between the last cell and the end of the notebook | |
101 | // ii) to prevent the div from scrolling up when the last cell is being |
|
101 | // ii) to prevent the div from scrolling up when the last cell is being | |
102 | // edited, but is too low on the page, which browsers will do automatically. |
|
102 | // edited, but is too low on the page, which browsers will do automatically. | |
103 | var end_space = $('<div/>').addClass('end_space'); |
|
103 | var end_space = $('<div/>').addClass('end_space'); | |
104 | end_space.dblclick(function (e) { |
|
104 | end_space.dblclick(function (e) { | |
105 | var ncells = that.ncells(); |
|
105 | var ncells = that.ncells(); | |
106 | that.insert_cell_below('code',ncells-1); |
|
106 | that.insert_cell_below('code',ncells-1); | |
107 | }); |
|
107 | }); | |
108 | this.element.append(this.container); |
|
108 | this.element.append(this.container); | |
109 | this.container.append(end_space); |
|
109 | this.container.append(end_space); | |
110 | }; |
|
110 | }; | |
111 |
|
111 | |||
112 | /** |
|
112 | /** | |
113 | * Bind JavaScript events: key presses and custom IPython events. |
|
113 | * Bind JavaScript events: key presses and custom IPython events. | |
114 | * |
|
114 | * | |
115 | * @method bind_events |
|
115 | * @method bind_events | |
116 | */ |
|
116 | */ | |
117 | Notebook.prototype.bind_events = function () { |
|
117 | Notebook.prototype.bind_events = function () { | |
118 | var that = this; |
|
118 | var that = this; | |
119 |
|
119 | |||
120 | $([IPython.events]).on('set_next_input.Notebook', function (event, data) { |
|
120 | $([IPython.events]).on('set_next_input.Notebook', function (event, data) { | |
121 | var index = that.find_cell_index(data.cell); |
|
121 | var index = that.find_cell_index(data.cell); | |
122 | var new_cell = that.insert_cell_below('code',index); |
|
122 | var new_cell = that.insert_cell_below('code',index); | |
123 | new_cell.set_text(data.text); |
|
123 | new_cell.set_text(data.text); | |
124 | that.dirty = true; |
|
124 | that.dirty = true; | |
125 | }); |
|
125 | }); | |
126 |
|
126 | |||
127 | $([IPython.events]).on('set_dirty.Notebook', function (event, data) { |
|
127 | $([IPython.events]).on('set_dirty.Notebook', function (event, data) { | |
128 | that.dirty = data.value; |
|
128 | that.dirty = data.value; | |
129 | }); |
|
129 | }); | |
130 |
|
130 | |||
131 | $([IPython.events]).on('select.Cell', function (event, data) { |
|
131 | $([IPython.events]).on('select.Cell', function (event, data) { | |
132 | var index = that.find_cell_index(data.cell); |
|
132 | var index = that.find_cell_index(data.cell); | |
133 | that.select(index); |
|
133 | that.select(index); | |
134 | }); |
|
134 | }); | |
135 |
|
135 | |||
136 | $([IPython.events]).on('edit_mode.Cell', function (event, data) { |
|
136 | $([IPython.events]).on('edit_mode.Cell', function (event, data) { | |
137 | var index = that.find_cell_index(data.cell); |
|
137 | var index = that.find_cell_index(data.cell); | |
138 | that.select(index); |
|
138 | that.select(index); | |
139 | that.edit_mode(); |
|
139 | that.edit_mode(); | |
140 | }); |
|
140 | }); | |
141 |
|
141 | |||
142 | $([IPython.events]).on('command_mode.Cell', function (event, data) { |
|
142 | $([IPython.events]).on('command_mode.Cell', function (event, data) { | |
143 | that.command_mode(); |
|
143 | that.command_mode(); | |
144 | }); |
|
144 | }); | |
145 |
|
145 | |||
146 | $([IPython.events]).on('status_autorestarting.Kernel', function () { |
|
146 | $([IPython.events]).on('status_autorestarting.Kernel', function () { | |
147 | IPython.dialog.modal({ |
|
147 | IPython.dialog.modal({ | |
148 | title: "Kernel Restarting", |
|
148 | title: "Kernel Restarting", | |
149 | body: "The kernel appears to have died. It will restart automatically.", |
|
149 | body: "The kernel appears to have died. It will restart automatically.", | |
150 | buttons: { |
|
150 | buttons: { | |
151 | OK : { |
|
151 | OK : { | |
152 | class : "btn-primary" |
|
152 | class : "btn-primary" | |
153 | } |
|
153 | } | |
154 | } |
|
154 | } | |
155 | }); |
|
155 | }); | |
156 | }); |
|
156 | }); | |
157 |
|
157 | |||
158 | var collapse_time = function (time) { |
|
158 | var collapse_time = function (time) { | |
159 | var app_height = $('#ipython-main-app').height(); // content height |
|
159 | var app_height = $('#ipython-main-app').height(); // content height | |
160 | var splitter_height = $('div#pager_splitter').outerHeight(true); |
|
160 | var splitter_height = $('div#pager_splitter').outerHeight(true); | |
161 | var new_height = app_height - splitter_height; |
|
161 | var new_height = app_height - splitter_height; | |
162 | that.element.animate({height : new_height + 'px'}, time); |
|
162 | that.element.animate({height : new_height + 'px'}, time); | |
163 | }; |
|
163 | }; | |
164 |
|
164 | |||
165 | this.element.bind('collapse_pager', function (event, extrap) { |
|
165 | this.element.bind('collapse_pager', function (event, extrap) { | |
166 | var time = (extrap != undefined) ? ((extrap.duration != undefined ) ? extrap.duration : 'fast') : 'fast'; |
|
166 | var time = (extrap != undefined) ? ((extrap.duration != undefined ) ? extrap.duration : 'fast') : 'fast'; | |
167 | collapse_time(time); |
|
167 | collapse_time(time); | |
168 | }); |
|
168 | }); | |
169 |
|
169 | |||
170 | var expand_time = function (time) { |
|
170 | var expand_time = function (time) { | |
171 | var app_height = $('#ipython-main-app').height(); // content height |
|
171 | var app_height = $('#ipython-main-app').height(); // content height | |
172 | var splitter_height = $('div#pager_splitter').outerHeight(true); |
|
172 | var splitter_height = $('div#pager_splitter').outerHeight(true); | |
173 | var pager_height = $('div#pager').outerHeight(true); |
|
173 | var pager_height = $('div#pager').outerHeight(true); | |
174 | var new_height = app_height - pager_height - splitter_height; |
|
174 | var new_height = app_height - pager_height - splitter_height; | |
175 | that.element.animate({height : new_height + 'px'}, time); |
|
175 | that.element.animate({height : new_height + 'px'}, time); | |
176 | }; |
|
176 | }; | |
177 |
|
177 | |||
178 | this.element.bind('expand_pager', function (event, extrap) { |
|
178 | this.element.bind('expand_pager', function (event, extrap) { | |
179 | var time = (extrap != undefined) ? ((extrap.duration != undefined ) ? extrap.duration : 'fast') : 'fast'; |
|
179 | var time = (extrap != undefined) ? ((extrap.duration != undefined ) ? extrap.duration : 'fast') : 'fast'; | |
180 | expand_time(time); |
|
180 | expand_time(time); | |
181 | }); |
|
181 | }); | |
182 |
|
182 | |||
183 | // Firefox 22 broke $(window).on("beforeunload") |
|
183 | // Firefox 22 broke $(window).on("beforeunload") | |
184 | // I'm not sure why or how. |
|
184 | // I'm not sure why or how. | |
185 | window.onbeforeunload = function (e) { |
|
185 | window.onbeforeunload = function (e) { | |
186 | // TODO: Make killing the kernel configurable. |
|
186 | // TODO: Make killing the kernel configurable. | |
187 | var kill_kernel = false; |
|
187 | var kill_kernel = false; | |
188 | if (kill_kernel) { |
|
188 | if (kill_kernel) { | |
189 | that.session.kill_kernel(); |
|
189 | that.session.kill_kernel(); | |
190 | } |
|
190 | } | |
191 | // if we are autosaving, trigger an autosave on nav-away. |
|
191 | // if we are autosaving, trigger an autosave on nav-away. | |
192 | // still warn, because if we don't the autosave may fail. |
|
192 | // still warn, because if we don't the autosave may fail. | |
193 | if (that.dirty) { |
|
193 | if (that.dirty) { | |
194 | if ( that.autosave_interval ) { |
|
194 | if ( that.autosave_interval ) { | |
195 | // schedule autosave in a timeout |
|
195 | // schedule autosave in a timeout | |
196 | // this gives you a chance to forcefully discard changes |
|
196 | // this gives you a chance to forcefully discard changes | |
197 | // by reloading the page if you *really* want to. |
|
197 | // by reloading the page if you *really* want to. | |
198 | // the timer doesn't start until you *dismiss* the dialog. |
|
198 | // the timer doesn't start until you *dismiss* the dialog. | |
199 | setTimeout(function () { |
|
199 | setTimeout(function () { | |
200 | if (that.dirty) { |
|
200 | if (that.dirty) { | |
201 | that.save_notebook(); |
|
201 | that.save_notebook(); | |
202 | } |
|
202 | } | |
203 | }, 1000); |
|
203 | }, 1000); | |
204 | return "Autosave in progress, latest changes may be lost."; |
|
204 | return "Autosave in progress, latest changes may be lost."; | |
205 | } else { |
|
205 | } else { | |
206 | return "Unsaved changes will be lost."; |
|
206 | return "Unsaved changes will be lost."; | |
207 | } |
|
207 | } | |
208 | }; |
|
208 | }; | |
209 | // Null is the *only* return value that will make the browser not |
|
209 | // Null is the *only* return value that will make the browser not | |
210 | // pop up the "don't leave" dialog. |
|
210 | // pop up the "don't leave" dialog. | |
211 | return null; |
|
211 | return null; | |
212 | }; |
|
212 | }; | |
213 | }; |
|
213 | }; | |
214 |
|
214 | |||
215 | /** |
|
215 | /** | |
216 | * Set the dirty flag, and trigger the set_dirty.Notebook event |
|
216 | * Set the dirty flag, and trigger the set_dirty.Notebook event | |
217 | * |
|
217 | * | |
218 | * @method set_dirty |
|
218 | * @method set_dirty | |
219 | */ |
|
219 | */ | |
220 | Notebook.prototype.set_dirty = function (value) { |
|
220 | Notebook.prototype.set_dirty = function (value) { | |
221 | if (value === undefined) { |
|
221 | if (value === undefined) { | |
222 | value = true; |
|
222 | value = true; | |
223 | } |
|
223 | } | |
224 | if (this.dirty == value) { |
|
224 | if (this.dirty == value) { | |
225 | return; |
|
225 | return; | |
226 | } |
|
226 | } | |
227 | $([IPython.events]).trigger('set_dirty.Notebook', {value: value}); |
|
227 | $([IPython.events]).trigger('set_dirty.Notebook', {value: value}); | |
228 | }; |
|
228 | }; | |
229 |
|
229 | |||
230 | /** |
|
230 | /** | |
231 | * Scroll the top of the page to a given cell. |
|
231 | * Scroll the top of the page to a given cell. | |
232 | * |
|
232 | * | |
233 | * @method scroll_to_cell |
|
233 | * @method scroll_to_cell | |
234 | * @param {Number} cell_number An index of the cell to view |
|
234 | * @param {Number} cell_number An index of the cell to view | |
235 | * @param {Number} time Animation time in milliseconds |
|
235 | * @param {Number} time Animation time in milliseconds | |
236 | * @return {Number} Pixel offset from the top of the container |
|
236 | * @return {Number} Pixel offset from the top of the container | |
237 | */ |
|
237 | */ | |
238 | Notebook.prototype.scroll_to_cell = function (cell_number, time) { |
|
238 | Notebook.prototype.scroll_to_cell = function (cell_number, time) { | |
239 | var cells = this.get_cells(); |
|
239 | var cells = this.get_cells(); | |
240 | var time = time || 0; |
|
240 | var time = time || 0; | |
241 | cell_number = Math.min(cells.length-1,cell_number); |
|
241 | cell_number = Math.min(cells.length-1,cell_number); | |
242 | cell_number = Math.max(0 ,cell_number); |
|
242 | cell_number = Math.max(0 ,cell_number); | |
243 | var scroll_value = cells[cell_number].element.position().top-cells[0].element.position().top ; |
|
243 | var scroll_value = cells[cell_number].element.position().top-cells[0].element.position().top ; | |
244 | this.element.animate({scrollTop:scroll_value}, time); |
|
244 | this.element.animate({scrollTop:scroll_value}, time); | |
245 | return scroll_value; |
|
245 | return scroll_value; | |
246 | }; |
|
246 | }; | |
247 |
|
247 | |||
248 | /** |
|
248 | /** | |
249 | * Scroll to the bottom of the page. |
|
249 | * Scroll to the bottom of the page. | |
250 | * |
|
250 | * | |
251 | * @method scroll_to_bottom |
|
251 | * @method scroll_to_bottom | |
252 | */ |
|
252 | */ | |
253 | Notebook.prototype.scroll_to_bottom = function () { |
|
253 | Notebook.prototype.scroll_to_bottom = function () { | |
254 | this.element.animate({scrollTop:this.element.get(0).scrollHeight}, 0); |
|
254 | this.element.animate({scrollTop:this.element.get(0).scrollHeight}, 0); | |
255 | }; |
|
255 | }; | |
256 |
|
256 | |||
257 | /** |
|
257 | /** | |
258 | * Scroll to the top of the page. |
|
258 | * Scroll to the top of the page. | |
259 | * |
|
259 | * | |
260 | * @method scroll_to_top |
|
260 | * @method scroll_to_top | |
261 | */ |
|
261 | */ | |
262 | Notebook.prototype.scroll_to_top = function () { |
|
262 | Notebook.prototype.scroll_to_top = function () { | |
263 | this.element.animate({scrollTop:0}, 0); |
|
263 | this.element.animate({scrollTop:0}, 0); | |
264 | }; |
|
264 | }; | |
265 |
|
265 | |||
266 | // Edit Notebook metadata |
|
266 | // Edit Notebook metadata | |
267 |
|
267 | |||
268 | Notebook.prototype.edit_metadata = function () { |
|
268 | Notebook.prototype.edit_metadata = function () { | |
269 | var that = this; |
|
269 | var that = this; | |
270 | IPython.dialog.edit_metadata(this.metadata, function (md) { |
|
270 | IPython.dialog.edit_metadata(this.metadata, function (md) { | |
271 | that.metadata = md; |
|
271 | that.metadata = md; | |
272 | }, 'Notebook'); |
|
272 | }, 'Notebook'); | |
273 | }; |
|
273 | }; | |
274 |
|
274 | |||
275 | // Cell indexing, retrieval, etc. |
|
275 | // Cell indexing, retrieval, etc. | |
276 |
|
276 | |||
277 | /** |
|
277 | /** | |
278 | * Get all cell elements in the notebook. |
|
278 | * Get all cell elements in the notebook. | |
279 | * |
|
279 | * | |
280 | * @method get_cell_elements |
|
280 | * @method get_cell_elements | |
281 | * @return {jQuery} A selector of all cell elements |
|
281 | * @return {jQuery} A selector of all cell elements | |
282 | */ |
|
282 | */ | |
283 | Notebook.prototype.get_cell_elements = function () { |
|
283 | Notebook.prototype.get_cell_elements = function () { | |
284 | return this.container.children("div.cell"); |
|
284 | return this.container.children("div.cell"); | |
285 | }; |
|
285 | }; | |
286 |
|
286 | |||
287 | /** |
|
287 | /** | |
288 | * Get a particular cell element. |
|
288 | * Get a particular cell element. | |
289 | * |
|
289 | * | |
290 | * @method get_cell_element |
|
290 | * @method get_cell_element | |
291 | * @param {Number} index An index of a cell to select |
|
291 | * @param {Number} index An index of a cell to select | |
292 | * @return {jQuery} A selector of the given cell. |
|
292 | * @return {jQuery} A selector of the given cell. | |
293 | */ |
|
293 | */ | |
294 | Notebook.prototype.get_cell_element = function (index) { |
|
294 | Notebook.prototype.get_cell_element = function (index) { | |
295 | var result = null; |
|
295 | var result = null; | |
296 | var e = this.get_cell_elements().eq(index); |
|
296 | var e = this.get_cell_elements().eq(index); | |
297 | if (e.length !== 0) { |
|
297 | if (e.length !== 0) { | |
298 | result = e; |
|
298 | result = e; | |
299 | } |
|
299 | } | |
300 | return result; |
|
300 | return result; | |
301 | }; |
|
301 | }; | |
302 |
|
302 | |||
303 | /** |
|
303 | /** | |
304 | * Count the cells in this notebook. |
|
304 | * Count the cells in this notebook. | |
305 | * |
|
305 | * | |
306 | * @method ncells |
|
306 | * @method ncells | |
307 | * @return {Number} The number of cells in this notebook |
|
307 | * @return {Number} The number of cells in this notebook | |
308 | */ |
|
308 | */ | |
309 | Notebook.prototype.ncells = function () { |
|
309 | Notebook.prototype.ncells = function () { | |
310 | return this.get_cell_elements().length; |
|
310 | return this.get_cell_elements().length; | |
311 | }; |
|
311 | }; | |
312 |
|
312 | |||
313 | /** |
|
313 | /** | |
314 | * Get all Cell objects in this notebook. |
|
314 | * Get all Cell objects in this notebook. | |
315 | * |
|
315 | * | |
316 | * @method get_cells |
|
316 | * @method get_cells | |
317 | * @return {Array} This notebook's Cell objects |
|
317 | * @return {Array} This notebook's Cell objects | |
318 | */ |
|
318 | */ | |
319 | // TODO: we are often calling cells as cells()[i], which we should optimize |
|
319 | // TODO: we are often calling cells as cells()[i], which we should optimize | |
320 | // to cells(i) or a new method. |
|
320 | // to cells(i) or a new method. | |
321 | Notebook.prototype.get_cells = function () { |
|
321 | Notebook.prototype.get_cells = function () { | |
322 | return this.get_cell_elements().toArray().map(function (e) { |
|
322 | return this.get_cell_elements().toArray().map(function (e) { | |
323 | return $(e).data("cell"); |
|
323 | return $(e).data("cell"); | |
324 | }); |
|
324 | }); | |
325 | }; |
|
325 | }; | |
326 |
|
326 | |||
327 | /** |
|
327 | /** | |
328 | * Get a Cell object from this notebook. |
|
328 | * Get a Cell object from this notebook. | |
329 | * |
|
329 | * | |
330 | * @method get_cell |
|
330 | * @method get_cell | |
331 | * @param {Number} index An index of a cell to retrieve |
|
331 | * @param {Number} index An index of a cell to retrieve | |
332 | * @return {Cell} A particular cell |
|
332 | * @return {Cell} A particular cell | |
333 | */ |
|
333 | */ | |
334 | Notebook.prototype.get_cell = function (index) { |
|
334 | Notebook.prototype.get_cell = function (index) { | |
335 | var result = null; |
|
335 | var result = null; | |
336 | var ce = this.get_cell_element(index); |
|
336 | var ce = this.get_cell_element(index); | |
337 | if (ce !== null) { |
|
337 | if (ce !== null) { | |
338 | result = ce.data('cell'); |
|
338 | result = ce.data('cell'); | |
339 | } |
|
339 | } | |
340 | return result; |
|
340 | return result; | |
341 | } |
|
341 | } | |
342 |
|
342 | |||
343 | /** |
|
343 | /** | |
344 | * Get the cell below a given cell. |
|
344 | * Get the cell below a given cell. | |
345 | * |
|
345 | * | |
346 | * @method get_next_cell |
|
346 | * @method get_next_cell | |
347 | * @param {Cell} cell The provided cell |
|
347 | * @param {Cell} cell The provided cell | |
348 | * @return {Cell} The next cell |
|
348 | * @return {Cell} The next cell | |
349 | */ |
|
349 | */ | |
350 | Notebook.prototype.get_next_cell = function (cell) { |
|
350 | Notebook.prototype.get_next_cell = function (cell) { | |
351 | var result = null; |
|
351 | var result = null; | |
352 | var index = this.find_cell_index(cell); |
|
352 | var index = this.find_cell_index(cell); | |
353 | if (this.is_valid_cell_index(index+1)) { |
|
353 | if (this.is_valid_cell_index(index+1)) { | |
354 | result = this.get_cell(index+1); |
|
354 | result = this.get_cell(index+1); | |
355 | } |
|
355 | } | |
356 | return result; |
|
356 | return result; | |
357 | } |
|
357 | } | |
358 |
|
358 | |||
359 | /** |
|
359 | /** | |
360 | * Get the cell above a given cell. |
|
360 | * Get the cell above a given cell. | |
361 | * |
|
361 | * | |
362 | * @method get_prev_cell |
|
362 | * @method get_prev_cell | |
363 | * @param {Cell} cell The provided cell |
|
363 | * @param {Cell} cell The provided cell | |
364 | * @return {Cell} The previous cell |
|
364 | * @return {Cell} The previous cell | |
365 | */ |
|
365 | */ | |
366 | Notebook.prototype.get_prev_cell = function (cell) { |
|
366 | Notebook.prototype.get_prev_cell = function (cell) { | |
367 | // TODO: off-by-one |
|
367 | // TODO: off-by-one | |
368 | // nb.get_prev_cell(nb.get_cell(1)) is null |
|
368 | // nb.get_prev_cell(nb.get_cell(1)) is null | |
369 | var result = null; |
|
369 | var result = null; | |
370 | var index = this.find_cell_index(cell); |
|
370 | var index = this.find_cell_index(cell); | |
371 | if (index !== null && index > 1) { |
|
371 | if (index !== null && index > 1) { | |
372 | result = this.get_cell(index-1); |
|
372 | result = this.get_cell(index-1); | |
373 | } |
|
373 | } | |
374 | return result; |
|
374 | return result; | |
375 | } |
|
375 | } | |
376 |
|
376 | |||
377 | /** |
|
377 | /** | |
378 | * Get the numeric index of a given cell. |
|
378 | * Get the numeric index of a given cell. | |
379 | * |
|
379 | * | |
380 | * @method find_cell_index |
|
380 | * @method find_cell_index | |
381 | * @param {Cell} cell The provided cell |
|
381 | * @param {Cell} cell The provided cell | |
382 | * @return {Number} The cell's numeric index |
|
382 | * @return {Number} The cell's numeric index | |
383 | */ |
|
383 | */ | |
384 | Notebook.prototype.find_cell_index = function (cell) { |
|
384 | Notebook.prototype.find_cell_index = function (cell) { | |
385 | var result = null; |
|
385 | var result = null; | |
386 | this.get_cell_elements().filter(function (index) { |
|
386 | this.get_cell_elements().filter(function (index) { | |
387 | if ($(this).data("cell") === cell) { |
|
387 | if ($(this).data("cell") === cell) { | |
388 | result = index; |
|
388 | result = index; | |
389 | }; |
|
389 | }; | |
390 | }); |
|
390 | }); | |
391 | return result; |
|
391 | return result; | |
392 | }; |
|
392 | }; | |
393 |
|
393 | |||
394 | /** |
|
394 | /** | |
395 | * Get a given index , or the selected index if none is provided. |
|
395 | * Get a given index , or the selected index if none is provided. | |
396 | * |
|
396 | * | |
397 | * @method index_or_selected |
|
397 | * @method index_or_selected | |
398 | * @param {Number} index A cell's index |
|
398 | * @param {Number} index A cell's index | |
399 | * @return {Number} The given index, or selected index if none is provided. |
|
399 | * @return {Number} The given index, or selected index if none is provided. | |
400 | */ |
|
400 | */ | |
401 | Notebook.prototype.index_or_selected = function (index) { |
|
401 | Notebook.prototype.index_or_selected = function (index) { | |
402 | var i; |
|
402 | var i; | |
403 | if (index === undefined || index === null) { |
|
403 | if (index === undefined || index === null) { | |
404 | i = this.get_selected_index(); |
|
404 | i = this.get_selected_index(); | |
405 | if (i === null) { |
|
405 | if (i === null) { | |
406 | i = 0; |
|
406 | i = 0; | |
407 | } |
|
407 | } | |
408 | } else { |
|
408 | } else { | |
409 | i = index; |
|
409 | i = index; | |
410 | } |
|
410 | } | |
411 | return i; |
|
411 | return i; | |
412 | }; |
|
412 | }; | |
413 |
|
413 | |||
414 | /** |
|
414 | /** | |
415 | * Get the currently selected cell. |
|
415 | * Get the currently selected cell. | |
416 | * @method get_selected_cell |
|
416 | * @method get_selected_cell | |
417 | * @return {Cell} The selected cell |
|
417 | * @return {Cell} The selected cell | |
418 | */ |
|
418 | */ | |
419 | Notebook.prototype.get_selected_cell = function () { |
|
419 | Notebook.prototype.get_selected_cell = function () { | |
420 | var index = this.get_selected_index(); |
|
420 | var index = this.get_selected_index(); | |
421 | return this.get_cell(index); |
|
421 | return this.get_cell(index); | |
422 | }; |
|
422 | }; | |
423 |
|
423 | |||
424 | /** |
|
424 | /** | |
425 | * Check whether a cell index is valid. |
|
425 | * Check whether a cell index is valid. | |
426 | * |
|
426 | * | |
427 | * @method is_valid_cell_index |
|
427 | * @method is_valid_cell_index | |
428 | * @param {Number} index A cell index |
|
428 | * @param {Number} index A cell index | |
429 | * @return True if the index is valid, false otherwise |
|
429 | * @return True if the index is valid, false otherwise | |
430 | */ |
|
430 | */ | |
431 | Notebook.prototype.is_valid_cell_index = function (index) { |
|
431 | Notebook.prototype.is_valid_cell_index = function (index) { | |
432 | if (index !== null && index >= 0 && index < this.ncells()) { |
|
432 | if (index !== null && index >= 0 && index < this.ncells()) { | |
433 | return true; |
|
433 | return true; | |
434 | } else { |
|
434 | } else { | |
435 | return false; |
|
435 | return false; | |
436 | }; |
|
436 | }; | |
437 | } |
|
437 | } | |
438 |
|
438 | |||
439 | /** |
|
439 | /** | |
440 | * Get the index of the currently selected cell. |
|
440 | * Get the index of the currently selected cell. | |
441 |
|
441 | |||
442 | * @method get_selected_index |
|
442 | * @method get_selected_index | |
443 | * @return {Number} The selected cell's numeric index |
|
443 | * @return {Number} The selected cell's numeric index | |
444 | */ |
|
444 | */ | |
445 | Notebook.prototype.get_selected_index = function () { |
|
445 | Notebook.prototype.get_selected_index = function () { | |
446 | var result = null; |
|
446 | var result = null; | |
447 | this.get_cell_elements().filter(function (index) { |
|
447 | this.get_cell_elements().filter(function (index) { | |
448 | if ($(this).data("cell").selected === true) { |
|
448 | if ($(this).data("cell").selected === true) { | |
449 | result = index; |
|
449 | result = index; | |
450 | }; |
|
450 | }; | |
451 | }); |
|
451 | }); | |
452 | return result; |
|
452 | return result; | |
453 | }; |
|
453 | }; | |
454 |
|
454 | |||
455 |
|
455 | |||
456 | // Cell selection. |
|
456 | // Cell selection. | |
457 |
|
457 | |||
458 | /** |
|
458 | /** | |
459 | * Programmatically select a cell. |
|
459 | * Programmatically select a cell. | |
460 | * |
|
460 | * | |
461 | * @method select |
|
461 | * @method select | |
462 | * @param {Number} index A cell's index |
|
462 | * @param {Number} index A cell's index | |
463 | * @return {Notebook} This notebook |
|
463 | * @return {Notebook} This notebook | |
464 | */ |
|
464 | */ | |
465 | Notebook.prototype.select = function (index) { |
|
465 | Notebook.prototype.select = function (index) { | |
466 | if (this.is_valid_cell_index(index)) { |
|
466 | if (this.is_valid_cell_index(index)) { | |
467 | var sindex = this.get_selected_index() |
|
467 | var sindex = this.get_selected_index() | |
468 | if (sindex !== null && index !== sindex) { |
|
468 | if (sindex !== null && index !== sindex) { | |
469 | this.command_mode(); |
|
469 | this.command_mode(); | |
470 | this.get_cell(sindex).unselect(); |
|
470 | this.get_cell(sindex).unselect(); | |
471 | }; |
|
471 | }; | |
472 | var cell = this.get_cell(index); |
|
472 | var cell = this.get_cell(index); | |
473 | cell.select(); |
|
473 | cell.select(); | |
474 | if (cell.cell_type === 'heading') { |
|
474 | if (cell.cell_type === 'heading') { | |
475 | $([IPython.events]).trigger('selected_cell_type_changed.Notebook', |
|
475 | $([IPython.events]).trigger('selected_cell_type_changed.Notebook', | |
476 | {'cell_type':cell.cell_type,level:cell.level} |
|
476 | {'cell_type':cell.cell_type,level:cell.level} | |
477 | ); |
|
477 | ); | |
478 | } else { |
|
478 | } else { | |
479 | $([IPython.events]).trigger('selected_cell_type_changed.Notebook', |
|
479 | $([IPython.events]).trigger('selected_cell_type_changed.Notebook', | |
480 | {'cell_type':cell.cell_type} |
|
480 | {'cell_type':cell.cell_type} | |
481 | ); |
|
481 | ); | |
482 | }; |
|
482 | }; | |
483 | }; |
|
483 | }; | |
484 | return this; |
|
484 | return this; | |
485 | }; |
|
485 | }; | |
486 |
|
486 | |||
487 | /** |
|
487 | /** | |
488 | * Programmatically select the next cell. |
|
488 | * Programmatically select the next cell. | |
489 | * |
|
489 | * | |
490 | * @method select_next |
|
490 | * @method select_next | |
491 | * @return {Notebook} This notebook |
|
491 | * @return {Notebook} This notebook | |
492 | */ |
|
492 | */ | |
493 | Notebook.prototype.select_next = function () { |
|
493 | Notebook.prototype.select_next = function () { | |
494 | var index = this.get_selected_index(); |
|
494 | var index = this.get_selected_index(); | |
495 | this.select(index+1); |
|
495 | this.select(index+1); | |
496 | return this; |
|
496 | return this; | |
497 | }; |
|
497 | }; | |
498 |
|
498 | |||
499 | /** |
|
499 | /** | |
500 | * Programmatically select the previous cell. |
|
500 | * Programmatically select the previous cell. | |
501 | * |
|
501 | * | |
502 | * @method select_prev |
|
502 | * @method select_prev | |
503 | * @return {Notebook} This notebook |
|
503 | * @return {Notebook} This notebook | |
504 | */ |
|
504 | */ | |
505 | Notebook.prototype.select_prev = function () { |
|
505 | Notebook.prototype.select_prev = function () { | |
506 | var index = this.get_selected_index(); |
|
506 | var index = this.get_selected_index(); | |
507 | this.select(index-1); |
|
507 | this.select(index-1); | |
508 | return this; |
|
508 | return this; | |
509 | }; |
|
509 | }; | |
510 |
|
510 | |||
511 |
|
511 | |||
512 | // Edit/Command mode |
|
512 | // Edit/Command mode | |
513 |
|
513 | |||
514 | Notebook.prototype.get_edit_index = function () { |
|
514 | Notebook.prototype.get_edit_index = function () { | |
515 | var result = null; |
|
515 | var result = null; | |
516 | this.get_cell_elements().filter(function (index) { |
|
516 | this.get_cell_elements().filter(function (index) { | |
517 | if ($(this).data("cell").mode === 'edit') { |
|
517 | if ($(this).data("cell").mode === 'edit') { | |
518 | result = index; |
|
518 | result = index; | |
519 | }; |
|
519 | }; | |
520 | }); |
|
520 | }); | |
521 | return result; |
|
521 | return result; | |
522 | }; |
|
522 | }; | |
523 |
|
523 | |||
524 | Notebook.prototype.command_mode = function () { |
|
524 | Notebook.prototype.command_mode = function () { | |
525 | if (this.mode !== 'command') { |
|
525 | if (this.mode !== 'command') { | |
526 | var index = this.get_edit_index(); |
|
526 | var index = this.get_edit_index(); | |
527 | var cell = this.get_cell(index); |
|
527 | var cell = this.get_cell(index); | |
528 | if (cell) { |
|
528 | if (cell) { | |
529 | cell.command_mode(); |
|
529 | cell.command_mode(); | |
530 | }; |
|
530 | }; | |
531 | this.mode = 'command'; |
|
531 | this.mode = 'command'; | |
532 | IPython.keyboard_manager.command_mode(); |
|
532 | IPython.keyboard_manager.command_mode(); | |
533 | }; |
|
533 | }; | |
534 | }; |
|
534 | }; | |
535 |
|
535 | |||
536 | Notebook.prototype.edit_mode = function () { |
|
536 | Notebook.prototype.edit_mode = function () { | |
537 | if (this.mode !== 'edit') { |
|
537 | if (this.mode !== 'edit') { | |
538 | var cell = this.get_selected_cell(); |
|
538 | var cell = this.get_selected_cell(); | |
539 | if (cell === null) {return;} // No cell is selected |
|
539 | if (cell === null) {return;} // No cell is selected | |
540 | // We need to set the mode to edit to prevent reentering this method |
|
540 | // We need to set the mode to edit to prevent reentering this method | |
541 | // when cell.edit_mode() is called below. |
|
541 | // when cell.edit_mode() is called below. | |
542 | this.mode = 'edit'; |
|
542 | this.mode = 'edit'; | |
543 | IPython.keyboard_manager.edit_mode(); |
|
543 | IPython.keyboard_manager.edit_mode(); | |
544 | cell.edit_mode(); |
|
544 | cell.edit_mode(); | |
545 | }; |
|
545 | }; | |
546 | }; |
|
546 | }; | |
547 |
|
547 | |||
548 | Notebook.prototype.focus_cell = function () { |
|
548 | Notebook.prototype.focus_cell = function () { | |
549 | var cell = this.get_selected_cell(); |
|
549 | var cell = this.get_selected_cell(); | |
550 | if (cell === null) {return;} // No cell is selected |
|
550 | if (cell === null) {return;} // No cell is selected | |
551 | cell.focus_cell(); |
|
551 | cell.focus_cell(); | |
552 | }; |
|
552 | }; | |
553 |
|
553 | |||
554 | // Cell movement |
|
554 | // Cell movement | |
555 |
|
555 | |||
556 | /** |
|
556 | /** | |
557 | * Move given (or selected) cell up and select it. |
|
557 | * Move given (or selected) cell up and select it. | |
558 | * |
|
558 | * | |
559 | * @method move_cell_up |
|
559 | * @method move_cell_up | |
560 | * @param [index] {integer} cell index |
|
560 | * @param [index] {integer} cell index | |
561 | * @return {Notebook} This notebook |
|
561 | * @return {Notebook} This notebook | |
562 | **/ |
|
562 | **/ | |
563 | Notebook.prototype.move_cell_up = function (index) { |
|
563 | Notebook.prototype.move_cell_up = function (index) { | |
564 | var i = this.index_or_selected(index); |
|
564 | var i = this.index_or_selected(index); | |
565 | if (this.is_valid_cell_index(i) && i > 0) { |
|
565 | if (this.is_valid_cell_index(i) && i > 0) { | |
566 | var pivot = this.get_cell_element(i-1); |
|
566 | var pivot = this.get_cell_element(i-1); | |
567 | var tomove = this.get_cell_element(i); |
|
567 | var tomove = this.get_cell_element(i); | |
568 | if (pivot !== null && tomove !== null) { |
|
568 | if (pivot !== null && tomove !== null) { | |
569 | tomove.detach(); |
|
569 | tomove.detach(); | |
570 | pivot.before(tomove); |
|
570 | pivot.before(tomove); | |
571 | this.select(i-1); |
|
571 | this.select(i-1); | |
572 | var cell = this.get_selected_cell(); |
|
572 | var cell = this.get_selected_cell(); | |
573 | cell.focus_cell(); |
|
573 | cell.focus_cell(); | |
574 | }; |
|
574 | }; | |
575 | this.set_dirty(true); |
|
575 | this.set_dirty(true); | |
576 | }; |
|
576 | }; | |
577 | return this; |
|
577 | return this; | |
578 | }; |
|
578 | }; | |
579 |
|
579 | |||
580 |
|
580 | |||
581 | /** |
|
581 | /** | |
582 | * Move given (or selected) cell down and select it |
|
582 | * Move given (or selected) cell down and select it | |
583 | * |
|
583 | * | |
584 | * @method move_cell_down |
|
584 | * @method move_cell_down | |
585 | * @param [index] {integer} cell index |
|
585 | * @param [index] {integer} cell index | |
586 | * @return {Notebook} This notebook |
|
586 | * @return {Notebook} This notebook | |
587 | **/ |
|
587 | **/ | |
588 | Notebook.prototype.move_cell_down = function (index) { |
|
588 | Notebook.prototype.move_cell_down = function (index) { | |
589 | var i = this.index_or_selected(index); |
|
589 | var i = this.index_or_selected(index); | |
590 | if (this.is_valid_cell_index(i) && this.is_valid_cell_index(i+1)) { |
|
590 | if (this.is_valid_cell_index(i) && this.is_valid_cell_index(i+1)) { | |
591 | var pivot = this.get_cell_element(i+1); |
|
591 | var pivot = this.get_cell_element(i+1); | |
592 | var tomove = this.get_cell_element(i); |
|
592 | var tomove = this.get_cell_element(i); | |
593 | if (pivot !== null && tomove !== null) { |
|
593 | if (pivot !== null && tomove !== null) { | |
594 | tomove.detach(); |
|
594 | tomove.detach(); | |
595 | pivot.after(tomove); |
|
595 | pivot.after(tomove); | |
596 | this.select(i+1); |
|
596 | this.select(i+1); | |
597 | var cell = this.get_selected_cell(); |
|
597 | var cell = this.get_selected_cell(); | |
598 | cell.focus_cell(); |
|
598 | cell.focus_cell(); | |
599 | }; |
|
599 | }; | |
600 | }; |
|
600 | }; | |
601 | this.set_dirty(); |
|
601 | this.set_dirty(); | |
602 | return this; |
|
602 | return this; | |
603 | }; |
|
603 | }; | |
604 |
|
604 | |||
605 |
|
605 | |||
606 | // Insertion, deletion. |
|
606 | // Insertion, deletion. | |
607 |
|
607 | |||
608 | /** |
|
608 | /** | |
609 | * Delete a cell from the notebook. |
|
609 | * Delete a cell from the notebook. | |
610 | * |
|
610 | * | |
611 | * @method delete_cell |
|
611 | * @method delete_cell | |
612 | * @param [index] A cell's numeric index |
|
612 | * @param [index] A cell's numeric index | |
613 | * @return {Notebook} This notebook |
|
613 | * @return {Notebook} This notebook | |
614 | */ |
|
614 | */ | |
615 | Notebook.prototype.delete_cell = function (index) { |
|
615 | Notebook.prototype.delete_cell = function (index) { | |
616 | var i = this.index_or_selected(index); |
|
616 | var i = this.index_or_selected(index); | |
617 | var cell = this.get_selected_cell(); |
|
617 | var cell = this.get_selected_cell(); | |
618 | this.undelete_backup = cell.toJSON(); |
|
618 | this.undelete_backup = cell.toJSON(); | |
619 | $('#undelete_cell').removeClass('disabled'); |
|
619 | $('#undelete_cell').removeClass('disabled'); | |
620 | if (this.is_valid_cell_index(i)) { |
|
620 | if (this.is_valid_cell_index(i)) { | |
621 | var old_ncells = this.ncells(); |
|
621 | var old_ncells = this.ncells(); | |
622 | var ce = this.get_cell_element(i); |
|
622 | var ce = this.get_cell_element(i); | |
623 | ce.remove(); |
|
623 | ce.remove(); | |
624 | if (i === 0) { |
|
624 | if (i === 0) { | |
625 | // Always make sure we have at least one cell. |
|
625 | // Always make sure we have at least one cell. | |
626 | if (old_ncells === 1) { |
|
626 | if (old_ncells === 1) { | |
627 | this.insert_cell_below('code'); |
|
627 | this.insert_cell_below('code'); | |
628 | } |
|
628 | } | |
629 | this.select(0); |
|
629 | this.select(0); | |
630 | this.undelete_index = 0; |
|
630 | this.undelete_index = 0; | |
631 | this.undelete_below = false; |
|
631 | this.undelete_below = false; | |
632 | } else if (i === old_ncells-1 && i !== 0) { |
|
632 | } else if (i === old_ncells-1 && i !== 0) { | |
633 | this.select(i-1); |
|
633 | this.select(i-1); | |
634 | this.undelete_index = i - 1; |
|
634 | this.undelete_index = i - 1; | |
635 | this.undelete_below = true; |
|
635 | this.undelete_below = true; | |
636 | } else { |
|
636 | } else { | |
637 | this.select(i); |
|
637 | this.select(i); | |
638 | this.undelete_index = i; |
|
638 | this.undelete_index = i; | |
639 | this.undelete_below = false; |
|
639 | this.undelete_below = false; | |
640 | }; |
|
640 | }; | |
641 | $([IPython.events]).trigger('delete.Cell', {'cell': cell, 'index': i}); |
|
641 | $([IPython.events]).trigger('delete.Cell', {'cell': cell, 'index': i}); | |
642 | this.set_dirty(true); |
|
642 | this.set_dirty(true); | |
643 | }; |
|
643 | }; | |
644 | return this; |
|
644 | return this; | |
645 | }; |
|
645 | }; | |
646 |
|
646 | |||
647 | /** |
|
647 | /** | |
648 | * Restore the most recently deleted cell. |
|
648 | * Restore the most recently deleted cell. | |
649 | * |
|
649 | * | |
650 | * @method undelete |
|
650 | * @method undelete | |
651 | */ |
|
651 | */ | |
652 | Notebook.prototype.undelete_cell = function() { |
|
652 | Notebook.prototype.undelete_cell = function() { | |
653 | if (this.undelete_backup !== null && this.undelete_index !== null) { |
|
653 | if (this.undelete_backup !== null && this.undelete_index !== null) { | |
654 | var current_index = this.get_selected_index(); |
|
654 | var current_index = this.get_selected_index(); | |
655 | if (this.undelete_index < current_index) { |
|
655 | if (this.undelete_index < current_index) { | |
656 | current_index = current_index + 1; |
|
656 | current_index = current_index + 1; | |
657 | } |
|
657 | } | |
658 | if (this.undelete_index >= this.ncells()) { |
|
658 | if (this.undelete_index >= this.ncells()) { | |
659 | this.select(this.ncells() - 1); |
|
659 | this.select(this.ncells() - 1); | |
660 | } |
|
660 | } | |
661 | else { |
|
661 | else { | |
662 | this.select(this.undelete_index); |
|
662 | this.select(this.undelete_index); | |
663 | } |
|
663 | } | |
664 | var cell_data = this.undelete_backup; |
|
664 | var cell_data = this.undelete_backup; | |
665 | var new_cell = null; |
|
665 | var new_cell = null; | |
666 | if (this.undelete_below) { |
|
666 | if (this.undelete_below) { | |
667 | new_cell = this.insert_cell_below(cell_data.cell_type); |
|
667 | new_cell = this.insert_cell_below(cell_data.cell_type); | |
668 | } else { |
|
668 | } else { | |
669 | new_cell = this.insert_cell_above(cell_data.cell_type); |
|
669 | new_cell = this.insert_cell_above(cell_data.cell_type); | |
670 | } |
|
670 | } | |
671 | new_cell.fromJSON(cell_data); |
|
671 | new_cell.fromJSON(cell_data); | |
672 | if (this.undelete_below) { |
|
672 | if (this.undelete_below) { | |
673 | this.select(current_index+1); |
|
673 | this.select(current_index+1); | |
674 | } else { |
|
674 | } else { | |
675 | this.select(current_index); |
|
675 | this.select(current_index); | |
676 | } |
|
676 | } | |
677 | this.undelete_backup = null; |
|
677 | this.undelete_backup = null; | |
678 | this.undelete_index = null; |
|
678 | this.undelete_index = null; | |
679 | } |
|
679 | } | |
680 | $('#undelete_cell').addClass('disabled'); |
|
680 | $('#undelete_cell').addClass('disabled'); | |
681 | } |
|
681 | } | |
682 |
|
682 | |||
683 | /** |
|
683 | /** | |
684 | * Insert a cell so that after insertion the cell is at given index. |
|
684 | * Insert a cell so that after insertion the cell is at given index. | |
685 | * |
|
685 | * | |
686 | * Similar to insert_above, but index parameter is mandatory |
|
686 | * Similar to insert_above, but index parameter is mandatory | |
687 | * |
|
687 | * | |
688 | * Index will be brought back into the accissible range [0,n] |
|
688 | * Index will be brought back into the accissible range [0,n] | |
689 | * |
|
689 | * | |
690 | * @method insert_cell_at_index |
|
690 | * @method insert_cell_at_index | |
691 | * @param type {string} in ['code','markdown','heading'] |
|
691 | * @param type {string} in ['code','markdown','heading'] | |
692 | * @param [index] {int} a valid index where to inser cell |
|
692 | * @param [index] {int} a valid index where to inser cell | |
693 | * |
|
693 | * | |
694 | * @return cell {cell|null} created cell or null |
|
694 | * @return cell {cell|null} created cell or null | |
695 | **/ |
|
695 | **/ | |
696 | Notebook.prototype.insert_cell_at_index = function(type, index){ |
|
696 | Notebook.prototype.insert_cell_at_index = function(type, index){ | |
697 |
|
697 | |||
698 | var ncells = this.ncells(); |
|
698 | var ncells = this.ncells(); | |
699 | var index = Math.min(index,ncells); |
|
699 | var index = Math.min(index,ncells); | |
700 | index = Math.max(index,0); |
|
700 | index = Math.max(index,0); | |
701 | var cell = null; |
|
701 | var cell = null; | |
702 |
|
702 | |||
703 | if (ncells === 0 || this.is_valid_cell_index(index) || index === ncells) { |
|
703 | if (ncells === 0 || this.is_valid_cell_index(index) || index === ncells) { | |
704 | if (type === 'code') { |
|
704 | if (type === 'code') { | |
705 | cell = new IPython.CodeCell(this.kernel); |
|
705 | cell = new IPython.CodeCell(this.kernel); | |
706 | cell.set_input_prompt(); |
|
706 | cell.set_input_prompt(); | |
707 | } else if (type === 'markdown') { |
|
707 | } else if (type === 'markdown') { | |
708 | cell = new IPython.MarkdownCell(); |
|
708 | cell = new IPython.MarkdownCell(); | |
709 | } else if (type === 'raw') { |
|
709 | } else if (type === 'raw') { | |
710 | cell = new IPython.RawCell(); |
|
710 | cell = new IPython.RawCell(); | |
711 | } else if (type === 'heading') { |
|
711 | } else if (type === 'heading') { | |
712 | cell = new IPython.HeadingCell(); |
|
712 | cell = new IPython.HeadingCell(); | |
713 | } |
|
713 | } | |
714 |
|
714 | |||
715 | if(this._insert_element_at_index(cell.element,index)) { |
|
715 | if(this._insert_element_at_index(cell.element,index)) { | |
716 | cell.render(); |
|
716 | cell.render(); | |
717 | $([IPython.events]).trigger('create.Cell', {'cell': cell, 'index': index}); |
|
717 | $([IPython.events]).trigger('create.Cell', {'cell': cell, 'index': index}); | |
718 | cell.refresh(); |
|
718 | cell.refresh(); | |
719 | // We used to select the cell after we refresh it, but there |
|
719 | // We used to select the cell after we refresh it, but there | |
720 | // are now cases were this method is called where select is |
|
720 | // are now cases were this method is called where select is | |
721 | // not appropriate. The selection logic should be handled by the |
|
721 | // not appropriate. The selection logic should be handled by the | |
722 | // caller of the the top level insert_cell methods. |
|
722 | // caller of the the top level insert_cell methods. | |
723 | this.set_dirty(true); |
|
723 | this.set_dirty(true); | |
724 | } |
|
724 | } | |
725 | } |
|
725 | } | |
726 | return cell; |
|
726 | return cell; | |
727 |
|
727 | |||
728 | }; |
|
728 | }; | |
729 |
|
729 | |||
730 | /** |
|
730 | /** | |
731 | * Insert an element at given cell index. |
|
731 | * Insert an element at given cell index. | |
732 | * |
|
732 | * | |
733 | * @method _insert_element_at_index |
|
733 | * @method _insert_element_at_index | |
734 | * @param element {dom element} a cell element |
|
734 | * @param element {dom element} a cell element | |
735 | * @param [index] {int} a valid index where to inser cell |
|
735 | * @param [index] {int} a valid index where to inser cell | |
736 | * @private |
|
736 | * @private | |
737 | * |
|
737 | * | |
738 | * return true if everything whent fine. |
|
738 | * return true if everything whent fine. | |
739 | **/ |
|
739 | **/ | |
740 | Notebook.prototype._insert_element_at_index = function(element, index){ |
|
740 | Notebook.prototype._insert_element_at_index = function(element, index){ | |
741 | if (element === undefined){ |
|
741 | if (element === undefined){ | |
742 | return false; |
|
742 | return false; | |
743 | } |
|
743 | } | |
744 |
|
744 | |||
745 | var ncells = this.ncells(); |
|
745 | var ncells = this.ncells(); | |
746 |
|
746 | |||
747 | if (ncells === 0) { |
|
747 | if (ncells === 0) { | |
748 | // special case append if empty |
|
748 | // special case append if empty | |
749 | this.element.find('div.end_space').before(element); |
|
749 | this.element.find('div.end_space').before(element); | |
750 | } else if ( ncells === index ) { |
|
750 | } else if ( ncells === index ) { | |
751 | // special case append it the end, but not empty |
|
751 | // special case append it the end, but not empty | |
752 | this.get_cell_element(index-1).after(element); |
|
752 | this.get_cell_element(index-1).after(element); | |
753 | } else if (this.is_valid_cell_index(index)) { |
|
753 | } else if (this.is_valid_cell_index(index)) { | |
754 | // otherwise always somewhere to append to |
|
754 | // otherwise always somewhere to append to | |
755 | this.get_cell_element(index).before(element); |
|
755 | this.get_cell_element(index).before(element); | |
756 | } else { |
|
756 | } else { | |
757 | return false; |
|
757 | return false; | |
758 | } |
|
758 | } | |
759 |
|
759 | |||
760 | if (this.undelete_index !== null && index <= this.undelete_index) { |
|
760 | if (this.undelete_index !== null && index <= this.undelete_index) { | |
761 | this.undelete_index = this.undelete_index + 1; |
|
761 | this.undelete_index = this.undelete_index + 1; | |
762 | this.set_dirty(true); |
|
762 | this.set_dirty(true); | |
763 | } |
|
763 | } | |
764 | return true; |
|
764 | return true; | |
765 | }; |
|
765 | }; | |
766 |
|
766 | |||
767 | /** |
|
767 | /** | |
768 | * Insert a cell of given type above given index, or at top |
|
768 | * Insert a cell of given type above given index, or at top | |
769 | * of notebook if index smaller than 0. |
|
769 | * of notebook if index smaller than 0. | |
770 | * |
|
770 | * | |
771 | * default index value is the one of currently selected cell |
|
771 | * default index value is the one of currently selected cell | |
772 | * |
|
772 | * | |
773 | * @method insert_cell_above |
|
773 | * @method insert_cell_above | |
774 | * @param type {string} cell type |
|
774 | * @param type {string} cell type | |
775 | * @param [index] {integer} |
|
775 | * @param [index] {integer} | |
776 | * |
|
776 | * | |
777 | * @return handle to created cell or null |
|
777 | * @return handle to created cell or null | |
778 | **/ |
|
778 | **/ | |
779 | Notebook.prototype.insert_cell_above = function (type, index) { |
|
779 | Notebook.prototype.insert_cell_above = function (type, index) { | |
780 | index = this.index_or_selected(index); |
|
780 | index = this.index_or_selected(index); | |
781 | return this.insert_cell_at_index(type, index); |
|
781 | return this.insert_cell_at_index(type, index); | |
782 | }; |
|
782 | }; | |
783 |
|
783 | |||
784 | /** |
|
784 | /** | |
785 | * Insert a cell of given type below given index, or at bottom |
|
785 | * Insert a cell of given type below given index, or at bottom | |
786 | * of notebook if index greater thatn number of cell |
|
786 | * of notebook if index greater thatn number of cell | |
787 | * |
|
787 | * | |
788 | * default index value is the one of currently selected cell |
|
788 | * default index value is the one of currently selected cell | |
789 | * |
|
789 | * | |
790 | * @method insert_cell_below |
|
790 | * @method insert_cell_below | |
791 | * @param type {string} cell type |
|
791 | * @param type {string} cell type | |
792 | * @param [index] {integer} |
|
792 | * @param [index] {integer} | |
793 | * |
|
793 | * | |
794 | * @return handle to created cell or null |
|
794 | * @return handle to created cell or null | |
795 | * |
|
795 | * | |
796 | **/ |
|
796 | **/ | |
797 | Notebook.prototype.insert_cell_below = function (type, index) { |
|
797 | Notebook.prototype.insert_cell_below = function (type, index) { | |
798 | index = this.index_or_selected(index); |
|
798 | index = this.index_or_selected(index); | |
799 | return this.insert_cell_at_index(type, index+1); |
|
799 | return this.insert_cell_at_index(type, index+1); | |
800 | }; |
|
800 | }; | |
801 |
|
801 | |||
802 |
|
802 | |||
803 | /** |
|
803 | /** | |
804 | * Insert cell at end of notebook |
|
804 | * Insert cell at end of notebook | |
805 | * |
|
805 | * | |
806 | * @method insert_cell_at_bottom |
|
806 | * @method insert_cell_at_bottom | |
807 | * @param {String} type cell type |
|
807 | * @param {String} type cell type | |
808 | * |
|
808 | * | |
809 | * @return the added cell; or null |
|
809 | * @return the added cell; or null | |
810 | **/ |
|
810 | **/ | |
811 | Notebook.prototype.insert_cell_at_bottom = function (type){ |
|
811 | Notebook.prototype.insert_cell_at_bottom = function (type){ | |
812 | var len = this.ncells(); |
|
812 | var len = this.ncells(); | |
813 | return this.insert_cell_below(type,len-1); |
|
813 | return this.insert_cell_below(type,len-1); | |
814 | }; |
|
814 | }; | |
815 |
|
815 | |||
816 | /** |
|
816 | /** | |
817 | * Turn a cell into a code cell. |
|
817 | * Turn a cell into a code cell. | |
818 | * |
|
818 | * | |
819 | * @method to_code |
|
819 | * @method to_code | |
820 | * @param {Number} [index] A cell's index |
|
820 | * @param {Number} [index] A cell's index | |
821 | */ |
|
821 | */ | |
822 | Notebook.prototype.to_code = function (index) { |
|
822 | Notebook.prototype.to_code = function (index) { | |
823 | var i = this.index_or_selected(index); |
|
823 | var i = this.index_or_selected(index); | |
824 | if (this.is_valid_cell_index(i)) { |
|
824 | if (this.is_valid_cell_index(i)) { | |
825 | var source_element = this.get_cell_element(i); |
|
825 | var source_element = this.get_cell_element(i); | |
826 | var source_cell = source_element.data("cell"); |
|
826 | var source_cell = source_element.data("cell"); | |
827 | if (!(source_cell instanceof IPython.CodeCell)) { |
|
827 | if (!(source_cell instanceof IPython.CodeCell)) { | |
828 | var target_cell = this.insert_cell_below('code',i); |
|
828 | var target_cell = this.insert_cell_below('code',i); | |
829 | var text = source_cell.get_text(); |
|
829 | var text = source_cell.get_text(); | |
830 | if (text === source_cell.placeholder) { |
|
830 | if (text === source_cell.placeholder) { | |
831 | text = ''; |
|
831 | text = ''; | |
832 | } |
|
832 | } | |
833 | target_cell.set_text(text); |
|
833 | target_cell.set_text(text); | |
834 | // make this value the starting point, so that we can only undo |
|
834 | // make this value the starting point, so that we can only undo | |
835 | // to this state, instead of a blank cell |
|
835 | // to this state, instead of a blank cell | |
836 | target_cell.code_mirror.clearHistory(); |
|
836 | target_cell.code_mirror.clearHistory(); | |
837 | source_element.remove(); |
|
837 | source_element.remove(); | |
838 | this.select(i); |
|
838 | this.select(i); | |
839 | this.edit_mode(); |
|
839 | this.edit_mode(); | |
840 | this.set_dirty(true); |
|
840 | this.set_dirty(true); | |
841 | }; |
|
841 | }; | |
842 | }; |
|
842 | }; | |
843 | }; |
|
843 | }; | |
844 |
|
844 | |||
845 | /** |
|
845 | /** | |
846 | * Turn a cell into a Markdown cell. |
|
846 | * Turn a cell into a Markdown cell. | |
847 | * |
|
847 | * | |
848 | * @method to_markdown |
|
848 | * @method to_markdown | |
849 | * @param {Number} [index] A cell's index |
|
849 | * @param {Number} [index] A cell's index | |
850 | */ |
|
850 | */ | |
851 | Notebook.prototype.to_markdown = function (index) { |
|
851 | Notebook.prototype.to_markdown = function (index) { | |
852 | var i = this.index_or_selected(index); |
|
852 | var i = this.index_or_selected(index); | |
853 | if (this.is_valid_cell_index(i)) { |
|
853 | if (this.is_valid_cell_index(i)) { | |
854 | var source_element = this.get_cell_element(i); |
|
854 | var source_element = this.get_cell_element(i); | |
855 | var source_cell = source_element.data("cell"); |
|
855 | var source_cell = source_element.data("cell"); | |
856 | if (!(source_cell instanceof IPython.MarkdownCell)) { |
|
856 | if (!(source_cell instanceof IPython.MarkdownCell)) { | |
857 | var target_cell = this.insert_cell_below('markdown',i); |
|
857 | var target_cell = this.insert_cell_below('markdown',i); | |
858 | var text = source_cell.get_text(); |
|
858 | var text = source_cell.get_text(); | |
859 | if (text === source_cell.placeholder) { |
|
859 | if (text === source_cell.placeholder) { | |
860 | text = ''; |
|
860 | text = ''; | |
861 | }; |
|
861 | }; | |
862 | // We must show the editor before setting its contents |
|
862 | // We must show the editor before setting its contents | |
863 | target_cell.unrender(); |
|
863 | target_cell.unrender(); | |
864 | target_cell.set_text(text); |
|
864 | target_cell.set_text(text); | |
865 | // make this value the starting point, so that we can only undo |
|
865 | // make this value the starting point, so that we can only undo | |
866 | // to this state, instead of a blank cell |
|
866 | // to this state, instead of a blank cell | |
867 | target_cell.code_mirror.clearHistory(); |
|
867 | target_cell.code_mirror.clearHistory(); | |
868 | source_element.remove(); |
|
868 | source_element.remove(); | |
869 | this.select(i); |
|
869 | this.select(i); | |
870 | this.edit_mode(); |
|
870 | this.edit_mode(); | |
871 | this.set_dirty(true); |
|
871 | this.set_dirty(true); | |
872 | }; |
|
872 | }; | |
873 | }; |
|
873 | }; | |
874 | }; |
|
874 | }; | |
875 |
|
875 | |||
876 | /** |
|
876 | /** | |
877 | * Turn a cell into a raw text cell. |
|
877 | * Turn a cell into a raw text cell. | |
878 | * |
|
878 | * | |
879 | * @method to_raw |
|
879 | * @method to_raw | |
880 | * @param {Number} [index] A cell's index |
|
880 | * @param {Number} [index] A cell's index | |
881 | */ |
|
881 | */ | |
882 | Notebook.prototype.to_raw = function (index) { |
|
882 | Notebook.prototype.to_raw = function (index) { | |
883 | var i = this.index_or_selected(index); |
|
883 | var i = this.index_or_selected(index); | |
884 | if (this.is_valid_cell_index(i)) { |
|
884 | if (this.is_valid_cell_index(i)) { | |
885 | var source_element = this.get_cell_element(i); |
|
885 | var source_element = this.get_cell_element(i); | |
886 | var source_cell = source_element.data("cell"); |
|
886 | var source_cell = source_element.data("cell"); | |
887 | var target_cell = null; |
|
887 | var target_cell = null; | |
888 | if (!(source_cell instanceof IPython.RawCell)) { |
|
888 | if (!(source_cell instanceof IPython.RawCell)) { | |
889 | target_cell = this.insert_cell_below('raw',i); |
|
889 | target_cell = this.insert_cell_below('raw',i); | |
890 | var text = source_cell.get_text(); |
|
890 | var text = source_cell.get_text(); | |
891 | if (text === source_cell.placeholder) { |
|
891 | if (text === source_cell.placeholder) { | |
892 | text = ''; |
|
892 | text = ''; | |
893 | }; |
|
893 | }; | |
894 | // We must show the editor before setting its contents |
|
894 | // We must show the editor before setting its contents | |
895 | target_cell.unrender(); |
|
895 | target_cell.unrender(); | |
896 | target_cell.set_text(text); |
|
896 | target_cell.set_text(text); | |
897 | // make this value the starting point, so that we can only undo |
|
897 | // make this value the starting point, so that we can only undo | |
898 | // to this state, instead of a blank cell |
|
898 | // to this state, instead of a blank cell | |
899 | target_cell.code_mirror.clearHistory(); |
|
899 | target_cell.code_mirror.clearHistory(); | |
900 | source_element.remove(); |
|
900 | source_element.remove(); | |
901 | this.select(i); |
|
901 | this.select(i); | |
902 | this.edit_mode(); |
|
902 | this.edit_mode(); | |
903 | this.set_dirty(true); |
|
903 | this.set_dirty(true); | |
904 | }; |
|
904 | }; | |
905 | }; |
|
905 | }; | |
906 | }; |
|
906 | }; | |
907 |
|
907 | |||
908 | /** |
|
908 | /** | |
909 | * Turn a cell into a heading cell. |
|
909 | * Turn a cell into a heading cell. | |
910 | * |
|
910 | * | |
911 | * @method to_heading |
|
911 | * @method to_heading | |
912 | * @param {Number} [index] A cell's index |
|
912 | * @param {Number} [index] A cell's index | |
913 | * @param {Number} [level] A heading level (e.g., 1 becomes <h1>) |
|
913 | * @param {Number} [level] A heading level (e.g., 1 becomes <h1>) | |
914 | */ |
|
914 | */ | |
915 | Notebook.prototype.to_heading = function (index, level) { |
|
915 | Notebook.prototype.to_heading = function (index, level) { | |
916 | level = level || 1; |
|
916 | level = level || 1; | |
917 | var i = this.index_or_selected(index); |
|
917 | var i = this.index_or_selected(index); | |
918 | if (this.is_valid_cell_index(i)) { |
|
918 | if (this.is_valid_cell_index(i)) { | |
919 | var source_element = this.get_cell_element(i); |
|
919 | var source_element = this.get_cell_element(i); | |
920 | var source_cell = source_element.data("cell"); |
|
920 | var source_cell = source_element.data("cell"); | |
921 | var target_cell = null; |
|
921 | var target_cell = null; | |
922 | if (source_cell instanceof IPython.HeadingCell) { |
|
922 | if (source_cell instanceof IPython.HeadingCell) { | |
923 | source_cell.set_level(level); |
|
923 | source_cell.set_level(level); | |
924 | } else { |
|
924 | } else { | |
925 | target_cell = this.insert_cell_below('heading',i); |
|
925 | target_cell = this.insert_cell_below('heading',i); | |
926 | var text = source_cell.get_text(); |
|
926 | var text = source_cell.get_text(); | |
927 | if (text === source_cell.placeholder) { |
|
927 | if (text === source_cell.placeholder) { | |
928 | text = ''; |
|
928 | text = ''; | |
929 | }; |
|
929 | }; | |
930 | // We must show the editor before setting its contents |
|
930 | // We must show the editor before setting its contents | |
931 | target_cell.set_level(level); |
|
931 | target_cell.set_level(level); | |
932 | target_cell.unrender(); |
|
932 | target_cell.unrender(); | |
933 | target_cell.set_text(text); |
|
933 | target_cell.set_text(text); | |
934 | // make this value the starting point, so that we can only undo |
|
934 | // make this value the starting point, so that we can only undo | |
935 | // to this state, instead of a blank cell |
|
935 | // to this state, instead of a blank cell | |
936 | target_cell.code_mirror.clearHistory(); |
|
936 | target_cell.code_mirror.clearHistory(); | |
937 | source_element.remove(); |
|
937 | source_element.remove(); | |
938 | this.select(i); |
|
938 | this.select(i); | |
939 | }; |
|
939 | }; | |
940 | this.edit_mode(); |
|
940 | this.edit_mode(); | |
941 | this.set_dirty(true); |
|
941 | this.set_dirty(true); | |
942 | $([IPython.events]).trigger('selected_cell_type_changed.Notebook', |
|
942 | $([IPython.events]).trigger('selected_cell_type_changed.Notebook', | |
943 | {'cell_type':'heading',level:level} |
|
943 | {'cell_type':'heading',level:level} | |
944 | ); |
|
944 | ); | |
945 | }; |
|
945 | }; | |
946 | }; |
|
946 | }; | |
947 |
|
947 | |||
948 |
|
948 | |||
949 | // Cut/Copy/Paste |
|
949 | // Cut/Copy/Paste | |
950 |
|
950 | |||
951 | /** |
|
951 | /** | |
952 | * Enable UI elements for pasting cells. |
|
952 | * Enable UI elements for pasting cells. | |
953 | * |
|
953 | * | |
954 | * @method enable_paste |
|
954 | * @method enable_paste | |
955 | */ |
|
955 | */ | |
956 | Notebook.prototype.enable_paste = function () { |
|
956 | Notebook.prototype.enable_paste = function () { | |
957 | var that = this; |
|
957 | var that = this; | |
958 | if (!this.paste_enabled) { |
|
958 | if (!this.paste_enabled) { | |
959 | $('#paste_cell_replace').removeClass('disabled') |
|
959 | $('#paste_cell_replace').removeClass('disabled') | |
960 | .on('click', function () {that.paste_cell_replace();}); |
|
960 | .on('click', function () {that.paste_cell_replace();}); | |
961 | $('#paste_cell_above').removeClass('disabled') |
|
961 | $('#paste_cell_above').removeClass('disabled') | |
962 | .on('click', function () {that.paste_cell_above();}); |
|
962 | .on('click', function () {that.paste_cell_above();}); | |
963 | $('#paste_cell_below').removeClass('disabled') |
|
963 | $('#paste_cell_below').removeClass('disabled') | |
964 | .on('click', function () {that.paste_cell_below();}); |
|
964 | .on('click', function () {that.paste_cell_below();}); | |
965 | this.paste_enabled = true; |
|
965 | this.paste_enabled = true; | |
966 | }; |
|
966 | }; | |
967 | }; |
|
967 | }; | |
968 |
|
968 | |||
969 | /** |
|
969 | /** | |
970 | * Disable UI elements for pasting cells. |
|
970 | * Disable UI elements for pasting cells. | |
971 | * |
|
971 | * | |
972 | * @method disable_paste |
|
972 | * @method disable_paste | |
973 | */ |
|
973 | */ | |
974 | Notebook.prototype.disable_paste = function () { |
|
974 | Notebook.prototype.disable_paste = function () { | |
975 | if (this.paste_enabled) { |
|
975 | if (this.paste_enabled) { | |
976 | $('#paste_cell_replace').addClass('disabled').off('click'); |
|
976 | $('#paste_cell_replace').addClass('disabled').off('click'); | |
977 | $('#paste_cell_above').addClass('disabled').off('click'); |
|
977 | $('#paste_cell_above').addClass('disabled').off('click'); | |
978 | $('#paste_cell_below').addClass('disabled').off('click'); |
|
978 | $('#paste_cell_below').addClass('disabled').off('click'); | |
979 | this.paste_enabled = false; |
|
979 | this.paste_enabled = false; | |
980 | }; |
|
980 | }; | |
981 | }; |
|
981 | }; | |
982 |
|
982 | |||
983 | /** |
|
983 | /** | |
984 | * Cut a cell. |
|
984 | * Cut a cell. | |
985 | * |
|
985 | * | |
986 | * @method cut_cell |
|
986 | * @method cut_cell | |
987 | */ |
|
987 | */ | |
988 | Notebook.prototype.cut_cell = function () { |
|
988 | Notebook.prototype.cut_cell = function () { | |
989 | this.copy_cell(); |
|
989 | this.copy_cell(); | |
990 | this.delete_cell(); |
|
990 | this.delete_cell(); | |
991 | } |
|
991 | } | |
992 |
|
992 | |||
993 | /** |
|
993 | /** | |
994 | * Copy a cell. |
|
994 | * Copy a cell. | |
995 | * |
|
995 | * | |
996 | * @method copy_cell |
|
996 | * @method copy_cell | |
997 | */ |
|
997 | */ | |
998 | Notebook.prototype.copy_cell = function () { |
|
998 | Notebook.prototype.copy_cell = function () { | |
999 | var cell = this.get_selected_cell(); |
|
999 | var cell = this.get_selected_cell(); | |
1000 | this.clipboard = cell.toJSON(); |
|
1000 | this.clipboard = cell.toJSON(); | |
1001 | this.enable_paste(); |
|
1001 | this.enable_paste(); | |
1002 | }; |
|
1002 | }; | |
1003 |
|
1003 | |||
1004 | /** |
|
1004 | /** | |
1005 | * Replace the selected cell with a cell in the clipboard. |
|
1005 | * Replace the selected cell with a cell in the clipboard. | |
1006 | * |
|
1006 | * | |
1007 | * @method paste_cell_replace |
|
1007 | * @method paste_cell_replace | |
1008 | */ |
|
1008 | */ | |
1009 | Notebook.prototype.paste_cell_replace = function () { |
|
1009 | Notebook.prototype.paste_cell_replace = function () { | |
1010 | if (this.clipboard !== null && this.paste_enabled) { |
|
1010 | if (this.clipboard !== null && this.paste_enabled) { | |
1011 | var cell_data = this.clipboard; |
|
1011 | var cell_data = this.clipboard; | |
1012 | var new_cell = this.insert_cell_above(cell_data.cell_type); |
|
1012 | var new_cell = this.insert_cell_above(cell_data.cell_type); | |
1013 | new_cell.fromJSON(cell_data); |
|
1013 | new_cell.fromJSON(cell_data); | |
1014 | var old_cell = this.get_next_cell(new_cell); |
|
1014 | var old_cell = this.get_next_cell(new_cell); | |
1015 | this.delete_cell(this.find_cell_index(old_cell)); |
|
1015 | this.delete_cell(this.find_cell_index(old_cell)); | |
1016 | this.select(this.find_cell_index(new_cell)); |
|
1016 | this.select(this.find_cell_index(new_cell)); | |
1017 | }; |
|
1017 | }; | |
1018 | }; |
|
1018 | }; | |
1019 |
|
1019 | |||
1020 | /** |
|
1020 | /** | |
1021 | * Paste a cell from the clipboard above the selected cell. |
|
1021 | * Paste a cell from the clipboard above the selected cell. | |
1022 | * |
|
1022 | * | |
1023 | * @method paste_cell_above |
|
1023 | * @method paste_cell_above | |
1024 | */ |
|
1024 | */ | |
1025 | Notebook.prototype.paste_cell_above = function () { |
|
1025 | Notebook.prototype.paste_cell_above = function () { | |
1026 | if (this.clipboard !== null && this.paste_enabled) { |
|
1026 | if (this.clipboard !== null && this.paste_enabled) { | |
1027 | var cell_data = this.clipboard; |
|
1027 | var cell_data = this.clipboard; | |
1028 | var new_cell = this.insert_cell_above(cell_data.cell_type); |
|
1028 | var new_cell = this.insert_cell_above(cell_data.cell_type); | |
1029 | new_cell.fromJSON(cell_data); |
|
1029 | new_cell.fromJSON(cell_data); | |
1030 | }; |
|
1030 | }; | |
1031 | }; |
|
1031 | }; | |
1032 |
|
1032 | |||
1033 | /** |
|
1033 | /** | |
1034 | * Paste a cell from the clipboard below the selected cell. |
|
1034 | * Paste a cell from the clipboard below the selected cell. | |
1035 | * |
|
1035 | * | |
1036 | * @method paste_cell_below |
|
1036 | * @method paste_cell_below | |
1037 | */ |
|
1037 | */ | |
1038 | Notebook.prototype.paste_cell_below = function () { |
|
1038 | Notebook.prototype.paste_cell_below = function () { | |
1039 | if (this.clipboard !== null && this.paste_enabled) { |
|
1039 | if (this.clipboard !== null && this.paste_enabled) { | |
1040 | var cell_data = this.clipboard; |
|
1040 | var cell_data = this.clipboard; | |
1041 | var new_cell = this.insert_cell_below(cell_data.cell_type); |
|
1041 | var new_cell = this.insert_cell_below(cell_data.cell_type); | |
1042 | new_cell.fromJSON(cell_data); |
|
1042 | new_cell.fromJSON(cell_data); | |
1043 | }; |
|
1043 | }; | |
1044 | }; |
|
1044 | }; | |
1045 |
|
1045 | |||
1046 | // Split/merge |
|
1046 | // Split/merge | |
1047 |
|
1047 | |||
1048 | /** |
|
1048 | /** | |
1049 | * Split the selected cell into two, at the cursor. |
|
1049 | * Split the selected cell into two, at the cursor. | |
1050 | * |
|
1050 | * | |
1051 | * @method split_cell |
|
1051 | * @method split_cell | |
1052 | */ |
|
1052 | */ | |
1053 | Notebook.prototype.split_cell = function () { |
|
1053 | Notebook.prototype.split_cell = function () { | |
1054 | var mdc = IPython.MarkdownCell; |
|
1054 | var mdc = IPython.MarkdownCell; | |
1055 | var rc = IPython.RawCell; |
|
1055 | var rc = IPython.RawCell; | |
1056 | var cell = this.get_selected_cell(); |
|
1056 | var cell = this.get_selected_cell(); | |
1057 | if (cell.is_splittable()) { |
|
1057 | if (cell.is_splittable()) { | |
1058 | var texta = cell.get_pre_cursor(); |
|
1058 | var texta = cell.get_pre_cursor(); | |
1059 | var textb = cell.get_post_cursor(); |
|
1059 | var textb = cell.get_post_cursor(); | |
1060 | if (cell instanceof IPython.CodeCell) { |
|
1060 | if (cell instanceof IPython.CodeCell) { | |
1061 | // In this case the operations keep the notebook in its existing mode |
|
1061 | // In this case the operations keep the notebook in its existing mode | |
1062 | // so we don't need to do any post-op mode changes. |
|
1062 | // so we don't need to do any post-op mode changes. | |
1063 | cell.set_text(textb); |
|
1063 | cell.set_text(textb); | |
1064 | var new_cell = this.insert_cell_above('code'); |
|
1064 | var new_cell = this.insert_cell_above('code'); | |
1065 | new_cell.set_text(texta); |
|
1065 | new_cell.set_text(texta); | |
1066 | } else if ((cell instanceof mdc && !cell.rendered) || (cell instanceof rc)) { |
|
1066 | } else if ((cell instanceof mdc && !cell.rendered) || (cell instanceof rc)) { | |
1067 | // We know cell is !rendered so we can use set_text. |
|
1067 | // We know cell is !rendered so we can use set_text. | |
1068 | cell.set_text(textb); |
|
1068 | cell.set_text(textb); | |
1069 | var new_cell = this.insert_cell_above(cell.cell_type); |
|
1069 | var new_cell = this.insert_cell_above(cell.cell_type); | |
1070 | // Unrender the new cell so we can call set_text. |
|
1070 | // Unrender the new cell so we can call set_text. | |
1071 | new_cell.unrender(); |
|
1071 | new_cell.unrender(); | |
1072 | new_cell.set_text(texta); |
|
1072 | new_cell.set_text(texta); | |
1073 | } |
|
1073 | } | |
1074 | }; |
|
1074 | }; | |
1075 | }; |
|
1075 | }; | |
1076 |
|
1076 | |||
1077 | /** |
|
1077 | /** | |
1078 | * Combine the selected cell into the cell above it. |
|
1078 | * Combine the selected cell into the cell above it. | |
1079 | * |
|
1079 | * | |
1080 | * @method merge_cell_above |
|
1080 | * @method merge_cell_above | |
1081 | */ |
|
1081 | */ | |
1082 | Notebook.prototype.merge_cell_above = function () { |
|
1082 | Notebook.prototype.merge_cell_above = function () { | |
1083 | var mdc = IPython.MarkdownCell; |
|
1083 | var mdc = IPython.MarkdownCell; | |
1084 | var rc = IPython.RawCell; |
|
1084 | var rc = IPython.RawCell; | |
1085 | var index = this.get_selected_index(); |
|
1085 | var index = this.get_selected_index(); | |
1086 | var cell = this.get_cell(index); |
|
1086 | var cell = this.get_cell(index); | |
1087 | var render = cell.rendered; |
|
1087 | var render = cell.rendered; | |
1088 | if (!cell.is_mergeable()) { |
|
1088 | if (!cell.is_mergeable()) { | |
1089 | return; |
|
1089 | return; | |
1090 | } |
|
1090 | } | |
1091 | if (index > 0) { |
|
1091 | if (index > 0) { | |
1092 | var upper_cell = this.get_cell(index-1); |
|
1092 | var upper_cell = this.get_cell(index-1); | |
1093 | if (!upper_cell.is_mergeable()) { |
|
1093 | if (!upper_cell.is_mergeable()) { | |
1094 | return; |
|
1094 | return; | |
1095 | } |
|
1095 | } | |
1096 | var upper_text = upper_cell.get_text(); |
|
1096 | var upper_text = upper_cell.get_text(); | |
1097 | var text = cell.get_text(); |
|
1097 | var text = cell.get_text(); | |
1098 | if (cell instanceof IPython.CodeCell) { |
|
1098 | if (cell instanceof IPython.CodeCell) { | |
1099 | cell.set_text(upper_text+'\n'+text); |
|
1099 | cell.set_text(upper_text+'\n'+text); | |
1100 | } else if ((cell instanceof mdc) || (cell instanceof rc)) { |
|
1100 | } else if ((cell instanceof mdc) || (cell instanceof rc)) { | |
1101 | cell.unrender(); // Must unrender before we set_text. |
|
1101 | cell.unrender(); // Must unrender before we set_text. | |
1102 | cell.set_text(upper_text+'\n\n'+text); |
|
1102 | cell.set_text(upper_text+'\n\n'+text); | |
1103 | if (render) { |
|
1103 | if (render) { | |
1104 | // The rendered state of the final cell should match |
|
1104 | // The rendered state of the final cell should match | |
1105 | // that of the original selected cell; |
|
1105 | // that of the original selected cell; | |
1106 | cell.render(); |
|
1106 | cell.render(); | |
1107 | } |
|
1107 | } | |
1108 | }; |
|
1108 | }; | |
1109 | this.delete_cell(index-1); |
|
1109 | this.delete_cell(index-1); | |
1110 | this.select(this.find_cell_index(cell)); |
|
1110 | this.select(this.find_cell_index(cell)); | |
1111 | }; |
|
1111 | }; | |
1112 | }; |
|
1112 | }; | |
1113 |
|
1113 | |||
1114 | /** |
|
1114 | /** | |
1115 | * Combine the selected cell into the cell below it. |
|
1115 | * Combine the selected cell into the cell below it. | |
1116 | * |
|
1116 | * | |
1117 | * @method merge_cell_below |
|
1117 | * @method merge_cell_below | |
1118 | */ |
|
1118 | */ | |
1119 | Notebook.prototype.merge_cell_below = function () { |
|
1119 | Notebook.prototype.merge_cell_below = function () { | |
1120 | var mdc = IPython.MarkdownCell; |
|
1120 | var mdc = IPython.MarkdownCell; | |
1121 | var rc = IPython.RawCell; |
|
1121 | var rc = IPython.RawCell; | |
1122 | var index = this.get_selected_index(); |
|
1122 | var index = this.get_selected_index(); | |
1123 | var cell = this.get_cell(index); |
|
1123 | var cell = this.get_cell(index); | |
1124 | var render = cell.rendered; |
|
1124 | var render = cell.rendered; | |
1125 | if (!cell.is_mergeable()) { |
|
1125 | if (!cell.is_mergeable()) { | |
1126 | return; |
|
1126 | return; | |
1127 | } |
|
1127 | } | |
1128 | if (index < this.ncells()-1) { |
|
1128 | if (index < this.ncells()-1) { | |
1129 | var lower_cell = this.get_cell(index+1); |
|
1129 | var lower_cell = this.get_cell(index+1); | |
1130 | if (!lower_cell.is_mergeable()) { |
|
1130 | if (!lower_cell.is_mergeable()) { | |
1131 | return; |
|
1131 | return; | |
1132 | } |
|
1132 | } | |
1133 | var lower_text = lower_cell.get_text(); |
|
1133 | var lower_text = lower_cell.get_text(); | |
1134 | var text = cell.get_text(); |
|
1134 | var text = cell.get_text(); | |
1135 | if (cell instanceof IPython.CodeCell) { |
|
1135 | if (cell instanceof IPython.CodeCell) { | |
1136 | cell.set_text(text+'\n'+lower_text); |
|
1136 | cell.set_text(text+'\n'+lower_text); | |
1137 | } else if ((cell instanceof mdc) || (cell instanceof rc)) { |
|
1137 | } else if ((cell instanceof mdc) || (cell instanceof rc)) { | |
1138 | cell.unrender(); // Must unrender before we set_text. |
|
1138 | cell.unrender(); // Must unrender before we set_text. | |
1139 | cell.set_text(text+'\n\n'+lower_text); |
|
1139 | cell.set_text(text+'\n\n'+lower_text); | |
1140 | if (render) { |
|
1140 | if (render) { | |
1141 | // The rendered state of the final cell should match |
|
1141 | // The rendered state of the final cell should match | |
1142 | // that of the original selected cell; |
|
1142 | // that of the original selected cell; | |
1143 | cell.render(); |
|
1143 | cell.render(); | |
1144 | } |
|
1144 | } | |
1145 | }; |
|
1145 | }; | |
1146 | this.delete_cell(index+1); |
|
1146 | this.delete_cell(index+1); | |
1147 | this.select(this.find_cell_index(cell)); |
|
1147 | this.select(this.find_cell_index(cell)); | |
1148 | }; |
|
1148 | }; | |
1149 | }; |
|
1149 | }; | |
1150 |
|
1150 | |||
1151 |
|
1151 | |||
1152 | // Cell collapsing and output clearing |
|
1152 | // Cell collapsing and output clearing | |
1153 |
|
1153 | |||
1154 | /** |
|
1154 | /** | |
1155 | * Hide a cell's output. |
|
1155 | * Hide a cell's output. | |
1156 | * |
|
1156 | * | |
1157 | * @method collapse |
|
1157 | * @method collapse | |
1158 | * @param {Number} index A cell's numeric index |
|
1158 | * @param {Number} index A cell's numeric index | |
1159 | */ |
|
1159 | */ | |
1160 | Notebook.prototype.collapse = function (index) { |
|
1160 | Notebook.prototype.collapse = function (index) { | |
1161 | var i = this.index_or_selected(index); |
|
1161 | var i = this.index_or_selected(index); | |
1162 | this.get_cell(i).collapse(); |
|
1162 | this.get_cell(i).collapse(); | |
1163 | this.set_dirty(true); |
|
1163 | this.set_dirty(true); | |
1164 | }; |
|
1164 | }; | |
1165 |
|
1165 | |||
1166 | /** |
|
1166 | /** | |
1167 | * Show a cell's output. |
|
1167 | * Show a cell's output. | |
1168 | * |
|
1168 | * | |
1169 | * @method expand |
|
1169 | * @method expand | |
1170 | * @param {Number} index A cell's numeric index |
|
1170 | * @param {Number} index A cell's numeric index | |
1171 | */ |
|
1171 | */ | |
1172 | Notebook.prototype.expand = function (index) { |
|
1172 | Notebook.prototype.expand = function (index) { | |
1173 | var i = this.index_or_selected(index); |
|
1173 | var i = this.index_or_selected(index); | |
1174 | this.get_cell(i).expand(); |
|
1174 | this.get_cell(i).expand(); | |
1175 | this.set_dirty(true); |
|
1175 | this.set_dirty(true); | |
1176 | }; |
|
1176 | }; | |
1177 |
|
1177 | |||
1178 | /** Toggle whether a cell's output is collapsed or expanded. |
|
1178 | /** Toggle whether a cell's output is collapsed or expanded. | |
1179 | * |
|
1179 | * | |
1180 | * @method toggle_output |
|
1180 | * @method toggle_output | |
1181 | * @param {Number} index A cell's numeric index |
|
1181 | * @param {Number} index A cell's numeric index | |
1182 | */ |
|
1182 | */ | |
1183 | Notebook.prototype.toggle_output = function (index) { |
|
1183 | Notebook.prototype.toggle_output = function (index) { | |
1184 | var i = this.index_or_selected(index); |
|
1184 | var i = this.index_or_selected(index); | |
1185 | this.get_cell(i).toggle_output(); |
|
1185 | this.get_cell(i).toggle_output(); | |
1186 | this.set_dirty(true); |
|
1186 | this.set_dirty(true); | |
1187 | }; |
|
1187 | }; | |
1188 |
|
1188 | |||
1189 | /** |
|
1189 | /** | |
1190 | * Toggle a scrollbar for long cell outputs. |
|
1190 | * Toggle a scrollbar for long cell outputs. | |
1191 | * |
|
1191 | * | |
1192 | * @method toggle_output_scroll |
|
1192 | * @method toggle_output_scroll | |
1193 | * @param {Number} index A cell's numeric index |
|
1193 | * @param {Number} index A cell's numeric index | |
1194 | */ |
|
1194 | */ | |
1195 | Notebook.prototype.toggle_output_scroll = function (index) { |
|
1195 | Notebook.prototype.toggle_output_scroll = function (index) { | |
1196 | var i = this.index_or_selected(index); |
|
1196 | var i = this.index_or_selected(index); | |
1197 | this.get_cell(i).toggle_output_scroll(); |
|
1197 | this.get_cell(i).toggle_output_scroll(); | |
1198 | }; |
|
1198 | }; | |
1199 |
|
1199 | |||
1200 | /** |
|
1200 | /** | |
1201 | * Hide each code cell's output area. |
|
1201 | * Hide each code cell's output area. | |
1202 | * |
|
1202 | * | |
1203 | * @method collapse_all_output |
|
1203 | * @method collapse_all_output | |
1204 | */ |
|
1204 | */ | |
1205 | Notebook.prototype.collapse_all_output = function () { |
|
1205 | Notebook.prototype.collapse_all_output = function () { | |
1206 | var ncells = this.ncells(); |
|
1206 | var ncells = this.ncells(); | |
1207 | var cells = this.get_cells(); |
|
1207 | var cells = this.get_cells(); | |
1208 | for (var i=0; i<ncells; i++) { |
|
1208 | for (var i=0; i<ncells; i++) { | |
1209 | if (cells[i] instanceof IPython.CodeCell) { |
|
1209 | if (cells[i] instanceof IPython.CodeCell) { | |
1210 | cells[i].output_area.collapse(); |
|
1210 | cells[i].output_area.collapse(); | |
1211 | } |
|
1211 | } | |
1212 | }; |
|
1212 | }; | |
1213 | // this should not be set if the `collapse` key is removed from nbformat |
|
1213 | // this should not be set if the `collapse` key is removed from nbformat | |
1214 | this.set_dirty(true); |
|
1214 | this.set_dirty(true); | |
1215 | }; |
|
1215 | }; | |
1216 |
|
1216 | |||
1217 | /** |
|
1217 | /** | |
1218 | * Expand each code cell's output area, and add a scrollbar for long output. |
|
1218 | * Expand each code cell's output area, and add a scrollbar for long output. | |
1219 | * |
|
1219 | * | |
1220 | * @method scroll_all_output |
|
1220 | * @method scroll_all_output | |
1221 | */ |
|
1221 | */ | |
1222 | Notebook.prototype.scroll_all_output = function () { |
|
1222 | Notebook.prototype.scroll_all_output = function () { | |
1223 | var ncells = this.ncells(); |
|
1223 | var ncells = this.ncells(); | |
1224 | var cells = this.get_cells(); |
|
1224 | var cells = this.get_cells(); | |
1225 | for (var i=0; i<ncells; i++) { |
|
1225 | for (var i=0; i<ncells; i++) { | |
1226 | if (cells[i] instanceof IPython.CodeCell) { |
|
1226 | if (cells[i] instanceof IPython.CodeCell) { | |
1227 | cells[i].output_area.expand(); |
|
1227 | cells[i].output_area.expand(); | |
1228 | cells[i].output_area.scroll_if_long(); |
|
1228 | cells[i].output_area.scroll_if_long(); | |
1229 | } |
|
1229 | } | |
1230 | }; |
|
1230 | }; | |
1231 | // this should not be set if the `collapse` key is removed from nbformat |
|
1231 | // this should not be set if the `collapse` key is removed from nbformat | |
1232 | this.set_dirty(true); |
|
1232 | this.set_dirty(true); | |
1233 | }; |
|
1233 | }; | |
1234 |
|
1234 | |||
1235 | /** |
|
1235 | /** | |
1236 | * Expand each code cell's output area, and remove scrollbars. |
|
1236 | * Expand each code cell's output area, and remove scrollbars. | |
1237 | * |
|
1237 | * | |
1238 | * @method expand_all_output |
|
1238 | * @method expand_all_output | |
1239 | */ |
|
1239 | */ | |
1240 | Notebook.prototype.expand_all_output = function () { |
|
1240 | Notebook.prototype.expand_all_output = function () { | |
1241 | var ncells = this.ncells(); |
|
1241 | var ncells = this.ncells(); | |
1242 | var cells = this.get_cells(); |
|
1242 | var cells = this.get_cells(); | |
1243 | for (var i=0; i<ncells; i++) { |
|
1243 | for (var i=0; i<ncells; i++) { | |
1244 | if (cells[i] instanceof IPython.CodeCell) { |
|
1244 | if (cells[i] instanceof IPython.CodeCell) { | |
1245 | cells[i].output_area.expand(); |
|
1245 | cells[i].output_area.expand(); | |
1246 | cells[i].output_area.unscroll_area(); |
|
1246 | cells[i].output_area.unscroll_area(); | |
1247 | } |
|
1247 | } | |
1248 | }; |
|
1248 | }; | |
1249 | // this should not be set if the `collapse` key is removed from nbformat |
|
1249 | // this should not be set if the `collapse` key is removed from nbformat | |
1250 | this.set_dirty(true); |
|
1250 | this.set_dirty(true); | |
1251 | }; |
|
1251 | }; | |
1252 |
|
1252 | |||
1253 | /** |
|
1253 | /** | |
1254 | * Clear each code cell's output area. |
|
1254 | * Clear each code cell's output area. | |
1255 | * |
|
1255 | * | |
1256 | * @method clear_all_output |
|
1256 | * @method clear_all_output | |
1257 | */ |
|
1257 | */ | |
1258 | Notebook.prototype.clear_all_output = function () { |
|
1258 | Notebook.prototype.clear_all_output = function () { | |
1259 | var ncells = this.ncells(); |
|
1259 | var ncells = this.ncells(); | |
1260 | var cells = this.get_cells(); |
|
1260 | var cells = this.get_cells(); | |
1261 | for (var i=0; i<ncells; i++) { |
|
1261 | for (var i=0; i<ncells; i++) { | |
1262 | if (cells[i] instanceof IPython.CodeCell) { |
|
1262 | if (cells[i] instanceof IPython.CodeCell) { | |
1263 | cells[i].clear_output(); |
|
1263 | cells[i].clear_output(); | |
1264 | // Make all In[] prompts blank, as well |
|
1264 | // Make all In[] prompts blank, as well | |
1265 | // TODO: make this configurable (via checkbox?) |
|
1265 | // TODO: make this configurable (via checkbox?) | |
1266 | cells[i].set_input_prompt(); |
|
1266 | cells[i].set_input_prompt(); | |
1267 | } |
|
1267 | } | |
1268 | }; |
|
1268 | }; | |
1269 | this.set_dirty(true); |
|
1269 | this.set_dirty(true); | |
1270 | }; |
|
1270 | }; | |
1271 |
|
1271 | |||
1272 |
|
1272 | |||
1273 | // Other cell functions: line numbers, ... |
|
1273 | // Other cell functions: line numbers, ... | |
1274 |
|
1274 | |||
1275 | /** |
|
1275 | /** | |
1276 | * Toggle line numbers in the selected cell's input area. |
|
1276 | * Toggle line numbers in the selected cell's input area. | |
1277 | * |
|
1277 | * | |
1278 | * @method cell_toggle_line_numbers |
|
1278 | * @method cell_toggle_line_numbers | |
1279 | */ |
|
1279 | */ | |
1280 | Notebook.prototype.cell_toggle_line_numbers = function() { |
|
1280 | Notebook.prototype.cell_toggle_line_numbers = function() { | |
1281 | this.get_selected_cell().toggle_line_numbers(); |
|
1281 | this.get_selected_cell().toggle_line_numbers(); | |
1282 | }; |
|
1282 | }; | |
1283 |
|
1283 | |||
1284 | // Session related things |
|
1284 | // Session related things | |
1285 |
|
1285 | |||
1286 | /** |
|
1286 | /** | |
1287 | * Start a new session and set it on each code cell. |
|
1287 | * Start a new session and set it on each code cell. | |
1288 | * |
|
1288 | * | |
1289 | * @method start_session |
|
1289 | * @method start_session | |
1290 | */ |
|
1290 | */ | |
1291 | Notebook.prototype.start_session = function () { |
|
1291 | Notebook.prototype.start_session = function () { | |
1292 | this.session = new IPython.Session(this.notebook_name, this.notebook_path, this); |
|
1292 | this.session = new IPython.Session(this.notebook_name, this.notebook_path, this); | |
1293 | this.session.start($.proxy(this._session_started, this)); |
|
1293 | this.session.start($.proxy(this._session_started, this)); | |
1294 | }; |
|
1294 | }; | |
1295 |
|
1295 | |||
1296 |
|
1296 | |||
1297 | /** |
|
1297 | /** | |
1298 | * Once a session is started, link the code cells to the kernel |
|
1298 | * Once a session is started, link the code cells to the kernel and pass the | |
|
1299 | * comm manager to the widget manager | |||
1299 | * |
|
1300 | * | |
1300 | */ |
|
1301 | */ | |
1301 | Notebook.prototype._session_started = function(){ |
|
1302 | Notebook.prototype._session_started = function(){ | |
1302 | this.kernel = this.session.kernel; |
|
1303 | this.kernel = this.session.kernel; | |
|
1304 | IPython.widget_manager.attach_comm_manager(this.kernel.comm_manager); | |||
1303 | var ncells = this.ncells(); |
|
1305 | var ncells = this.ncells(); | |
1304 | for (var i=0; i<ncells; i++) { |
|
1306 | for (var i=0; i<ncells; i++) { | |
1305 | var cell = this.get_cell(i); |
|
1307 | var cell = this.get_cell(i); | |
1306 | if (cell instanceof IPython.CodeCell) { |
|
1308 | if (cell instanceof IPython.CodeCell) { | |
1307 | cell.set_kernel(this.session.kernel); |
|
1309 | cell.set_kernel(this.session.kernel); | |
1308 | }; |
|
1310 | }; | |
1309 | }; |
|
1311 | }; | |
1310 | }; |
|
1312 | }; | |
1311 |
|
1313 | |||
1312 | /** |
|
1314 | /** | |
1313 | * Prompt the user to restart the IPython kernel. |
|
1315 | * Prompt the user to restart the IPython kernel. | |
1314 | * |
|
1316 | * | |
1315 | * @method restart_kernel |
|
1317 | * @method restart_kernel | |
1316 | */ |
|
1318 | */ | |
1317 | Notebook.prototype.restart_kernel = function () { |
|
1319 | Notebook.prototype.restart_kernel = function () { | |
1318 | var that = this; |
|
1320 | var that = this; | |
1319 | IPython.dialog.modal({ |
|
1321 | IPython.dialog.modal({ | |
1320 | title : "Restart kernel or continue running?", |
|
1322 | title : "Restart kernel or continue running?", | |
1321 | body : $("<p/>").html( |
|
1323 | body : $("<p/>").html( | |
1322 | 'Do you want to restart the current kernel? You will lose all variables defined in it.' |
|
1324 | 'Do you want to restart the current kernel? You will lose all variables defined in it.' | |
1323 | ), |
|
1325 | ), | |
1324 | buttons : { |
|
1326 | buttons : { | |
1325 | "Continue running" : {}, |
|
1327 | "Continue running" : {}, | |
1326 | "Restart" : { |
|
1328 | "Restart" : { | |
1327 | "class" : "btn-danger", |
|
1329 | "class" : "btn-danger", | |
1328 | "click" : function() { |
|
1330 | "click" : function() { | |
1329 | that.session.restart_kernel(); |
|
1331 | that.session.restart_kernel(); | |
1330 | } |
|
1332 | } | |
1331 | } |
|
1333 | } | |
1332 | } |
|
1334 | } | |
1333 | }); |
|
1335 | }); | |
1334 | }; |
|
1336 | }; | |
1335 |
|
1337 | |||
1336 | /** |
|
1338 | /** | |
1337 | * Execute or render cell outputs and go into command mode. |
|
1339 | * Execute or render cell outputs and go into command mode. | |
1338 | * |
|
1340 | * | |
1339 | * @method execute_cell |
|
1341 | * @method execute_cell | |
1340 | */ |
|
1342 | */ | |
1341 | Notebook.prototype.execute_cell = function () { |
|
1343 | Notebook.prototype.execute_cell = function () { | |
1342 | // mode = shift, ctrl, alt |
|
1344 | // mode = shift, ctrl, alt | |
1343 | var cell = this.get_selected_cell(); |
|
1345 | var cell = this.get_selected_cell(); | |
1344 | var cell_index = this.find_cell_index(cell); |
|
1346 | var cell_index = this.find_cell_index(cell); | |
1345 |
|
1347 | |||
1346 | cell.execute(); |
|
1348 | cell.execute(); | |
1347 | this.command_mode(); |
|
1349 | this.command_mode(); | |
1348 | cell.focus_cell(); |
|
1350 | cell.focus_cell(); | |
1349 | this.set_dirty(true); |
|
1351 | this.set_dirty(true); | |
1350 | } |
|
1352 | } | |
1351 |
|
1353 | |||
1352 | /** |
|
1354 | /** | |
1353 | * Execute or render cell outputs and insert a new cell below. |
|
1355 | * Execute or render cell outputs and insert a new cell below. | |
1354 | * |
|
1356 | * | |
1355 | * @method execute_cell_and_insert_below |
|
1357 | * @method execute_cell_and_insert_below | |
1356 | */ |
|
1358 | */ | |
1357 | Notebook.prototype.execute_cell_and_insert_below = function () { |
|
1359 | Notebook.prototype.execute_cell_and_insert_below = function () { | |
1358 | var cell = this.get_selected_cell(); |
|
1360 | var cell = this.get_selected_cell(); | |
1359 | var cell_index = this.find_cell_index(cell); |
|
1361 | var cell_index = this.find_cell_index(cell); | |
1360 |
|
1362 | |||
1361 | cell.execute(); |
|
1363 | cell.execute(); | |
1362 |
|
1364 | |||
1363 | // If we are at the end always insert a new cell and return |
|
1365 | // If we are at the end always insert a new cell and return | |
1364 | if (cell_index === (this.ncells()-1)) { |
|
1366 | if (cell_index === (this.ncells()-1)) { | |
1365 | this.insert_cell_below('code'); |
|
1367 | this.insert_cell_below('code'); | |
1366 | this.select(cell_index+1); |
|
1368 | this.select(cell_index+1); | |
1367 | this.edit_mode(); |
|
1369 | this.edit_mode(); | |
1368 | this.scroll_to_bottom(); |
|
1370 | this.scroll_to_bottom(); | |
1369 | this.set_dirty(true); |
|
1371 | this.set_dirty(true); | |
1370 | return; |
|
1372 | return; | |
1371 | } |
|
1373 | } | |
1372 |
|
1374 | |||
1373 | // Only insert a new cell, if we ended up in an already populated cell |
|
1375 | // Only insert a new cell, if we ended up in an already populated cell | |
1374 | var next_text = this.get_cell(cell_index+1).get_text(); |
|
1376 | var next_text = this.get_cell(cell_index+1).get_text(); | |
1375 | if (/\S/.test(next_text) === true) { |
|
1377 | if (/\S/.test(next_text) === true) { | |
1376 | this.insert_cell_below('code'); |
|
1378 | this.insert_cell_below('code'); | |
1377 | } |
|
1379 | } | |
1378 | this.select(cell_index+1); |
|
1380 | this.select(cell_index+1); | |
1379 | this.edit_mode(); |
|
1381 | this.edit_mode(); | |
1380 | this.set_dirty(true); |
|
1382 | this.set_dirty(true); | |
1381 | }; |
|
1383 | }; | |
1382 |
|
1384 | |||
1383 | /** |
|
1385 | /** | |
1384 | * Execute or render cell outputs and select the next cell. |
|
1386 | * Execute or render cell outputs and select the next cell. | |
1385 | * |
|
1387 | * | |
1386 | * @method execute_cell_and_select_below |
|
1388 | * @method execute_cell_and_select_below | |
1387 | */ |
|
1389 | */ | |
1388 | Notebook.prototype.execute_cell_and_select_below = function () { |
|
1390 | Notebook.prototype.execute_cell_and_select_below = function () { | |
1389 |
|
1391 | |||
1390 | var cell = this.get_selected_cell(); |
|
1392 | var cell = this.get_selected_cell(); | |
1391 | var cell_index = this.find_cell_index(cell); |
|
1393 | var cell_index = this.find_cell_index(cell); | |
1392 |
|
1394 | |||
1393 | cell.execute(); |
|
1395 | cell.execute(); | |
1394 |
|
1396 | |||
1395 | // If we are at the end always insert a new cell and return |
|
1397 | // If we are at the end always insert a new cell and return | |
1396 | if (cell_index === (this.ncells()-1)) { |
|
1398 | if (cell_index === (this.ncells()-1)) { | |
1397 | this.insert_cell_below('code'); |
|
1399 | this.insert_cell_below('code'); | |
1398 | this.select(cell_index+1); |
|
1400 | this.select(cell_index+1); | |
1399 | this.edit_mode(); |
|
1401 | this.edit_mode(); | |
1400 | this.scroll_to_bottom(); |
|
1402 | this.scroll_to_bottom(); | |
1401 | this.set_dirty(true); |
|
1403 | this.set_dirty(true); | |
1402 | return; |
|
1404 | return; | |
1403 | } |
|
1405 | } | |
1404 |
|
1406 | |||
1405 | this.select(cell_index+1); |
|
1407 | this.select(cell_index+1); | |
1406 | this.get_cell(cell_index+1).focus_cell(); |
|
1408 | this.get_cell(cell_index+1).focus_cell(); | |
1407 | this.set_dirty(true); |
|
1409 | this.set_dirty(true); | |
1408 | }; |
|
1410 | }; | |
1409 |
|
1411 | |||
1410 | /** |
|
1412 | /** | |
1411 | * Execute all cells below the selected cell. |
|
1413 | * Execute all cells below the selected cell. | |
1412 | * |
|
1414 | * | |
1413 | * @method execute_cells_below |
|
1415 | * @method execute_cells_below | |
1414 | */ |
|
1416 | */ | |
1415 | Notebook.prototype.execute_cells_below = function () { |
|
1417 | Notebook.prototype.execute_cells_below = function () { | |
1416 | this.execute_cell_range(this.get_selected_index(), this.ncells()); |
|
1418 | this.execute_cell_range(this.get_selected_index(), this.ncells()); | |
1417 | this.scroll_to_bottom(); |
|
1419 | this.scroll_to_bottom(); | |
1418 | }; |
|
1420 | }; | |
1419 |
|
1421 | |||
1420 | /** |
|
1422 | /** | |
1421 | * Execute all cells above the selected cell. |
|
1423 | * Execute all cells above the selected cell. | |
1422 | * |
|
1424 | * | |
1423 | * @method execute_cells_above |
|
1425 | * @method execute_cells_above | |
1424 | */ |
|
1426 | */ | |
1425 | Notebook.prototype.execute_cells_above = function () { |
|
1427 | Notebook.prototype.execute_cells_above = function () { | |
1426 | this.execute_cell_range(0, this.get_selected_index()); |
|
1428 | this.execute_cell_range(0, this.get_selected_index()); | |
1427 | }; |
|
1429 | }; | |
1428 |
|
1430 | |||
1429 | /** |
|
1431 | /** | |
1430 | * Execute all cells. |
|
1432 | * Execute all cells. | |
1431 | * |
|
1433 | * | |
1432 | * @method execute_all_cells |
|
1434 | * @method execute_all_cells | |
1433 | */ |
|
1435 | */ | |
1434 | Notebook.prototype.execute_all_cells = function () { |
|
1436 | Notebook.prototype.execute_all_cells = function () { | |
1435 | this.execute_cell_range(0, this.ncells()); |
|
1437 | this.execute_cell_range(0, this.ncells()); | |
1436 | this.scroll_to_bottom(); |
|
1438 | this.scroll_to_bottom(); | |
1437 | }; |
|
1439 | }; | |
1438 |
|
1440 | |||
1439 | /** |
|
1441 | /** | |
1440 | * Execute a contiguous range of cells. |
|
1442 | * Execute a contiguous range of cells. | |
1441 | * |
|
1443 | * | |
1442 | * @method execute_cell_range |
|
1444 | * @method execute_cell_range | |
1443 | * @param {Number} start Index of the first cell to execute (inclusive) |
|
1445 | * @param {Number} start Index of the first cell to execute (inclusive) | |
1444 | * @param {Number} end Index of the last cell to execute (exclusive) |
|
1446 | * @param {Number} end Index of the last cell to execute (exclusive) | |
1445 | */ |
|
1447 | */ | |
1446 | Notebook.prototype.execute_cell_range = function (start, end) { |
|
1448 | Notebook.prototype.execute_cell_range = function (start, end) { | |
1447 | for (var i=start; i<end; i++) { |
|
1449 | for (var i=start; i<end; i++) { | |
1448 | this.select(i); |
|
1450 | this.select(i); | |
1449 | this.execute_cell(); |
|
1451 | this.execute_cell(); | |
1450 | }; |
|
1452 | }; | |
1451 | }; |
|
1453 | }; | |
1452 |
|
1454 | |||
1453 | // Persistance and loading |
|
1455 | // Persistance and loading | |
1454 |
|
1456 | |||
1455 | /** |
|
1457 | /** | |
1456 | * Getter method for this notebook's name. |
|
1458 | * Getter method for this notebook's name. | |
1457 | * |
|
1459 | * | |
1458 | * @method get_notebook_name |
|
1460 | * @method get_notebook_name | |
1459 | * @return {String} This notebook's name |
|
1461 | * @return {String} This notebook's name | |
1460 | */ |
|
1462 | */ | |
1461 | Notebook.prototype.get_notebook_name = function () { |
|
1463 | Notebook.prototype.get_notebook_name = function () { | |
1462 | var nbname = this.notebook_name.substring(0,this.notebook_name.length-6); |
|
1464 | var nbname = this.notebook_name.substring(0,this.notebook_name.length-6); | |
1463 | return nbname; |
|
1465 | return nbname; | |
1464 | }; |
|
1466 | }; | |
1465 |
|
1467 | |||
1466 | /** |
|
1468 | /** | |
1467 | * Setter method for this notebook's name. |
|
1469 | * Setter method for this notebook's name. | |
1468 | * |
|
1470 | * | |
1469 | * @method set_notebook_name |
|
1471 | * @method set_notebook_name | |
1470 | * @param {String} name A new name for this notebook |
|
1472 | * @param {String} name A new name for this notebook | |
1471 | */ |
|
1473 | */ | |
1472 | Notebook.prototype.set_notebook_name = function (name) { |
|
1474 | Notebook.prototype.set_notebook_name = function (name) { | |
1473 | this.notebook_name = name; |
|
1475 | this.notebook_name = name; | |
1474 | }; |
|
1476 | }; | |
1475 |
|
1477 | |||
1476 | /** |
|
1478 | /** | |
1477 | * Check that a notebook's name is valid. |
|
1479 | * Check that a notebook's name is valid. | |
1478 | * |
|
1480 | * | |
1479 | * @method test_notebook_name |
|
1481 | * @method test_notebook_name | |
1480 | * @param {String} nbname A name for this notebook |
|
1482 | * @param {String} nbname A name for this notebook | |
1481 | * @return {Boolean} True if the name is valid, false if invalid |
|
1483 | * @return {Boolean} True if the name is valid, false if invalid | |
1482 | */ |
|
1484 | */ | |
1483 | Notebook.prototype.test_notebook_name = function (nbname) { |
|
1485 | Notebook.prototype.test_notebook_name = function (nbname) { | |
1484 | nbname = nbname || ''; |
|
1486 | nbname = nbname || ''; | |
1485 | if (this.notebook_name_blacklist_re.test(nbname) == false && nbname.length>0) { |
|
1487 | if (this.notebook_name_blacklist_re.test(nbname) == false && nbname.length>0) { | |
1486 | return true; |
|
1488 | return true; | |
1487 | } else { |
|
1489 | } else { | |
1488 | return false; |
|
1490 | return false; | |
1489 | }; |
|
1491 | }; | |
1490 | }; |
|
1492 | }; | |
1491 |
|
1493 | |||
1492 | /** |
|
1494 | /** | |
1493 | * Load a notebook from JSON (.ipynb). |
|
1495 | * Load a notebook from JSON (.ipynb). | |
1494 | * |
|
1496 | * | |
1495 | * This currently handles one worksheet: others are deleted. |
|
1497 | * This currently handles one worksheet: others are deleted. | |
1496 | * |
|
1498 | * | |
1497 | * @method fromJSON |
|
1499 | * @method fromJSON | |
1498 | * @param {Object} data JSON representation of a notebook |
|
1500 | * @param {Object} data JSON representation of a notebook | |
1499 | */ |
|
1501 | */ | |
1500 | Notebook.prototype.fromJSON = function (data) { |
|
1502 | Notebook.prototype.fromJSON = function (data) { | |
1501 | var content = data.content; |
|
1503 | var content = data.content; | |
1502 | var ncells = this.ncells(); |
|
1504 | var ncells = this.ncells(); | |
1503 | var i; |
|
1505 | var i; | |
1504 | for (i=0; i<ncells; i++) { |
|
1506 | for (i=0; i<ncells; i++) { | |
1505 | // Always delete cell 0 as they get renumbered as they are deleted. |
|
1507 | // Always delete cell 0 as they get renumbered as they are deleted. | |
1506 | this.delete_cell(0); |
|
1508 | this.delete_cell(0); | |
1507 | }; |
|
1509 | }; | |
1508 | // Save the metadata and name. |
|
1510 | // Save the metadata and name. | |
1509 | this.metadata = content.metadata; |
|
1511 | this.metadata = content.metadata; | |
1510 | this.notebook_name = data.name; |
|
1512 | this.notebook_name = data.name; | |
1511 | // Only handle 1 worksheet for now. |
|
1513 | // Only handle 1 worksheet for now. | |
1512 | var worksheet = content.worksheets[0]; |
|
1514 | var worksheet = content.worksheets[0]; | |
1513 | if (worksheet !== undefined) { |
|
1515 | if (worksheet !== undefined) { | |
1514 | if (worksheet.metadata) { |
|
1516 | if (worksheet.metadata) { | |
1515 | this.worksheet_metadata = worksheet.metadata; |
|
1517 | this.worksheet_metadata = worksheet.metadata; | |
1516 | } |
|
1518 | } | |
1517 | var new_cells = worksheet.cells; |
|
1519 | var new_cells = worksheet.cells; | |
1518 | ncells = new_cells.length; |
|
1520 | ncells = new_cells.length; | |
1519 | var cell_data = null; |
|
1521 | var cell_data = null; | |
1520 | var new_cell = null; |
|
1522 | var new_cell = null; | |
1521 | for (i=0; i<ncells; i++) { |
|
1523 | for (i=0; i<ncells; i++) { | |
1522 | cell_data = new_cells[i]; |
|
1524 | cell_data = new_cells[i]; | |
1523 | // VERSIONHACK: plaintext -> raw |
|
1525 | // VERSIONHACK: plaintext -> raw | |
1524 | // handle never-released plaintext name for raw cells |
|
1526 | // handle never-released plaintext name for raw cells | |
1525 | if (cell_data.cell_type === 'plaintext'){ |
|
1527 | if (cell_data.cell_type === 'plaintext'){ | |
1526 | cell_data.cell_type = 'raw'; |
|
1528 | cell_data.cell_type = 'raw'; | |
1527 | } |
|
1529 | } | |
1528 |
|
1530 | |||
1529 | new_cell = this.insert_cell_at_index(cell_data.cell_type, i); |
|
1531 | new_cell = this.insert_cell_at_index(cell_data.cell_type, i); | |
1530 | new_cell.fromJSON(cell_data); |
|
1532 | new_cell.fromJSON(cell_data); | |
1531 | }; |
|
1533 | }; | |
1532 | }; |
|
1534 | }; | |
1533 | if (content.worksheets.length > 1) { |
|
1535 | if (content.worksheets.length > 1) { | |
1534 | IPython.dialog.modal({ |
|
1536 | IPython.dialog.modal({ | |
1535 | title : "Multiple worksheets", |
|
1537 | title : "Multiple worksheets", | |
1536 | body : "This notebook has " + data.worksheets.length + " worksheets, " + |
|
1538 | body : "This notebook has " + data.worksheets.length + " worksheets, " + | |
1537 | "but this version of IPython can only handle the first. " + |
|
1539 | "but this version of IPython can only handle the first. " + | |
1538 | "If you save this notebook, worksheets after the first will be lost.", |
|
1540 | "If you save this notebook, worksheets after the first will be lost.", | |
1539 | buttons : { |
|
1541 | buttons : { | |
1540 | OK : { |
|
1542 | OK : { | |
1541 | class : "btn-danger" |
|
1543 | class : "btn-danger" | |
1542 | } |
|
1544 | } | |
1543 | } |
|
1545 | } | |
1544 | }); |
|
1546 | }); | |
1545 | } |
|
1547 | } | |
1546 | }; |
|
1548 | }; | |
1547 |
|
1549 | |||
1548 | /** |
|
1550 | /** | |
1549 | * Dump this notebook into a JSON-friendly object. |
|
1551 | * Dump this notebook into a JSON-friendly object. | |
1550 | * |
|
1552 | * | |
1551 | * @method toJSON |
|
1553 | * @method toJSON | |
1552 | * @return {Object} A JSON-friendly representation of this notebook. |
|
1554 | * @return {Object} A JSON-friendly representation of this notebook. | |
1553 | */ |
|
1555 | */ | |
1554 | Notebook.prototype.toJSON = function () { |
|
1556 | Notebook.prototype.toJSON = function () { | |
1555 | var cells = this.get_cells(); |
|
1557 | var cells = this.get_cells(); | |
1556 | var ncells = cells.length; |
|
1558 | var ncells = cells.length; | |
1557 | var cell_array = new Array(ncells); |
|
1559 | var cell_array = new Array(ncells); | |
1558 | for (var i=0; i<ncells; i++) { |
|
1560 | for (var i=0; i<ncells; i++) { | |
1559 | cell_array[i] = cells[i].toJSON(); |
|
1561 | cell_array[i] = cells[i].toJSON(); | |
1560 | }; |
|
1562 | }; | |
1561 | var data = { |
|
1563 | var data = { | |
1562 | // Only handle 1 worksheet for now. |
|
1564 | // Only handle 1 worksheet for now. | |
1563 | worksheets : [{ |
|
1565 | worksheets : [{ | |
1564 | cells: cell_array, |
|
1566 | cells: cell_array, | |
1565 | metadata: this.worksheet_metadata |
|
1567 | metadata: this.worksheet_metadata | |
1566 | }], |
|
1568 | }], | |
1567 | metadata : this.metadata |
|
1569 | metadata : this.metadata | |
1568 | }; |
|
1570 | }; | |
1569 | return data; |
|
1571 | return data; | |
1570 | }; |
|
1572 | }; | |
1571 |
|
1573 | |||
1572 | /** |
|
1574 | /** | |
1573 | * Start an autosave timer, for periodically saving the notebook. |
|
1575 | * Start an autosave timer, for periodically saving the notebook. | |
1574 | * |
|
1576 | * | |
1575 | * @method set_autosave_interval |
|
1577 | * @method set_autosave_interval | |
1576 | * @param {Integer} interval the autosave interval in milliseconds |
|
1578 | * @param {Integer} interval the autosave interval in milliseconds | |
1577 | */ |
|
1579 | */ | |
1578 | Notebook.prototype.set_autosave_interval = function (interval) { |
|
1580 | Notebook.prototype.set_autosave_interval = function (interval) { | |
1579 | var that = this; |
|
1581 | var that = this; | |
1580 | // clear previous interval, so we don't get simultaneous timers |
|
1582 | // clear previous interval, so we don't get simultaneous timers | |
1581 | if (this.autosave_timer) { |
|
1583 | if (this.autosave_timer) { | |
1582 | clearInterval(this.autosave_timer); |
|
1584 | clearInterval(this.autosave_timer); | |
1583 | } |
|
1585 | } | |
1584 |
|
1586 | |||
1585 | this.autosave_interval = this.minimum_autosave_interval = interval; |
|
1587 | this.autosave_interval = this.minimum_autosave_interval = interval; | |
1586 | if (interval) { |
|
1588 | if (interval) { | |
1587 | this.autosave_timer = setInterval(function() { |
|
1589 | this.autosave_timer = setInterval(function() { | |
1588 | if (that.dirty) { |
|
1590 | if (that.dirty) { | |
1589 | that.save_notebook(); |
|
1591 | that.save_notebook(); | |
1590 | } |
|
1592 | } | |
1591 | }, interval); |
|
1593 | }, interval); | |
1592 | $([IPython.events]).trigger("autosave_enabled.Notebook", interval); |
|
1594 | $([IPython.events]).trigger("autosave_enabled.Notebook", interval); | |
1593 | } else { |
|
1595 | } else { | |
1594 | this.autosave_timer = null; |
|
1596 | this.autosave_timer = null; | |
1595 | $([IPython.events]).trigger("autosave_disabled.Notebook"); |
|
1597 | $([IPython.events]).trigger("autosave_disabled.Notebook"); | |
1596 | }; |
|
1598 | }; | |
1597 | }; |
|
1599 | }; | |
1598 |
|
1600 | |||
1599 | /** |
|
1601 | /** | |
1600 | * Save this notebook on the server. |
|
1602 | * Save this notebook on the server. | |
1601 | * |
|
1603 | * | |
1602 | * @method save_notebook |
|
1604 | * @method save_notebook | |
1603 | */ |
|
1605 | */ | |
1604 | Notebook.prototype.save_notebook = function (extra_settings) { |
|
1606 | Notebook.prototype.save_notebook = function (extra_settings) { | |
1605 | // Create a JSON model to be sent to the server. |
|
1607 | // Create a JSON model to be sent to the server. | |
1606 | var model = {}; |
|
1608 | var model = {}; | |
1607 | model.name = this.notebook_name; |
|
1609 | model.name = this.notebook_name; | |
1608 | model.path = this.notebook_path; |
|
1610 | model.path = this.notebook_path; | |
1609 | model.content = this.toJSON(); |
|
1611 | model.content = this.toJSON(); | |
1610 | model.content.nbformat = this.nbformat; |
|
1612 | model.content.nbformat = this.nbformat; | |
1611 | model.content.nbformat_minor = this.nbformat_minor; |
|
1613 | model.content.nbformat_minor = this.nbformat_minor; | |
1612 | // time the ajax call for autosave tuning purposes. |
|
1614 | // time the ajax call for autosave tuning purposes. | |
1613 | var start = new Date().getTime(); |
|
1615 | var start = new Date().getTime(); | |
1614 | // We do the call with settings so we can set cache to false. |
|
1616 | // We do the call with settings so we can set cache to false. | |
1615 | var settings = { |
|
1617 | var settings = { | |
1616 | processData : false, |
|
1618 | processData : false, | |
1617 | cache : false, |
|
1619 | cache : false, | |
1618 | type : "PUT", |
|
1620 | type : "PUT", | |
1619 | data : JSON.stringify(model), |
|
1621 | data : JSON.stringify(model), | |
1620 | headers : {'Content-Type': 'application/json'}, |
|
1622 | headers : {'Content-Type': 'application/json'}, | |
1621 | success : $.proxy(this.save_notebook_success, this, start), |
|
1623 | success : $.proxy(this.save_notebook_success, this, start), | |
1622 | error : $.proxy(this.save_notebook_error, this) |
|
1624 | error : $.proxy(this.save_notebook_error, this) | |
1623 | }; |
|
1625 | }; | |
1624 | if (extra_settings) { |
|
1626 | if (extra_settings) { | |
1625 | for (var key in extra_settings) { |
|
1627 | for (var key in extra_settings) { | |
1626 | settings[key] = extra_settings[key]; |
|
1628 | settings[key] = extra_settings[key]; | |
1627 | } |
|
1629 | } | |
1628 | } |
|
1630 | } | |
1629 | $([IPython.events]).trigger('notebook_saving.Notebook'); |
|
1631 | $([IPython.events]).trigger('notebook_saving.Notebook'); | |
1630 | var url = utils.url_join_encode( |
|
1632 | var url = utils.url_join_encode( | |
1631 | this._baseProjectUrl, |
|
1633 | this._baseProjectUrl, | |
1632 | 'api/notebooks', |
|
1634 | 'api/notebooks', | |
1633 | this.notebook_path, |
|
1635 | this.notebook_path, | |
1634 | this.notebook_name |
|
1636 | this.notebook_name | |
1635 | ); |
|
1637 | ); | |
1636 | $.ajax(url, settings); |
|
1638 | $.ajax(url, settings); | |
1637 | }; |
|
1639 | }; | |
1638 |
|
1640 | |||
1639 | /** |
|
1641 | /** | |
1640 | * Success callback for saving a notebook. |
|
1642 | * Success callback for saving a notebook. | |
1641 | * |
|
1643 | * | |
1642 | * @method save_notebook_success |
|
1644 | * @method save_notebook_success | |
1643 | * @param {Integer} start the time when the save request started |
|
1645 | * @param {Integer} start the time when the save request started | |
1644 | * @param {Object} data JSON representation of a notebook |
|
1646 | * @param {Object} data JSON representation of a notebook | |
1645 | * @param {String} status Description of response status |
|
1647 | * @param {String} status Description of response status | |
1646 | * @param {jqXHR} xhr jQuery Ajax object |
|
1648 | * @param {jqXHR} xhr jQuery Ajax object | |
1647 | */ |
|
1649 | */ | |
1648 | Notebook.prototype.save_notebook_success = function (start, data, status, xhr) { |
|
1650 | Notebook.prototype.save_notebook_success = function (start, data, status, xhr) { | |
1649 | this.set_dirty(false); |
|
1651 | this.set_dirty(false); | |
1650 | $([IPython.events]).trigger('notebook_saved.Notebook'); |
|
1652 | $([IPython.events]).trigger('notebook_saved.Notebook'); | |
1651 | this._update_autosave_interval(start); |
|
1653 | this._update_autosave_interval(start); | |
1652 | if (this._checkpoint_after_save) { |
|
1654 | if (this._checkpoint_after_save) { | |
1653 | this.create_checkpoint(); |
|
1655 | this.create_checkpoint(); | |
1654 | this._checkpoint_after_save = false; |
|
1656 | this._checkpoint_after_save = false; | |
1655 | }; |
|
1657 | }; | |
1656 | }; |
|
1658 | }; | |
1657 |
|
1659 | |||
1658 | /** |
|
1660 | /** | |
1659 | * update the autosave interval based on how long the last save took |
|
1661 | * update the autosave interval based on how long the last save took | |
1660 | * |
|
1662 | * | |
1661 | * @method _update_autosave_interval |
|
1663 | * @method _update_autosave_interval | |
1662 | * @param {Integer} timestamp when the save request started |
|
1664 | * @param {Integer} timestamp when the save request started | |
1663 | */ |
|
1665 | */ | |
1664 | Notebook.prototype._update_autosave_interval = function (start) { |
|
1666 | Notebook.prototype._update_autosave_interval = function (start) { | |
1665 | var duration = (new Date().getTime() - start); |
|
1667 | var duration = (new Date().getTime() - start); | |
1666 | if (this.autosave_interval) { |
|
1668 | if (this.autosave_interval) { | |
1667 | // new save interval: higher of 10x save duration or parameter (default 30 seconds) |
|
1669 | // new save interval: higher of 10x save duration or parameter (default 30 seconds) | |
1668 | var interval = Math.max(10 * duration, this.minimum_autosave_interval); |
|
1670 | var interval = Math.max(10 * duration, this.minimum_autosave_interval); | |
1669 | // round to 10 seconds, otherwise we will be setting a new interval too often |
|
1671 | // round to 10 seconds, otherwise we will be setting a new interval too often | |
1670 | interval = 10000 * Math.round(interval / 10000); |
|
1672 | interval = 10000 * Math.round(interval / 10000); | |
1671 | // set new interval, if it's changed |
|
1673 | // set new interval, if it's changed | |
1672 | if (interval != this.autosave_interval) { |
|
1674 | if (interval != this.autosave_interval) { | |
1673 | this.set_autosave_interval(interval); |
|
1675 | this.set_autosave_interval(interval); | |
1674 | } |
|
1676 | } | |
1675 | } |
|
1677 | } | |
1676 | }; |
|
1678 | }; | |
1677 |
|
1679 | |||
1678 | /** |
|
1680 | /** | |
1679 | * Failure callback for saving a notebook. |
|
1681 | * Failure callback for saving a notebook. | |
1680 | * |
|
1682 | * | |
1681 | * @method save_notebook_error |
|
1683 | * @method save_notebook_error | |
1682 | * @param {jqXHR} xhr jQuery Ajax object |
|
1684 | * @param {jqXHR} xhr jQuery Ajax object | |
1683 | * @param {String} status Description of response status |
|
1685 | * @param {String} status Description of response status | |
1684 | * @param {String} error HTTP error message |
|
1686 | * @param {String} error HTTP error message | |
1685 | */ |
|
1687 | */ | |
1686 | Notebook.prototype.save_notebook_error = function (xhr, status, error) { |
|
1688 | Notebook.prototype.save_notebook_error = function (xhr, status, error) { | |
1687 | $([IPython.events]).trigger('notebook_save_failed.Notebook', [xhr, status, error]); |
|
1689 | $([IPython.events]).trigger('notebook_save_failed.Notebook', [xhr, status, error]); | |
1688 | }; |
|
1690 | }; | |
1689 |
|
1691 | |||
1690 | Notebook.prototype.new_notebook = function(){ |
|
1692 | Notebook.prototype.new_notebook = function(){ | |
1691 | var path = this.notebook_path; |
|
1693 | var path = this.notebook_path; | |
1692 | var base_project_url = this._baseProjectUrl; |
|
1694 | var base_project_url = this._baseProjectUrl; | |
1693 | var settings = { |
|
1695 | var settings = { | |
1694 | processData : false, |
|
1696 | processData : false, | |
1695 | cache : false, |
|
1697 | cache : false, | |
1696 | type : "POST", |
|
1698 | type : "POST", | |
1697 | dataType : "json", |
|
1699 | dataType : "json", | |
1698 | async : false, |
|
1700 | async : false, | |
1699 | success : function (data, status, xhr){ |
|
1701 | success : function (data, status, xhr){ | |
1700 | var notebook_name = data.name; |
|
1702 | var notebook_name = data.name; | |
1701 | window.open( |
|
1703 | window.open( | |
1702 | utils.url_join_encode( |
|
1704 | utils.url_join_encode( | |
1703 | base_project_url, |
|
1705 | base_project_url, | |
1704 | 'notebooks', |
|
1706 | 'notebooks', | |
1705 | path, |
|
1707 | path, | |
1706 | notebook_name |
|
1708 | notebook_name | |
1707 | ), |
|
1709 | ), | |
1708 | '_blank' |
|
1710 | '_blank' | |
1709 | ); |
|
1711 | ); | |
1710 | } |
|
1712 | } | |
1711 | }; |
|
1713 | }; | |
1712 | var url = utils.url_join_encode( |
|
1714 | var url = utils.url_join_encode( | |
1713 | base_project_url, |
|
1715 | base_project_url, | |
1714 | 'api/notebooks', |
|
1716 | 'api/notebooks', | |
1715 | path |
|
1717 | path | |
1716 | ); |
|
1718 | ); | |
1717 | $.ajax(url,settings); |
|
1719 | $.ajax(url,settings); | |
1718 | }; |
|
1720 | }; | |
1719 |
|
1721 | |||
1720 |
|
1722 | |||
1721 | Notebook.prototype.copy_notebook = function(){ |
|
1723 | Notebook.prototype.copy_notebook = function(){ | |
1722 | var path = this.notebook_path; |
|
1724 | var path = this.notebook_path; | |
1723 | var base_project_url = this._baseProjectUrl; |
|
1725 | var base_project_url = this._baseProjectUrl; | |
1724 | var settings = { |
|
1726 | var settings = { | |
1725 | processData : false, |
|
1727 | processData : false, | |
1726 | cache : false, |
|
1728 | cache : false, | |
1727 | type : "POST", |
|
1729 | type : "POST", | |
1728 | dataType : "json", |
|
1730 | dataType : "json", | |
1729 | data : JSON.stringify({copy_from : this.notebook_name}), |
|
1731 | data : JSON.stringify({copy_from : this.notebook_name}), | |
1730 | async : false, |
|
1732 | async : false, | |
1731 | success : function (data, status, xhr) { |
|
1733 | success : function (data, status, xhr) { | |
1732 | window.open(utils.url_join_encode( |
|
1734 | window.open(utils.url_join_encode( | |
1733 | base_project_url, |
|
1735 | base_project_url, | |
1734 | 'notebooks', |
|
1736 | 'notebooks', | |
1735 | data.path, |
|
1737 | data.path, | |
1736 | data.name |
|
1738 | data.name | |
1737 | ), '_blank'); |
|
1739 | ), '_blank'); | |
1738 | } |
|
1740 | } | |
1739 | }; |
|
1741 | }; | |
1740 | var url = utils.url_join_encode( |
|
1742 | var url = utils.url_join_encode( | |
1741 | base_project_url, |
|
1743 | base_project_url, | |
1742 | 'api/notebooks', |
|
1744 | 'api/notebooks', | |
1743 | path |
|
1745 | path | |
1744 | ); |
|
1746 | ); | |
1745 | $.ajax(url,settings); |
|
1747 | $.ajax(url,settings); | |
1746 | }; |
|
1748 | }; | |
1747 |
|
1749 | |||
1748 | Notebook.prototype.rename = function (nbname) { |
|
1750 | Notebook.prototype.rename = function (nbname) { | |
1749 | var that = this; |
|
1751 | var that = this; | |
1750 | var data = {name: nbname + '.ipynb'}; |
|
1752 | var data = {name: nbname + '.ipynb'}; | |
1751 | var settings = { |
|
1753 | var settings = { | |
1752 | processData : false, |
|
1754 | processData : false, | |
1753 | cache : false, |
|
1755 | cache : false, | |
1754 | type : "PATCH", |
|
1756 | type : "PATCH", | |
1755 | data : JSON.stringify(data), |
|
1757 | data : JSON.stringify(data), | |
1756 | dataType: "json", |
|
1758 | dataType: "json", | |
1757 | headers : {'Content-Type': 'application/json'}, |
|
1759 | headers : {'Content-Type': 'application/json'}, | |
1758 | success : $.proxy(that.rename_success, this), |
|
1760 | success : $.proxy(that.rename_success, this), | |
1759 | error : $.proxy(that.rename_error, this) |
|
1761 | error : $.proxy(that.rename_error, this) | |
1760 | }; |
|
1762 | }; | |
1761 | $([IPython.events]).trigger('rename_notebook.Notebook', data); |
|
1763 | $([IPython.events]).trigger('rename_notebook.Notebook', data); | |
1762 | var url = utils.url_join_encode( |
|
1764 | var url = utils.url_join_encode( | |
1763 | this._baseProjectUrl, |
|
1765 | this._baseProjectUrl, | |
1764 | 'api/notebooks', |
|
1766 | 'api/notebooks', | |
1765 | this.notebook_path, |
|
1767 | this.notebook_path, | |
1766 | this.notebook_name |
|
1768 | this.notebook_name | |
1767 | ); |
|
1769 | ); | |
1768 | $.ajax(url, settings); |
|
1770 | $.ajax(url, settings); | |
1769 | }; |
|
1771 | }; | |
1770 |
|
1772 | |||
1771 |
|
1773 | |||
1772 | Notebook.prototype.rename_success = function (json, status, xhr) { |
|
1774 | Notebook.prototype.rename_success = function (json, status, xhr) { | |
1773 | this.notebook_name = json.name; |
|
1775 | this.notebook_name = json.name; | |
1774 | var name = this.notebook_name; |
|
1776 | var name = this.notebook_name; | |
1775 | var path = json.path; |
|
1777 | var path = json.path; | |
1776 | this.session.rename_notebook(name, path); |
|
1778 | this.session.rename_notebook(name, path); | |
1777 | $([IPython.events]).trigger('notebook_renamed.Notebook', json); |
|
1779 | $([IPython.events]).trigger('notebook_renamed.Notebook', json); | |
1778 | } |
|
1780 | } | |
1779 |
|
1781 | |||
1780 | Notebook.prototype.rename_error = function (xhr, status, error) { |
|
1782 | Notebook.prototype.rename_error = function (xhr, status, error) { | |
1781 | var that = this; |
|
1783 | var that = this; | |
1782 | var dialog = $('<div/>').append( |
|
1784 | var dialog = $('<div/>').append( | |
1783 | $("<p/>").addClass("rename-message") |
|
1785 | $("<p/>").addClass("rename-message") | |
1784 | .html('This notebook name already exists.') |
|
1786 | .html('This notebook name already exists.') | |
1785 | ) |
|
1787 | ) | |
1786 | $([IPython.events]).trigger('notebook_rename_failed.Notebook', [xhr, status, error]); |
|
1788 | $([IPython.events]).trigger('notebook_rename_failed.Notebook', [xhr, status, error]); | |
1787 | IPython.dialog.modal({ |
|
1789 | IPython.dialog.modal({ | |
1788 | title: "Notebook Rename Error!", |
|
1790 | title: "Notebook Rename Error!", | |
1789 | body: dialog, |
|
1791 | body: dialog, | |
1790 | buttons : { |
|
1792 | buttons : { | |
1791 | "Cancel": {}, |
|
1793 | "Cancel": {}, | |
1792 | "OK": { |
|
1794 | "OK": { | |
1793 | class: "btn-primary", |
|
1795 | class: "btn-primary", | |
1794 | click: function () { |
|
1796 | click: function () { | |
1795 | IPython.save_widget.rename_notebook(); |
|
1797 | IPython.save_widget.rename_notebook(); | |
1796 | }} |
|
1798 | }} | |
1797 | }, |
|
1799 | }, | |
1798 | open : function (event, ui) { |
|
1800 | open : function (event, ui) { | |
1799 | var that = $(this); |
|
1801 | var that = $(this); | |
1800 | // Upon ENTER, click the OK button. |
|
1802 | // Upon ENTER, click the OK button. | |
1801 | that.find('input[type="text"]').keydown(function (event, ui) { |
|
1803 | that.find('input[type="text"]').keydown(function (event, ui) { | |
1802 | if (event.which === utils.keycodes.ENTER) { |
|
1804 | if (event.which === utils.keycodes.ENTER) { | |
1803 | that.find('.btn-primary').first().click(); |
|
1805 | that.find('.btn-primary').first().click(); | |
1804 | } |
|
1806 | } | |
1805 | }); |
|
1807 | }); | |
1806 | that.find('input[type="text"]').focus(); |
|
1808 | that.find('input[type="text"]').focus(); | |
1807 | } |
|
1809 | } | |
1808 | }); |
|
1810 | }); | |
1809 | } |
|
1811 | } | |
1810 |
|
1812 | |||
1811 | /** |
|
1813 | /** | |
1812 | * Request a notebook's data from the server. |
|
1814 | * Request a notebook's data from the server. | |
1813 | * |
|
1815 | * | |
1814 | * @method load_notebook |
|
1816 | * @method load_notebook | |
1815 | * @param {String} notebook_name and path A notebook to load |
|
1817 | * @param {String} notebook_name and path A notebook to load | |
1816 | */ |
|
1818 | */ | |
1817 | Notebook.prototype.load_notebook = function (notebook_name, notebook_path) { |
|
1819 | Notebook.prototype.load_notebook = function (notebook_name, notebook_path) { | |
1818 | var that = this; |
|
1820 | var that = this; | |
1819 | this.notebook_name = notebook_name; |
|
1821 | this.notebook_name = notebook_name; | |
1820 | this.notebook_path = notebook_path; |
|
1822 | this.notebook_path = notebook_path; | |
1821 | // We do the call with settings so we can set cache to false. |
|
1823 | // We do the call with settings so we can set cache to false. | |
1822 | var settings = { |
|
1824 | var settings = { | |
1823 | processData : false, |
|
1825 | processData : false, | |
1824 | cache : false, |
|
1826 | cache : false, | |
1825 | type : "GET", |
|
1827 | type : "GET", | |
1826 | dataType : "json", |
|
1828 | dataType : "json", | |
1827 | success : $.proxy(this.load_notebook_success,this), |
|
1829 | success : $.proxy(this.load_notebook_success,this), | |
1828 | error : $.proxy(this.load_notebook_error,this), |
|
1830 | error : $.proxy(this.load_notebook_error,this), | |
1829 | }; |
|
1831 | }; | |
1830 | $([IPython.events]).trigger('notebook_loading.Notebook'); |
|
1832 | $([IPython.events]).trigger('notebook_loading.Notebook'); | |
1831 | var url = utils.url_join_encode( |
|
1833 | var url = utils.url_join_encode( | |
1832 | this._baseProjectUrl, |
|
1834 | this._baseProjectUrl, | |
1833 | 'api/notebooks', |
|
1835 | 'api/notebooks', | |
1834 | this.notebook_path, |
|
1836 | this.notebook_path, | |
1835 | this.notebook_name |
|
1837 | this.notebook_name | |
1836 | ); |
|
1838 | ); | |
1837 | $.ajax(url, settings); |
|
1839 | $.ajax(url, settings); | |
1838 | }; |
|
1840 | }; | |
1839 |
|
1841 | |||
1840 | /** |
|
1842 | /** | |
1841 | * Success callback for loading a notebook from the server. |
|
1843 | * Success callback for loading a notebook from the server. | |
1842 | * |
|
1844 | * | |
1843 | * Load notebook data from the JSON response. |
|
1845 | * Load notebook data from the JSON response. | |
1844 | * |
|
1846 | * | |
1845 | * @method load_notebook_success |
|
1847 | * @method load_notebook_success | |
1846 | * @param {Object} data JSON representation of a notebook |
|
1848 | * @param {Object} data JSON representation of a notebook | |
1847 | * @param {String} status Description of response status |
|
1849 | * @param {String} status Description of response status | |
1848 | * @param {jqXHR} xhr jQuery Ajax object |
|
1850 | * @param {jqXHR} xhr jQuery Ajax object | |
1849 | */ |
|
1851 | */ | |
1850 | Notebook.prototype.load_notebook_success = function (data, status, xhr) { |
|
1852 | Notebook.prototype.load_notebook_success = function (data, status, xhr) { | |
1851 | this.fromJSON(data); |
|
1853 | this.fromJSON(data); | |
1852 | if (this.ncells() === 0) { |
|
1854 | if (this.ncells() === 0) { | |
1853 | this.insert_cell_below('code'); |
|
1855 | this.insert_cell_below('code'); | |
1854 | this.select(0); |
|
1856 | this.select(0); | |
1855 | this.edit_mode(); |
|
1857 | this.edit_mode(); | |
1856 | } else { |
|
1858 | } else { | |
1857 | this.select(0); |
|
1859 | this.select(0); | |
1858 | this.command_mode(); |
|
1860 | this.command_mode(); | |
1859 | }; |
|
1861 | }; | |
1860 | this.set_dirty(false); |
|
1862 | this.set_dirty(false); | |
1861 | this.scroll_to_top(); |
|
1863 | this.scroll_to_top(); | |
1862 | if (data.orig_nbformat !== undefined && data.nbformat !== data.orig_nbformat) { |
|
1864 | if (data.orig_nbformat !== undefined && data.nbformat !== data.orig_nbformat) { | |
1863 | var msg = "This notebook has been converted from an older " + |
|
1865 | var msg = "This notebook has been converted from an older " + | |
1864 | "notebook format (v"+data.orig_nbformat+") to the current notebook " + |
|
1866 | "notebook format (v"+data.orig_nbformat+") to the current notebook " + | |
1865 | "format (v"+data.nbformat+"). The next time you save this notebook, the " + |
|
1867 | "format (v"+data.nbformat+"). The next time you save this notebook, the " + | |
1866 | "newer notebook format will be used and older versions of IPython " + |
|
1868 | "newer notebook format will be used and older versions of IPython " + | |
1867 | "may not be able to read it. To keep the older version, close the " + |
|
1869 | "may not be able to read it. To keep the older version, close the " + | |
1868 | "notebook without saving it."; |
|
1870 | "notebook without saving it."; | |
1869 | IPython.dialog.modal({ |
|
1871 | IPython.dialog.modal({ | |
1870 | title : "Notebook converted", |
|
1872 | title : "Notebook converted", | |
1871 | body : msg, |
|
1873 | body : msg, | |
1872 | buttons : { |
|
1874 | buttons : { | |
1873 | OK : { |
|
1875 | OK : { | |
1874 | class : "btn-primary" |
|
1876 | class : "btn-primary" | |
1875 | } |
|
1877 | } | |
1876 | } |
|
1878 | } | |
1877 | }); |
|
1879 | }); | |
1878 | } else if (data.orig_nbformat_minor !== undefined && data.nbformat_minor !== data.orig_nbformat_minor) { |
|
1880 | } else if (data.orig_nbformat_minor !== undefined && data.nbformat_minor !== data.orig_nbformat_minor) { | |
1879 | var that = this; |
|
1881 | var that = this; | |
1880 | var orig_vs = 'v' + data.nbformat + '.' + data.orig_nbformat_minor; |
|
1882 | var orig_vs = 'v' + data.nbformat + '.' + data.orig_nbformat_minor; | |
1881 | var this_vs = 'v' + data.nbformat + '.' + this.nbformat_minor; |
|
1883 | var this_vs = 'v' + data.nbformat + '.' + this.nbformat_minor; | |
1882 | var msg = "This notebook is version " + orig_vs + ", but we only fully support up to " + |
|
1884 | var msg = "This notebook is version " + orig_vs + ", but we only fully support up to " + | |
1883 | this_vs + ". You can still work with this notebook, but some features " + |
|
1885 | this_vs + ". You can still work with this notebook, but some features " + | |
1884 | "introduced in later notebook versions may not be available." |
|
1886 | "introduced in later notebook versions may not be available." | |
1885 |
|
1887 | |||
1886 | IPython.dialog.modal({ |
|
1888 | IPython.dialog.modal({ | |
1887 | title : "Newer Notebook", |
|
1889 | title : "Newer Notebook", | |
1888 | body : msg, |
|
1890 | body : msg, | |
1889 | buttons : { |
|
1891 | buttons : { | |
1890 | OK : { |
|
1892 | OK : { | |
1891 | class : "btn-danger" |
|
1893 | class : "btn-danger" | |
1892 | } |
|
1894 | } | |
1893 | } |
|
1895 | } | |
1894 | }); |
|
1896 | }); | |
1895 |
|
1897 | |||
1896 | } |
|
1898 | } | |
1897 |
|
1899 | |||
1898 | // Create the session after the notebook is completely loaded to prevent |
|
1900 | // Create the session after the notebook is completely loaded to prevent | |
1899 | // code execution upon loading, which is a security risk. |
|
1901 | // code execution upon loading, which is a security risk. | |
1900 | if (this.session == null) { |
|
1902 | if (this.session == null) { | |
1901 | this.start_session(); |
|
1903 | this.start_session(); | |
1902 | } |
|
1904 | } | |
1903 | // load our checkpoint list |
|
1905 | // load our checkpoint list | |
1904 | this.list_checkpoints(); |
|
1906 | this.list_checkpoints(); | |
1905 |
|
1907 | |||
1906 | // load toolbar state |
|
1908 | // load toolbar state | |
1907 | if (this.metadata.celltoolbar) { |
|
1909 | if (this.metadata.celltoolbar) { | |
1908 | IPython.CellToolbar.global_show(); |
|
1910 | IPython.CellToolbar.global_show(); | |
1909 | IPython.CellToolbar.activate_preset(this.metadata.celltoolbar); |
|
1911 | IPython.CellToolbar.activate_preset(this.metadata.celltoolbar); | |
1910 | } |
|
1912 | } | |
1911 |
|
1913 | |||
1912 | $([IPython.events]).trigger('notebook_loaded.Notebook'); |
|
1914 | $([IPython.events]).trigger('notebook_loaded.Notebook'); | |
1913 | }; |
|
1915 | }; | |
1914 |
|
1916 | |||
1915 | /** |
|
1917 | /** | |
1916 | * Failure callback for loading a notebook from the server. |
|
1918 | * Failure callback for loading a notebook from the server. | |
1917 | * |
|
1919 | * | |
1918 | * @method load_notebook_error |
|
1920 | * @method load_notebook_error | |
1919 | * @param {jqXHR} xhr jQuery Ajax object |
|
1921 | * @param {jqXHR} xhr jQuery Ajax object | |
1920 | * @param {String} status Description of response status |
|
1922 | * @param {String} status Description of response status | |
1921 | * @param {String} error HTTP error message |
|
1923 | * @param {String} error HTTP error message | |
1922 | */ |
|
1924 | */ | |
1923 | Notebook.prototype.load_notebook_error = function (xhr, status, error) { |
|
1925 | Notebook.prototype.load_notebook_error = function (xhr, status, error) { | |
1924 | $([IPython.events]).trigger('notebook_load_failed.Notebook', [xhr, status, error]); |
|
1926 | $([IPython.events]).trigger('notebook_load_failed.Notebook', [xhr, status, error]); | |
1925 | if (xhr.status === 400) { |
|
1927 | if (xhr.status === 400) { | |
1926 | var msg = error; |
|
1928 | var msg = error; | |
1927 | } else if (xhr.status === 500) { |
|
1929 | } else if (xhr.status === 500) { | |
1928 | var msg = "An unknown error occurred while loading this notebook. " + |
|
1930 | var msg = "An unknown error occurred while loading this notebook. " + | |
1929 | "This version can load notebook formats " + |
|
1931 | "This version can load notebook formats " + | |
1930 | "v" + this.nbformat + " or earlier."; |
|
1932 | "v" + this.nbformat + " or earlier."; | |
1931 | } |
|
1933 | } | |
1932 | IPython.dialog.modal({ |
|
1934 | IPython.dialog.modal({ | |
1933 | title: "Error loading notebook", |
|
1935 | title: "Error loading notebook", | |
1934 | body : msg, |
|
1936 | body : msg, | |
1935 | buttons : { |
|
1937 | buttons : { | |
1936 | "OK": {} |
|
1938 | "OK": {} | |
1937 | } |
|
1939 | } | |
1938 | }); |
|
1940 | }); | |
1939 | } |
|
1941 | } | |
1940 |
|
1942 | |||
1941 | /********************* checkpoint-related *********************/ |
|
1943 | /********************* checkpoint-related *********************/ | |
1942 |
|
1944 | |||
1943 | /** |
|
1945 | /** | |
1944 | * Save the notebook then immediately create a checkpoint. |
|
1946 | * Save the notebook then immediately create a checkpoint. | |
1945 | * |
|
1947 | * | |
1946 | * @method save_checkpoint |
|
1948 | * @method save_checkpoint | |
1947 | */ |
|
1949 | */ | |
1948 | Notebook.prototype.save_checkpoint = function () { |
|
1950 | Notebook.prototype.save_checkpoint = function () { | |
1949 | this._checkpoint_after_save = true; |
|
1951 | this._checkpoint_after_save = true; | |
1950 | this.save_notebook(); |
|
1952 | this.save_notebook(); | |
1951 | }; |
|
1953 | }; | |
1952 |
|
1954 | |||
1953 | /** |
|
1955 | /** | |
1954 | * Add a checkpoint for this notebook. |
|
1956 | * Add a checkpoint for this notebook. | |
1955 | * for use as a callback from checkpoint creation. |
|
1957 | * for use as a callback from checkpoint creation. | |
1956 | * |
|
1958 | * | |
1957 | * @method add_checkpoint |
|
1959 | * @method add_checkpoint | |
1958 | */ |
|
1960 | */ | |
1959 | Notebook.prototype.add_checkpoint = function (checkpoint) { |
|
1961 | Notebook.prototype.add_checkpoint = function (checkpoint) { | |
1960 | var found = false; |
|
1962 | var found = false; | |
1961 | for (var i = 0; i < this.checkpoints.length; i++) { |
|
1963 | for (var i = 0; i < this.checkpoints.length; i++) { | |
1962 | var existing = this.checkpoints[i]; |
|
1964 | var existing = this.checkpoints[i]; | |
1963 | if (existing.id == checkpoint.id) { |
|
1965 | if (existing.id == checkpoint.id) { | |
1964 | found = true; |
|
1966 | found = true; | |
1965 | this.checkpoints[i] = checkpoint; |
|
1967 | this.checkpoints[i] = checkpoint; | |
1966 | break; |
|
1968 | break; | |
1967 | } |
|
1969 | } | |
1968 | } |
|
1970 | } | |
1969 | if (!found) { |
|
1971 | if (!found) { | |
1970 | this.checkpoints.push(checkpoint); |
|
1972 | this.checkpoints.push(checkpoint); | |
1971 | } |
|
1973 | } | |
1972 | this.last_checkpoint = this.checkpoints[this.checkpoints.length - 1]; |
|
1974 | this.last_checkpoint = this.checkpoints[this.checkpoints.length - 1]; | |
1973 | }; |
|
1975 | }; | |
1974 |
|
1976 | |||
1975 | /** |
|
1977 | /** | |
1976 | * List checkpoints for this notebook. |
|
1978 | * List checkpoints for this notebook. | |
1977 | * |
|
1979 | * | |
1978 | * @method list_checkpoints |
|
1980 | * @method list_checkpoints | |
1979 | */ |
|
1981 | */ | |
1980 | Notebook.prototype.list_checkpoints = function () { |
|
1982 | Notebook.prototype.list_checkpoints = function () { | |
1981 | var url = utils.url_join_encode( |
|
1983 | var url = utils.url_join_encode( | |
1982 | this._baseProjectUrl, |
|
1984 | this._baseProjectUrl, | |
1983 | 'api/notebooks', |
|
1985 | 'api/notebooks', | |
1984 | this.notebook_path, |
|
1986 | this.notebook_path, | |
1985 | this.notebook_name, |
|
1987 | this.notebook_name, | |
1986 | 'checkpoints' |
|
1988 | 'checkpoints' | |
1987 | ); |
|
1989 | ); | |
1988 | $.get(url).done( |
|
1990 | $.get(url).done( | |
1989 | $.proxy(this.list_checkpoints_success, this) |
|
1991 | $.proxy(this.list_checkpoints_success, this) | |
1990 | ).fail( |
|
1992 | ).fail( | |
1991 | $.proxy(this.list_checkpoints_error, this) |
|
1993 | $.proxy(this.list_checkpoints_error, this) | |
1992 | ); |
|
1994 | ); | |
1993 | }; |
|
1995 | }; | |
1994 |
|
1996 | |||
1995 | /** |
|
1997 | /** | |
1996 | * Success callback for listing checkpoints. |
|
1998 | * Success callback for listing checkpoints. | |
1997 | * |
|
1999 | * | |
1998 | * @method list_checkpoint_success |
|
2000 | * @method list_checkpoint_success | |
1999 | * @param {Object} data JSON representation of a checkpoint |
|
2001 | * @param {Object} data JSON representation of a checkpoint | |
2000 | * @param {String} status Description of response status |
|
2002 | * @param {String} status Description of response status | |
2001 | * @param {jqXHR} xhr jQuery Ajax object |
|
2003 | * @param {jqXHR} xhr jQuery Ajax object | |
2002 | */ |
|
2004 | */ | |
2003 | Notebook.prototype.list_checkpoints_success = function (data, status, xhr) { |
|
2005 | Notebook.prototype.list_checkpoints_success = function (data, status, xhr) { | |
2004 | var data = $.parseJSON(data); |
|
2006 | var data = $.parseJSON(data); | |
2005 | this.checkpoints = data; |
|
2007 | this.checkpoints = data; | |
2006 | if (data.length) { |
|
2008 | if (data.length) { | |
2007 | this.last_checkpoint = data[data.length - 1]; |
|
2009 | this.last_checkpoint = data[data.length - 1]; | |
2008 | } else { |
|
2010 | } else { | |
2009 | this.last_checkpoint = null; |
|
2011 | this.last_checkpoint = null; | |
2010 | } |
|
2012 | } | |
2011 | $([IPython.events]).trigger('checkpoints_listed.Notebook', [data]); |
|
2013 | $([IPython.events]).trigger('checkpoints_listed.Notebook', [data]); | |
2012 | }; |
|
2014 | }; | |
2013 |
|
2015 | |||
2014 | /** |
|
2016 | /** | |
2015 | * Failure callback for listing a checkpoint. |
|
2017 | * Failure callback for listing a checkpoint. | |
2016 | * |
|
2018 | * | |
2017 | * @method list_checkpoint_error |
|
2019 | * @method list_checkpoint_error | |
2018 | * @param {jqXHR} xhr jQuery Ajax object |
|
2020 | * @param {jqXHR} xhr jQuery Ajax object | |
2019 | * @param {String} status Description of response status |
|
2021 | * @param {String} status Description of response status | |
2020 | * @param {String} error_msg HTTP error message |
|
2022 | * @param {String} error_msg HTTP error message | |
2021 | */ |
|
2023 | */ | |
2022 | Notebook.prototype.list_checkpoints_error = function (xhr, status, error_msg) { |
|
2024 | Notebook.prototype.list_checkpoints_error = function (xhr, status, error_msg) { | |
2023 | $([IPython.events]).trigger('list_checkpoints_failed.Notebook'); |
|
2025 | $([IPython.events]).trigger('list_checkpoints_failed.Notebook'); | |
2024 | }; |
|
2026 | }; | |
2025 |
|
2027 | |||
2026 | /** |
|
2028 | /** | |
2027 | * Create a checkpoint of this notebook on the server from the most recent save. |
|
2029 | * Create a checkpoint of this notebook on the server from the most recent save. | |
2028 | * |
|
2030 | * | |
2029 | * @method create_checkpoint |
|
2031 | * @method create_checkpoint | |
2030 | */ |
|
2032 | */ | |
2031 | Notebook.prototype.create_checkpoint = function () { |
|
2033 | Notebook.prototype.create_checkpoint = function () { | |
2032 | var url = utils.url_join_encode( |
|
2034 | var url = utils.url_join_encode( | |
2033 | this._baseProjectUrl, |
|
2035 | this._baseProjectUrl, | |
2034 | 'api/notebooks', |
|
2036 | 'api/notebooks', | |
2035 | this.notebookPath(), |
|
2037 | this.notebookPath(), | |
2036 | this.notebook_name, |
|
2038 | this.notebook_name, | |
2037 | 'checkpoints' |
|
2039 | 'checkpoints' | |
2038 | ); |
|
2040 | ); | |
2039 | $.post(url).done( |
|
2041 | $.post(url).done( | |
2040 | $.proxy(this.create_checkpoint_success, this) |
|
2042 | $.proxy(this.create_checkpoint_success, this) | |
2041 | ).fail( |
|
2043 | ).fail( | |
2042 | $.proxy(this.create_checkpoint_error, this) |
|
2044 | $.proxy(this.create_checkpoint_error, this) | |
2043 | ); |
|
2045 | ); | |
2044 | }; |
|
2046 | }; | |
2045 |
|
2047 | |||
2046 | /** |
|
2048 | /** | |
2047 | * Success callback for creating a checkpoint. |
|
2049 | * Success callback for creating a checkpoint. | |
2048 | * |
|
2050 | * | |
2049 | * @method create_checkpoint_success |
|
2051 | * @method create_checkpoint_success | |
2050 | * @param {Object} data JSON representation of a checkpoint |
|
2052 | * @param {Object} data JSON representation of a checkpoint | |
2051 | * @param {String} status Description of response status |
|
2053 | * @param {String} status Description of response status | |
2052 | * @param {jqXHR} xhr jQuery Ajax object |
|
2054 | * @param {jqXHR} xhr jQuery Ajax object | |
2053 | */ |
|
2055 | */ | |
2054 | Notebook.prototype.create_checkpoint_success = function (data, status, xhr) { |
|
2056 | Notebook.prototype.create_checkpoint_success = function (data, status, xhr) { | |
2055 | var data = $.parseJSON(data); |
|
2057 | var data = $.parseJSON(data); | |
2056 | this.add_checkpoint(data); |
|
2058 | this.add_checkpoint(data); | |
2057 | $([IPython.events]).trigger('checkpoint_created.Notebook', data); |
|
2059 | $([IPython.events]).trigger('checkpoint_created.Notebook', data); | |
2058 | }; |
|
2060 | }; | |
2059 |
|
2061 | |||
2060 | /** |
|
2062 | /** | |
2061 | * Failure callback for creating a checkpoint. |
|
2063 | * Failure callback for creating a checkpoint. | |
2062 | * |
|
2064 | * | |
2063 | * @method create_checkpoint_error |
|
2065 | * @method create_checkpoint_error | |
2064 | * @param {jqXHR} xhr jQuery Ajax object |
|
2066 | * @param {jqXHR} xhr jQuery Ajax object | |
2065 | * @param {String} status Description of response status |
|
2067 | * @param {String} status Description of response status | |
2066 | * @param {String} error_msg HTTP error message |
|
2068 | * @param {String} error_msg HTTP error message | |
2067 | */ |
|
2069 | */ | |
2068 | Notebook.prototype.create_checkpoint_error = function (xhr, status, error_msg) { |
|
2070 | Notebook.prototype.create_checkpoint_error = function (xhr, status, error_msg) { | |
2069 | $([IPython.events]).trigger('checkpoint_failed.Notebook'); |
|
2071 | $([IPython.events]).trigger('checkpoint_failed.Notebook'); | |
2070 | }; |
|
2072 | }; | |
2071 |
|
2073 | |||
2072 | Notebook.prototype.restore_checkpoint_dialog = function (checkpoint) { |
|
2074 | Notebook.prototype.restore_checkpoint_dialog = function (checkpoint) { | |
2073 | var that = this; |
|
2075 | var that = this; | |
2074 | var checkpoint = checkpoint || this.last_checkpoint; |
|
2076 | var checkpoint = checkpoint || this.last_checkpoint; | |
2075 | if ( ! checkpoint ) { |
|
2077 | if ( ! checkpoint ) { | |
2076 | console.log("restore dialog, but no checkpoint to restore to!"); |
|
2078 | console.log("restore dialog, but no checkpoint to restore to!"); | |
2077 | return; |
|
2079 | return; | |
2078 | } |
|
2080 | } | |
2079 | var body = $('<div/>').append( |
|
2081 | var body = $('<div/>').append( | |
2080 | $('<p/>').addClass("p-space").text( |
|
2082 | $('<p/>').addClass("p-space").text( | |
2081 | "Are you sure you want to revert the notebook to " + |
|
2083 | "Are you sure you want to revert the notebook to " + | |
2082 | "the latest checkpoint?" |
|
2084 | "the latest checkpoint?" | |
2083 | ).append( |
|
2085 | ).append( | |
2084 | $("<strong/>").text( |
|
2086 | $("<strong/>").text( | |
2085 | " This cannot be undone." |
|
2087 | " This cannot be undone." | |
2086 | ) |
|
2088 | ) | |
2087 | ) |
|
2089 | ) | |
2088 | ).append( |
|
2090 | ).append( | |
2089 | $('<p/>').addClass("p-space").text("The checkpoint was last updated at:") |
|
2091 | $('<p/>').addClass("p-space").text("The checkpoint was last updated at:") | |
2090 | ).append( |
|
2092 | ).append( | |
2091 | $('<p/>').addClass("p-space").text( |
|
2093 | $('<p/>').addClass("p-space").text( | |
2092 | Date(checkpoint.last_modified) |
|
2094 | Date(checkpoint.last_modified) | |
2093 | ).css("text-align", "center") |
|
2095 | ).css("text-align", "center") | |
2094 | ); |
|
2096 | ); | |
2095 |
|
2097 | |||
2096 | IPython.dialog.modal({ |
|
2098 | IPython.dialog.modal({ | |
2097 | title : "Revert notebook to checkpoint", |
|
2099 | title : "Revert notebook to checkpoint", | |
2098 | body : body, |
|
2100 | body : body, | |
2099 | buttons : { |
|
2101 | buttons : { | |
2100 | Revert : { |
|
2102 | Revert : { | |
2101 | class : "btn-danger", |
|
2103 | class : "btn-danger", | |
2102 | click : function () { |
|
2104 | click : function () { | |
2103 | that.restore_checkpoint(checkpoint.id); |
|
2105 | that.restore_checkpoint(checkpoint.id); | |
2104 | } |
|
2106 | } | |
2105 | }, |
|
2107 | }, | |
2106 | Cancel : {} |
|
2108 | Cancel : {} | |
2107 | } |
|
2109 | } | |
2108 | }); |
|
2110 | }); | |
2109 | } |
|
2111 | } | |
2110 |
|
2112 | |||
2111 | /** |
|
2113 | /** | |
2112 | * Restore the notebook to a checkpoint state. |
|
2114 | * Restore the notebook to a checkpoint state. | |
2113 | * |
|
2115 | * | |
2114 | * @method restore_checkpoint |
|
2116 | * @method restore_checkpoint | |
2115 | * @param {String} checkpoint ID |
|
2117 | * @param {String} checkpoint ID | |
2116 | */ |
|
2118 | */ | |
2117 | Notebook.prototype.restore_checkpoint = function (checkpoint) { |
|
2119 | Notebook.prototype.restore_checkpoint = function (checkpoint) { | |
2118 | $([IPython.events]).trigger('notebook_restoring.Notebook', checkpoint); |
|
2120 | $([IPython.events]).trigger('notebook_restoring.Notebook', checkpoint); | |
2119 | var url = utils.url_join_encode( |
|
2121 | var url = utils.url_join_encode( | |
2120 | this._baseProjectUrl, |
|
2122 | this._baseProjectUrl, | |
2121 | 'api/notebooks', |
|
2123 | 'api/notebooks', | |
2122 | this.notebookPath(), |
|
2124 | this.notebookPath(), | |
2123 | this.notebook_name, |
|
2125 | this.notebook_name, | |
2124 | 'checkpoints', |
|
2126 | 'checkpoints', | |
2125 | checkpoint |
|
2127 | checkpoint | |
2126 | ); |
|
2128 | ); | |
2127 | $.post(url).done( |
|
2129 | $.post(url).done( | |
2128 | $.proxy(this.restore_checkpoint_success, this) |
|
2130 | $.proxy(this.restore_checkpoint_success, this) | |
2129 | ).fail( |
|
2131 | ).fail( | |
2130 | $.proxy(this.restore_checkpoint_error, this) |
|
2132 | $.proxy(this.restore_checkpoint_error, this) | |
2131 | ); |
|
2133 | ); | |
2132 | }; |
|
2134 | }; | |
2133 |
|
2135 | |||
2134 | /** |
|
2136 | /** | |
2135 | * Success callback for restoring a notebook to a checkpoint. |
|
2137 | * Success callback for restoring a notebook to a checkpoint. | |
2136 | * |
|
2138 | * | |
2137 | * @method restore_checkpoint_success |
|
2139 | * @method restore_checkpoint_success | |
2138 | * @param {Object} data (ignored, should be empty) |
|
2140 | * @param {Object} data (ignored, should be empty) | |
2139 | * @param {String} status Description of response status |
|
2141 | * @param {String} status Description of response status | |
2140 | * @param {jqXHR} xhr jQuery Ajax object |
|
2142 | * @param {jqXHR} xhr jQuery Ajax object | |
2141 | */ |
|
2143 | */ | |
2142 | Notebook.prototype.restore_checkpoint_success = function (data, status, xhr) { |
|
2144 | Notebook.prototype.restore_checkpoint_success = function (data, status, xhr) { | |
2143 | $([IPython.events]).trigger('checkpoint_restored.Notebook'); |
|
2145 | $([IPython.events]).trigger('checkpoint_restored.Notebook'); | |
2144 | this.load_notebook(this.notebook_name, this.notebook_path); |
|
2146 | this.load_notebook(this.notebook_name, this.notebook_path); | |
2145 | }; |
|
2147 | }; | |
2146 |
|
2148 | |||
2147 | /** |
|
2149 | /** | |
2148 | * Failure callback for restoring a notebook to a checkpoint. |
|
2150 | * Failure callback for restoring a notebook to a checkpoint. | |
2149 | * |
|
2151 | * | |
2150 | * @method restore_checkpoint_error |
|
2152 | * @method restore_checkpoint_error | |
2151 | * @param {jqXHR} xhr jQuery Ajax object |
|
2153 | * @param {jqXHR} xhr jQuery Ajax object | |
2152 | * @param {String} status Description of response status |
|
2154 | * @param {String} status Description of response status | |
2153 | * @param {String} error_msg HTTP error message |
|
2155 | * @param {String} error_msg HTTP error message | |
2154 | */ |
|
2156 | */ | |
2155 | Notebook.prototype.restore_checkpoint_error = function (xhr, status, error_msg) { |
|
2157 | Notebook.prototype.restore_checkpoint_error = function (xhr, status, error_msg) { | |
2156 | $([IPython.events]).trigger('checkpoint_restore_failed.Notebook'); |
|
2158 | $([IPython.events]).trigger('checkpoint_restore_failed.Notebook'); | |
2157 | }; |
|
2159 | }; | |
2158 |
|
2160 | |||
2159 | /** |
|
2161 | /** | |
2160 | * Delete a notebook checkpoint. |
|
2162 | * Delete a notebook checkpoint. | |
2161 | * |
|
2163 | * | |
2162 | * @method delete_checkpoint |
|
2164 | * @method delete_checkpoint | |
2163 | * @param {String} checkpoint ID |
|
2165 | * @param {String} checkpoint ID | |
2164 | */ |
|
2166 | */ | |
2165 | Notebook.prototype.delete_checkpoint = function (checkpoint) { |
|
2167 | Notebook.prototype.delete_checkpoint = function (checkpoint) { | |
2166 | $([IPython.events]).trigger('notebook_restoring.Notebook', checkpoint); |
|
2168 | $([IPython.events]).trigger('notebook_restoring.Notebook', checkpoint); | |
2167 | var url = utils.url_join_encode( |
|
2169 | var url = utils.url_join_encode( | |
2168 | this._baseProjectUrl, |
|
2170 | this._baseProjectUrl, | |
2169 | 'api/notebooks', |
|
2171 | 'api/notebooks', | |
2170 | this.notebookPath(), |
|
2172 | this.notebookPath(), | |
2171 | this.notebook_name, |
|
2173 | this.notebook_name, | |
2172 | 'checkpoints', |
|
2174 | 'checkpoints', | |
2173 | checkpoint |
|
2175 | checkpoint | |
2174 | ); |
|
2176 | ); | |
2175 | $.ajax(url, { |
|
2177 | $.ajax(url, { | |
2176 | type: 'DELETE', |
|
2178 | type: 'DELETE', | |
2177 | success: $.proxy(this.delete_checkpoint_success, this), |
|
2179 | success: $.proxy(this.delete_checkpoint_success, this), | |
2178 | error: $.proxy(this.delete_notebook_error,this) |
|
2180 | error: $.proxy(this.delete_notebook_error,this) | |
2179 | }); |
|
2181 | }); | |
2180 | }; |
|
2182 | }; | |
2181 |
|
2183 | |||
2182 | /** |
|
2184 | /** | |
2183 | * Success callback for deleting a notebook checkpoint |
|
2185 | * Success callback for deleting a notebook checkpoint | |
2184 | * |
|
2186 | * | |
2185 | * @method delete_checkpoint_success |
|
2187 | * @method delete_checkpoint_success | |
2186 | * @param {Object} data (ignored, should be empty) |
|
2188 | * @param {Object} data (ignored, should be empty) | |
2187 | * @param {String} status Description of response status |
|
2189 | * @param {String} status Description of response status | |
2188 | * @param {jqXHR} xhr jQuery Ajax object |
|
2190 | * @param {jqXHR} xhr jQuery Ajax object | |
2189 | */ |
|
2191 | */ | |
2190 | Notebook.prototype.delete_checkpoint_success = function (data, status, xhr) { |
|
2192 | Notebook.prototype.delete_checkpoint_success = function (data, status, xhr) { | |
2191 | $([IPython.events]).trigger('checkpoint_deleted.Notebook', data); |
|
2193 | $([IPython.events]).trigger('checkpoint_deleted.Notebook', data); | |
2192 | this.load_notebook(this.notebook_name, this.notebook_path); |
|
2194 | this.load_notebook(this.notebook_name, this.notebook_path); | |
2193 | }; |
|
2195 | }; | |
2194 |
|
2196 | |||
2195 | /** |
|
2197 | /** | |
2196 | * Failure callback for deleting a notebook checkpoint. |
|
2198 | * Failure callback for deleting a notebook checkpoint. | |
2197 | * |
|
2199 | * | |
2198 | * @method delete_checkpoint_error |
|
2200 | * @method delete_checkpoint_error | |
2199 | * @param {jqXHR} xhr jQuery Ajax object |
|
2201 | * @param {jqXHR} xhr jQuery Ajax object | |
2200 | * @param {String} status Description of response status |
|
2202 | * @param {String} status Description of response status | |
2201 | * @param {String} error_msg HTTP error message |
|
2203 | * @param {String} error_msg HTTP error message | |
2202 | */ |
|
2204 | */ | |
2203 | Notebook.prototype.delete_checkpoint_error = function (xhr, status, error_msg) { |
|
2205 | Notebook.prototype.delete_checkpoint_error = function (xhr, status, error_msg) { | |
2204 | $([IPython.events]).trigger('checkpoint_delete_failed.Notebook'); |
|
2206 | $([IPython.events]).trigger('checkpoint_delete_failed.Notebook'); | |
2205 | }; |
|
2207 | }; | |
2206 |
|
2208 | |||
2207 |
|
2209 | |||
2208 | IPython.Notebook = Notebook; |
|
2210 | IPython.Notebook = Notebook; | |
2209 |
|
2211 | |||
2210 |
|
2212 | |||
2211 | return IPython; |
|
2213 | return IPython; | |
2212 |
|
2214 | |||
2213 | }(IPython)); No newline at end of file |
|
2215 | }(IPython)); |
@@ -1,468 +1,476 b'' | |||||
1 | //---------------------------------------------------------------------------- |
|
1 | //---------------------------------------------------------------------------- | |
2 | // Copyright (C) 2013 The IPython Development Team |
|
2 | // Copyright (C) 2013 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 | // WidgetModel, WidgetView, and WidgetManager |
|
9 | // WidgetModel, WidgetView, and WidgetManager | |
10 | //============================================================================ |
|
10 | //============================================================================ | |
11 | /** |
|
11 | /** | |
12 | * Base Widget classes |
|
12 | * Base Widget classes | |
13 | * @module IPython |
|
13 | * @module IPython | |
14 | * @namespace IPython |
|
14 | * @namespace IPython | |
15 | * @submodule widget |
|
15 | * @submodule widget | |
16 | */ |
|
16 | */ | |
17 |
|
17 | |||
18 | "use strict"; |
|
18 | "use strict"; | |
19 |
|
19 | |||
20 | // Use require.js 'define' method so that require.js is intelligent enough to |
|
20 | // Use require.js 'define' method so that require.js is intelligent enough to | |
21 | // syncronously load everything within this file when it is being 'required' |
|
21 | // syncronously load everything within this file when it is being 'required' | |
22 | // elsewhere. |
|
22 | // elsewhere. | |
23 | define(["components/underscore/underscore-min", |
|
23 | define(["components/underscore/underscore-min", | |
24 | "components/backbone/backbone-min", |
|
24 | "components/backbone/backbone-min", | |
25 | ], function(){ |
|
25 | ], function(){ | |
26 |
|
26 | |||
27 | // Only run once on a notebook. |
|
|||
28 | if (IPython.notebook.widget_manager == undefined) { |
|
|||
29 |
|
27 | |||
30 |
|
|
28 | //-------------------------------------------------------------------- | |
31 |
|
|
29 | // WidgetModel class | |
32 |
|
|
30 | //-------------------------------------------------------------------- | |
33 |
|
|
31 | var WidgetModel = Backbone.Model.extend({ | |
34 |
|
|
32 | constructor: function(comm_manager, comm, widget_view_types) { | |
35 |
|
|
33 | this.comm_manager = comm_manager; | |
36 |
|
|
34 | this.widget_view_types = widget_view_types; | |
37 |
|
|
35 | this.pending_msgs = 0; | |
38 |
|
|
36 | this.msg_throttle = 3; | |
39 |
|
|
37 | this.msg_buffer = null; | |
40 |
|
|
38 | this.views = {}; | |
41 |
|
39 | |||
42 |
|
|
40 | // Remember comm associated with the model. | |
43 |
|
|
41 | this.comm = comm; | |
44 |
|
|
42 | comm.model = this; | |
45 |
|
43 | |||
46 |
|
|
44 | // Hook comm messages up to model. | |
47 |
|
|
45 | comm.on_close($.proxy(this.handle_comm_closed, this)); | |
48 |
|
|
46 | comm.on_msg($.proxy(this.handle_comm_msg, this)); | |
49 |
|
47 | |||
50 |
|
|
48 | return Backbone.Model.apply(this); | |
51 |
|
|
49 | }, | |
52 |
|
50 | |||
53 |
|
51 | |||
54 |
|
|
52 | update_other_views: function(caller) { | |
55 |
|
|
53 | this.last_modified_view = caller; | |
56 |
|
|
54 | this.save(this.changedAttributes(), {patch: true}); | |
57 |
|
55 | |||
58 |
|
|
56 | for (var output_area in this.views) { | |
59 |
|
|
57 | var views = this.views[output_area]; | |
60 |
|
|
58 | for (var view_index in views) { | |
61 |
|
|
59 | var view = views[view_index]; | |
62 |
|
|
60 | if (view !== caller) { | |
63 |
|
|
61 | view.update(); | |
64 |
|
|
62 | } | |
65 |
|
|
63 | } | |
66 |
|
|
64 | } | |
67 |
|
|
65 | }, | |
68 |
|
66 | |||
69 |
|
67 | |||
70 |
|
|
68 | handle_status: function (output_area, msg) { | |
71 |
|
|
69 | //execution_state : ('busy', 'idle', 'starting') | |
72 |
|
|
70 | if (msg.content.execution_state=='idle') { | |
73 |
|
|
71 | ||
74 |
|
|
72 | // Send buffer if this message caused another message to be | |
75 |
|
|
73 | // throttled. | |
76 |
|
|
74 | if (this.msg_buffer != null && | |
77 |
|
|
75 | this.msg_throttle == this.pending_msgs && | |
78 |
|
|
76 | this.msg_buffer.length > 0) { | |
79 |
|
|
77 | ||
80 |
|
|
78 | var output_area = this._get_msg_output_area(msg); | |
81 |
|
|
79 | var callbacks = this._make_callbacks(output_area); | |
82 |
|
|
80 | var data = {sync_method: 'update', sync_data: this.msg_buffer}; | |
83 |
|
|
81 | comm.send(data, callbacks); | |
84 |
|
|
82 | this.msg_buffer = null; | |
85 |
|
|
83 | } else { | |
86 |
|
84 | |||
87 |
|
|
85 | // Only decrease the pending message count if the buffer | |
88 |
|
|
86 | // doesn't get flushed (sent). | |
89 |
|
|
87 | --this.pending_msgs; | |
90 |
|
|
88 | } | |
91 |
|
|
89 | } | |
92 | } |
|
|||
93 |
|
|
90 | }, | |
94 |
|
91 | |||
95 |
|
92 | |||
96 |
|
|
93 | // Custom syncronization logic. | |
97 |
|
|
94 | handle_sync: function (method, options) { | |
98 |
|
|
95 | var model_json = this.toJSON(); | |
99 |
|
96 | |||
100 |
|
|
97 | // Only send updated state if the state hasn't been changed | |
101 |
|
|
98 | // during an update. | |
102 |
|
|
99 | if (!this.updating) { | |
103 |
|
|
100 | if (this.pending_msgs >= this.msg_throttle) { | |
104 |
|
|
101 | // The throttle has been exceeded, buffer the current msg so | |
105 |
|
|
102 | // it can be sent once the kernel has finished processing | |
106 |
|
|
103 | // some of the existing messages. | |
107 |
|
|
104 | if (method=='patch') { | |
108 |
|
|
105 | if (this.msg_buffer == null) { | |
109 |
|
|
106 | this.msg_buffer = $.extend({}, model_json); // Copy | |
110 |
|
|
107 | } | |
111 |
|
|
108 | for (var attr in options.attrs) { | |
112 |
|
|
109 | this.msg_buffer[attr] = options.attrs[attr]; | |
113 |
|
|
110 | } | |
114 |
|
|
111 | } else { | |
115 |
|
|
112 | this.msg_buffer = $.extend({}, model_json); // Copy | |
116 |
|
|
113 | } | |
117 |
|
114 | |||
118 |
|
|
115 | } else { | |
119 |
|
|
116 | // We haven't exceeded the throttle, send the message like | |
120 |
|
|
117 | // normal. If this is a patch operation, just send the | |
121 |
|
|
118 | // changes. | |
122 |
|
|
119 | var send_json = model_json; | |
123 |
|
|
120 | if (method=='patch') { | |
124 |
|
|
121 | send_json = {}; | |
125 |
|
|
122 | for (var attr in options.attrs) { | |
126 |
|
|
123 | send_json[attr] = options.attrs[attr]; | |
127 |
|
|
124 | } | |
128 |
|
|
125 | } | |
129 |
|
126 | |||
130 |
|
|
127 | var data = {sync_method: method, sync_data: send_json}; | |
131 |
|
|
128 | var output_area = this.last_modified_view.output_area; | |
132 |
|
|
129 | var callbacks = this._make_callbacks(output_area); | |
133 |
|
|
130 | this.comm.send(data, callbacks); | |
134 |
|
|
131 | this.pending_msgs++; | |
135 |
|
|
132 | } | |
136 |
|
|
133 | } | |
137 |
|
|
134 | ||
138 |
|
|
135 | // Since the comm is a one-way communication, assume the message | |
139 |
|
|
136 | // arrived. | |
140 |
|
|
137 | return model_json; | |
141 |
|
|
138 | }, | |
142 |
|
139 | |||
143 |
|
140 | |||
144 |
|
|
141 | // Handle incomming comm msg. | |
145 |
|
|
142 | handle_comm_msg: function (msg) { | |
146 |
|
|
143 | var method = msg.content.data.method; | |
147 |
|
|
144 | switch (method){ | |
148 |
|
|
145 | case 'display': | |
149 |
|
146 | |||
150 |
|
|
147 | // Try to get the cell index. | |
151 |
|
|
148 | var output_area = this._get_output_area(msg.parent_header.msg_id); | |
152 |
|
|
149 | if (output_area == null) { | |
153 |
|
|
150 | console.log("Could not determine where the display" + | |
154 |
|
|
151 | " message was from. Widget will not be displayed") | |
155 |
|
|
152 | } else { | |
156 |
|
|
153 | this.display_view(msg.content.data.view_name, | |
157 |
|
|
154 | msg.content.data.parent, | |
158 |
|
|
155 | output_area); | |
159 |
|
|
156 | } | |
160 |
|
|
157 | break; | |
161 |
|
|
158 | case 'update': | |
162 |
|
|
159 | this.handle_update(msg.content.data.state); | |
163 |
|
|
160 | break; | |
164 |
|
|
161 | } | |
165 |
|
|
162 | }, | |
166 |
|
163 | |||
167 |
|
164 | |||
168 |
|
|
165 | // Handle when a widget is updated via the python side. | |
169 |
|
|
166 | handle_update: function (state) { | |
170 |
|
|
167 | this.updating = true; | |
171 |
|
|
168 | try { | |
172 |
|
|
169 | for (var key in state) { | |
173 |
|
|
170 | if (state.hasOwnProperty(key)) { | |
174 |
|
|
171 | if (key == "_css"){ | |
175 |
|
|
172 | this.css = state[key]; | |
176 |
|
|
173 | } else { | |
177 |
|
|
174 | this.set(key, state[key]); | |
178 |
|
|
175 | } | |
179 |
|
|
176 | } | |
180 |
|
|
177 | } | |
181 |
|
|
178 | this.id = this.comm.comm_id; | |
182 |
|
|
179 | this.save(); | |
183 |
|
|
180 | } finally { | |
184 |
|
|
181 | this.updating = false; | |
185 |
|
|
182 | } | |
186 |
|
|
183 | }, | |
187 |
|
184 | |||
188 |
|
185 | |||
189 |
|
|
186 | // Handle when a widget is closed. | |
190 |
|
|
187 | handle_comm_closed: function (msg) { | |
191 |
|
|
188 | for (var output_area in this.views) { | |
192 |
|
|
189 | var views = this.views[output_area]; | |
193 |
|
|
190 | for (var view_index in views) { | |
194 |
|
|
191 | var view = views[view_index]; | |
195 |
|
|
192 | view.remove(); | |
196 |
|
|
193 | } | |
197 |
|
|
194 | } | |
198 |
|
|
195 | }, | |
199 |
|
196 | |||
200 |
|
197 | |||
201 |
|
|
198 | // Create view that represents the model. | |
202 |
|
|
199 | display_view: function (view_name, parent_comm_id, output_area) { | |
203 |
|
|
200 | var new_views = []; | |
204 |
|
201 | |||
205 |
|
|
202 | var displayed = false; | |
206 |
|
|
203 | if (parent_comm_id != undefined) { | |
207 |
|
|
204 | var parent_comm = this.comm_manager.comms[parent_comm_id]; | |
208 |
|
|
205 | var parent_model = parent_comm.model; | |
209 |
|
|
206 | var parent_views = parent_model.views[output_area]; | |
210 |
|
|
207 | for (var parent_view_index in parent_views) { | |
211 |
|
|
208 | var parent_view = parent_views[parent_view_index]; | |
212 |
|
|
209 | if (parent_view.display_child != undefined) { | |
213 |
|
|
210 | var view = this._create_view(view_name, output_area); | |
214 |
|
|
211 | new_views.push(view); | |
215 |
|
|
212 | parent_view.display_child(view); | |
216 |
|
|
213 | displayed = true; | |
217 |
|
|
214 | } | |
218 |
|
|
215 | } | |
219 |
|
|
216 | } | |
220 |
|
217 | |||
221 |
|
|
218 | if (!displayed) { | |
222 |
|
|
219 | // No parent view is defined or exists. Add the view's | |
223 |
|
|
220 | // element to cell's widget div. | |
224 |
|
|
221 | var view = this._create_view(view_name, output_area); | |
225 |
|
|
222 | new_views.push(view); | |
226 |
|
|
223 | this._get_widget_area_element(output_area, true) | |
227 |
|
|
224 | .append(view.$el); | |
228 |
|
|
225 | ||
229 |
|
|
226 | } | |
230 |
|
227 | |||
231 |
|
|
228 | for (var view_index in new_views) { | |
232 |
|
|
229 | var view = new_views[view_index]; | |
233 |
|
|
230 | view.update(); | |
234 |
|
|
231 | } | |
235 |
|
|
232 | }, | |
236 |
|
233 | |||
237 |
|
234 | |||
238 |
|
|
235 | // Create a view | |
239 |
|
|
236 | _create_view: function (view_name, output_area) { | |
240 |
|
|
237 | var view = new this.widget_view_types[view_name]({model: this}); | |
241 |
|
|
238 | view.render(); | |
242 |
|
|
239 | if (this.views[output_area]==undefined) { | |
243 |
|
|
240 | this.views[output_area] = [] | |
244 |
|
|
241 | } | |
245 |
|
|
242 | this.views[output_area].push(view); | |
246 |
|
|
243 | view.output_area = output_area; | |
247 |
|
244 | |||
248 |
|
|
245 | // Handle when the view element is remove from the page. | |
249 |
|
|
246 | var that = this; | |
250 |
|
|
247 | view.$el.on("remove", function(){ | |
251 |
|
|
248 | var index = that.views[output_area].indexOf(view); | |
252 |
|
|
249 | if (index > -1) { | |
253 |
|
|
250 | that.views[output_area].splice(index, 1); | |
254 |
|
|
251 | } | |
255 |
|
|
252 | view.remove(); // Clean-up view | |
256 |
|
|
253 | if (that.views[output_area].length()==0) { | |
257 |
|
|
254 | delete that.views[output_area]; | |
258 |
|
|
255 | } | |
259 |
|
256 | |||
260 |
|
|
257 | // Close the comm if there are no views left. | |
261 |
|
|
258 | if (that.views.length()==0) { | |
262 |
|
|
259 | that.comm.close(); | |
263 |
|
|
260 | } | |
264 |
|
|
261 | }); | |
265 |
|
|
262 | return view; | |
266 |
|
|
263 | }, | |
267 |
|
264 | |||
268 |
|
265 | |||
269 |
|
|
266 | // Build a callback dict. | |
270 |
|
|
267 | _make_callbacks: function (output_area) { | |
271 |
|
|
268 | var callbacks = {}; | |
272 |
|
|
269 | if (output_area != null) { | |
273 |
|
|
270 | var that = this; | |
274 |
|
|
271 | callbacks = { | |
275 |
|
|
272 | iopub : { | |
276 |
|
|
273 | output : $.proxy(output_area.handle_output, output_area), | |
277 |
|
|
274 | clear_output : $.proxy(output_area.handle_clear_output, output_area), | |
278 |
|
|
275 | status : function(msg){ | |
279 |
|
|
276 | that.handle_status(output_area, msg); | |
280 |
|
|
277 | }, | |
281 |
|
|
278 | get_output_area : function() { | |
282 |
|
|
279 | if (that.last_modified_view != undefined && | |
283 |
|
|
280 | that.last_modified_view.output_area != undefined) { | |
284 |
|
|
281 | return that.last_modified_view.output_area; | |
285 |
|
|
282 | } else { | |
286 |
|
|
283 | return null | |
287 |
|
|
284 | } | |
288 |
|
|
285 | }, | |
289 |
|
|
286 | }, | |
290 |
|
|
287 | }; | |
291 |
|
|
288 | } | |
292 |
|
|
289 | return callbacks; | |
293 |
|
|
290 | }, | |
294 |
|
291 | |||
295 |
|
292 | |||
296 |
|
|
293 | // Get the output area corresponding to the msg_id. | |
297 |
|
|
294 | // output_area is an instance of Ipython.OutputArea | |
298 |
|
|
295 | _get_output_area: function (msg_id) { | |
299 |
|
|
296 | ||
300 |
|
|
297 | // First, guess cell.execute triggered | |
301 |
|
|
298 | var cells = IPython.notebook.get_cells(); | |
302 |
|
|
299 | for (var cell_index in cells) { | |
303 |
|
|
300 | if (cells[cell_index].last_msg_id == msg_id) { | |
304 |
|
|
301 | var cell = IPython.notebook.get_cell(cell_index) | |
305 |
|
|
302 | return cell.output_area; | |
306 |
|
|
303 | } | |
307 |
|
|
304 | } | |
308 |
|
305 | |||
309 |
|
|
306 | // Second, guess widget triggered | |
310 |
|
|
307 | var callbacks = this.comm_manager.kernel.get_callbacks_for_msg(msg_id) | |
311 |
|
|
308 | if (callbacks != undefined && callbacks.iopub != undefined && callbacks.iopub.get_output_area != undefined) { | |
312 |
|
|
309 | var output_area = callbacks.iopub.get_output_area(); | |
313 |
|
|
310 | if (output_area != null) { | |
314 |
|
|
311 | return output_area; | |
315 |
|
|
312 | } | |
316 |
|
|
313 | } | |
317 |
|
|
314 | ||
318 |
|
|
315 | // Not triggered by a widget or a cell | |
319 |
|
|
316 | return null; | |
320 |
|
|
317 | }, | |
321 |
|
318 | |||
322 |
|
|
319 | // Gets widget output area (as a JQuery element) from the | |
323 |
|
|
320 | // output_area (Ipython.OutputArea instance) | |
324 |
|
|
321 | _get_widget_area_element: function (output_area, show) { | |
325 |
|
|
322 | var widget_area = output_area.element | |
326 |
|
|
323 | .parent() // output_wrapper | |
327 |
|
|
324 | .parent() // cell | |
328 |
|
|
325 | .find('.widget-area'); | |
329 |
|
|
326 | if (show) { widget_area.show(); } | |
330 |
|
|
327 | return widget_area.find('.widget-subarea'); | |
331 |
|
|
328 | }, | |
332 |
|
329 | |||
333 |
|
|
330 | }); | |
334 |
|
331 | |||
335 |
|
332 | |||
336 |
|
|
333 | //-------------------------------------------------------------------- | |
337 |
|
|
334 | // WidgetView class | |
338 |
|
|
335 | //-------------------------------------------------------------------- | |
339 |
|
|
336 | var WidgetView = Backbone.View.extend({ | |
340 |
|
|
337 | ||
341 |
|
|
338 | initialize: function() { | |
342 |
|
|
339 | this.visible = true; | |
343 |
|
|
340 | this.model.on('change',this.update,this); | |
344 |
|
|
341 | this._add_class_calls = this.model.get('_add_class')[0]; | |
345 |
|
|
342 | this._remove_class_calls = this.model.get('_remove_class')[0]; | |
346 |
|
|
343 | }, | |
347 |
|
|
344 | ||
348 |
|
|
345 | update: function() { | |
349 |
|
|
346 | if (this.model.get('visible') != undefined) { | |
350 |
|
|
347 | if (this.visible != this.model.get('visible')) { | |
351 |
|
|
348 | this.visible = this.model.get('visible'); | |
352 |
|
|
349 | if (this.visible) { | |
353 |
|
|
350 | this.$el.show(); | |
354 |
|
|
351 | } else { | |
355 |
|
|
352 | this.$el.hide(); | |
356 |
|
|
353 | } | |
357 |
|
|
354 | } | |
358 |
|
|
355 | } | |
359 |
|
356 | |||
360 |
|
|
357 | if (this.model.css != undefined) { | |
361 |
|
|
358 | for (var selector in this.model.css) { | |
362 |
|
|
359 | if (this.model.css.hasOwnProperty(selector)) { | |
363 |
|
|
360 | ||
364 |
|
|
361 | // Apply the css traits to all elements that match the selector. | |
365 |
|
|
362 | var elements = this.get_selector_element(selector); | |
366 |
|
|
363 | if (elements.length > 0) { | |
367 |
|
|
364 | var css_traits = this.model.css[selector]; | |
368 |
|
|
365 | for (var css_key in css_traits) { | |
369 |
|
|
366 | if (css_traits.hasOwnProperty(css_key)) { | |
370 |
|
|
367 | elements.css(css_key, css_traits[css_key]); | |
371 |
|
|
368 | } | |
372 |
|
|
369 | } | |
373 |
|
|
370 | } | |
374 |
|
|
371 | } | |
375 |
|
|
372 | } | |
376 |
|
|
373 | } | |
377 |
|
374 | |||
378 |
|
|
375 | var add_class = this.model.get('_add_class'); | |
379 |
|
|
376 | if (add_class != undefined){ | |
380 |
|
|
377 | var add_class_calls = add_class[0]; | |
381 |
|
|
378 | if (add_class_calls > this._add_class_calls) { | |
382 |
|
|
379 | this._add_class_calls = add_class_calls; | |
383 |
|
|
380 | var elements = this.get_selector_element(add_class[1]); | |
384 |
|
|
381 | if (elements.length > 0) { | |
385 |
|
|
382 | elements.addClass(add_class[2]); | |
386 |
|
|
383 | } | |
387 |
|
|
384 | } | |
388 |
|
|
385 | } | |
389 |
|
386 | |||
390 |
|
|
387 | var remove_class = this.model.get('_remove_class'); | |
391 |
|
|
388 | if (remove_class != undefined){ | |
392 |
|
|
389 | var remove_class_calls = remove_class[0]; | |
393 |
|
|
390 | if (remove_class_calls > this._remove_class_calls) { | |
394 |
|
|
391 | this._remove_class_calls = remove_class_calls; | |
395 |
|
|
392 | var elements = this.get_selector_element(remove_class[1]); | |
396 |
|
|
393 | if (elements.length > 0) { | |
397 |
|
|
394 | elements.removeClass(remove_class[2]); | |
398 |
|
|
395 | } | |
399 |
|
|
396 | } | |
400 |
|
|
397 | } | |
401 |
|
|
398 | }, | |
402 |
|
399 | |||
403 |
|
|
400 | get_selector_element: function(selector) { | |
404 |
|
|
401 | // Get the elements via the css selector. If the selector is | |
405 |
|
|
402 | // blank, apply the style to the $el_to_style element. If | |
406 |
|
|
403 | // the $el_to_style element is not defined, use apply the | |
407 |
|
|
404 | // style to the view's element. | |
408 |
|
|
405 | var elements = this.$el.find(selector); | |
409 |
|
|
406 | if (selector=='') { | |
410 |
|
|
407 | if (this.$el_to_style == undefined) { | |
411 |
|
|
408 | elements = this.$el; | |
412 |
|
|
409 | } else { | |
413 |
|
|
410 | elements = this.$el_to_style; | |
414 |
|
|
411 | } | |
415 |
|
|
412 | } | |
416 |
|
|
413 | return elements; | |
417 |
|
|
414 | }, | |
418 |
|
|
415 | }); | |
419 |
|
416 | |||
420 |
|
417 | |||
421 |
|
|
418 | //-------------------------------------------------------------------- | |
422 |
|
|
419 | // WidgetManager class | |
423 |
|
|
420 | //-------------------------------------------------------------------- | |
424 |
|
|
421 | var WidgetManager = function(){ | |
425 |
|
|
422 | this.comm_manager = null; | |
426 |
|
|
423 | this.widget_model_types = {}; | |
427 |
|
|
424 | this.widget_view_types = {}; | |
428 |
|
|
425 | ||
429 |
|
|
426 | var that = this; | |
430 |
|
|
427 | Backbone.sync = function(method, model, options, error) { | |
431 |
|
|
428 | var result = model.handle_sync(method, options); | |
432 |
|
|
429 | if (options.success) { | |
433 |
|
|
430 | options.success(result); | |
434 |
|
|
431 | } | |
435 |
|
|
432 | }; | |
436 |
|
|
433 | } | |
437 |
|
434 | |||
438 |
|
435 | |||
|
436 | WidgetManager.prototype.attach_comm_manager = function (comm_manager) { | |||
|
437 | this.comm_manager = comm_manager; | |||
|
438 | ||||
|
439 | // Register already register widget model types with the comm manager. | |||
|
440 | for (var widget_model_name in this.widget_model_types) { | |||
|
441 | this.comm_manager.register_target(widget_model_name, $.proxy(this.handle_com_open, this)); | |||
|
442 | } | |||
|
443 | } | |||
|
444 | ||||
|
445 | ||||
439 |
|
|
446 | WidgetManager.prototype.register_widget_model = function (widget_model_name, widget_model_type) { | |
440 |
|
|
447 | // Register the widget with the comm manager. Make sure to pass this object's context | |
441 |
|
|
448 | // in so `this` works in the call back. | |
|
449 | if (this.comm_manager!=null) { | |||
442 | this.comm_manager.register_target(widget_model_name, $.proxy(this.handle_com_open, this)); |
|
450 | this.comm_manager.register_target(widget_model_name, $.proxy(this.handle_com_open, this)); | |
|
451 | } | |||
443 |
|
|
452 | this.widget_model_types[widget_model_name] = widget_model_type; | |
444 |
|
|
453 | } | |
445 |
|
454 | |||
446 |
|
455 | |||
447 |
|
|
456 | WidgetManager.prototype.register_widget_view = function (widget_view_name, widget_view_type) { | |
448 |
|
|
457 | this.widget_view_types[widget_view_name] = widget_view_type; | |
449 |
|
|
458 | } | |
450 |
|
459 | |||
451 |
|
460 | |||
452 |
|
|
461 | WidgetManager.prototype.handle_com_open = function (comm, msg) { | |
453 |
|
|
462 | var widget_type_name = msg.content.target_name; | |
454 |
|
|
463 | var widget_model = new this.widget_model_types[widget_type_name](this.comm_manager, comm, this.widget_view_types); | |
455 |
|
|
464 | } | |
456 |
|
465 | |||
457 |
|
466 | |||
458 |
|
|
467 | //-------------------------------------------------------------------- | |
459 |
|
|
468 | // Init code | |
460 |
|
|
469 | //-------------------------------------------------------------------- | |
461 |
|
|
470 | IPython.WidgetManager = WidgetManager; | |
462 |
|
|
471 | IPython.WidgetModel = WidgetModel; | |
463 |
|
|
472 | IPython.WidgetView = WidgetView; | |
464 |
|
473 | |||
465 |
|
|
474 | IPython.widget_manager = new WidgetManager(); | |
466 |
|
475 | |||
467 | }; |
|
|||
468 | }); |
|
476 | }); |
@@ -1,109 +1,109 b'' | |||||
1 |
|
1 | |||
2 |
|
|
2 | define(["notebook/js/widget"], function(){ | |
3 |
|
3 | |||
4 | var BoolWidgetModel = IPython.WidgetModel.extend({}); |
|
4 | var BoolWidgetModel = IPython.WidgetModel.extend({}); | |
5 |
IPython |
|
5 | IPython.widget_manager.register_widget_model('BoolWidgetModel', BoolWidgetModel); | |
6 |
|
6 | |||
7 | var CheckboxView = IPython.WidgetView.extend({ |
|
7 | var CheckboxView = IPython.WidgetView.extend({ | |
8 |
|
8 | |||
9 | // Called when view is rendered. |
|
9 | // Called when view is rendered. | |
10 | render : function(){ |
|
10 | render : function(){ | |
11 | this.$el = $('<div />') |
|
11 | this.$el = $('<div />') | |
12 | .addClass('widget-hbox-single'); |
|
12 | .addClass('widget-hbox-single'); | |
13 | this.$label = $('<div />') |
|
13 | this.$label = $('<div />') | |
14 | .addClass('widget-hlabel') |
|
14 | .addClass('widget-hlabel') | |
15 | .appendTo(this.$el) |
|
15 | .appendTo(this.$el) | |
16 | .hide(); |
|
16 | .hide(); | |
17 | var that = this; |
|
17 | var that = this; | |
18 | this.$checkbox = $('<input />') |
|
18 | this.$checkbox = $('<input />') | |
19 | .attr('type', 'checkbox') |
|
19 | .attr('type', 'checkbox') | |
20 | .click(function(el) { |
|
20 | .click(function(el) { | |
21 | that.user_invoked_update = true; |
|
21 | that.user_invoked_update = true; | |
22 | that.model.set('value', that.$checkbox.prop('checked')); |
|
22 | that.model.set('value', that.$checkbox.prop('checked')); | |
23 | that.model.update_other_views(that); |
|
23 | that.model.update_other_views(that); | |
24 | that.user_invoked_update = false; |
|
24 | that.user_invoked_update = false; | |
25 | }) |
|
25 | }) | |
26 | .appendTo(this.$el); |
|
26 | .appendTo(this.$el); | |
27 |
|
27 | |||
28 | this.$el_to_style = this.$checkbox; // Set default element to style |
|
28 | this.$el_to_style = this.$checkbox; // Set default element to style | |
29 | this.update(); // Set defaults. |
|
29 | this.update(); // Set defaults. | |
30 | }, |
|
30 | }, | |
31 |
|
31 | |||
32 | // Handles: Backend -> Frontend Sync |
|
32 | // Handles: Backend -> Frontend Sync | |
33 | // Frontent -> Frontend Sync |
|
33 | // Frontent -> Frontend Sync | |
34 | update : function(){ |
|
34 | update : function(){ | |
35 | if (!this.user_invoked_update) { |
|
35 | if (!this.user_invoked_update) { | |
36 | this.$checkbox.prop('checked', this.model.get('value')); |
|
36 | this.$checkbox.prop('checked', this.model.get('value')); | |
37 |
|
37 | |||
38 | var disabled = this.model.get('disabled'); |
|
38 | var disabled = this.model.get('disabled'); | |
39 | this.$checkbox.prop('disabled', disabled); |
|
39 | this.$checkbox.prop('disabled', disabled); | |
40 |
|
40 | |||
41 | var description = this.model.get('description'); |
|
41 | var description = this.model.get('description'); | |
42 | if (description.length == 0) { |
|
42 | if (description.length == 0) { | |
43 | this.$label.hide(); |
|
43 | this.$label.hide(); | |
44 | } else { |
|
44 | } else { | |
45 | this.$label.html(description); |
|
45 | this.$label.html(description); | |
46 | this.$label.show(); |
|
46 | this.$label.show(); | |
47 | } |
|
47 | } | |
48 | } |
|
48 | } | |
49 | return IPython.WidgetView.prototype.update.call(this); |
|
49 | return IPython.WidgetView.prototype.update.call(this); | |
50 | }, |
|
50 | }, | |
51 |
|
51 | |||
52 | }); |
|
52 | }); | |
53 |
|
53 | |||
54 |
IPython |
|
54 | IPython.widget_manager.register_widget_view('CheckboxView', CheckboxView); | |
55 |
|
55 | |||
56 | var ToggleButtonView = IPython.WidgetView.extend({ |
|
56 | var ToggleButtonView = IPython.WidgetView.extend({ | |
57 |
|
57 | |||
58 | // Called when view is rendered. |
|
58 | // Called when view is rendered. | |
59 | render : function(){ |
|
59 | render : function(){ | |
60 | this.$el |
|
60 | this.$el | |
61 | .html(''); |
|
61 | .html(''); | |
62 |
|
62 | |||
63 | this.$button = $('<button />') |
|
63 | this.$button = $('<button />') | |
64 | .addClass('btn') |
|
64 | .addClass('btn') | |
65 | .attr('type', 'button') |
|
65 | .attr('type', 'button') | |
66 | .attr('data-toggle', 'button') |
|
66 | .attr('data-toggle', 'button') | |
67 | .appendTo(this.$el); |
|
67 | .appendTo(this.$el); | |
68 | this.$el_to_style = this.$button; // Set default element to style |
|
68 | this.$el_to_style = this.$button; // Set default element to style | |
69 |
|
69 | |||
70 | this.update(); // Set defaults. |
|
70 | this.update(); // Set defaults. | |
71 | }, |
|
71 | }, | |
72 |
|
72 | |||
73 | // Handles: Backend -> Frontend Sync |
|
73 | // Handles: Backend -> Frontend Sync | |
74 | // Frontent -> Frontend Sync |
|
74 | // Frontent -> Frontend Sync | |
75 | update : function(){ |
|
75 | update : function(){ | |
76 | if (!this.user_invoked_update) { |
|
76 | if (!this.user_invoked_update) { | |
77 | if (this.model.get('value')) { |
|
77 | if (this.model.get('value')) { | |
78 | this.$button.addClass('active'); |
|
78 | this.$button.addClass('active'); | |
79 | } else { |
|
79 | } else { | |
80 | this.$button.removeClass('active'); |
|
80 | this.$button.removeClass('active'); | |
81 | } |
|
81 | } | |
82 |
|
82 | |||
83 | var disabled = this.model.get('disabled'); |
|
83 | var disabled = this.model.get('disabled'); | |
84 | this.$button.prop('disabled', disabled); |
|
84 | this.$button.prop('disabled', disabled); | |
85 |
|
85 | |||
86 | var description = this.model.get('description'); |
|
86 | var description = this.model.get('description'); | |
87 | if (description.length == 0) { |
|
87 | if (description.length == 0) { | |
88 | this.$button.html(' '); // Preserve button height |
|
88 | this.$button.html(' '); // Preserve button height | |
89 | } else { |
|
89 | } else { | |
90 | this.$button.html(description); |
|
90 | this.$button.html(description); | |
91 | } |
|
91 | } | |
92 | } |
|
92 | } | |
93 | return IPython.WidgetView.prototype.update.call(this); |
|
93 | return IPython.WidgetView.prototype.update.call(this); | |
94 | }, |
|
94 | }, | |
95 |
|
95 | |||
96 | events: {"click button" : "handleClick"}, |
|
96 | events: {"click button" : "handleClick"}, | |
97 |
|
97 | |||
98 | // Handles and validates user input. |
|
98 | // Handles and validates user input. | |
99 | handleClick: function(e) { |
|
99 | handleClick: function(e) { | |
100 | this.user_invoked_update = true; |
|
100 | this.user_invoked_update = true; | |
101 | this.model.set('value', ! $(e.target).hasClass('active')); |
|
101 | this.model.set('value', ! $(e.target).hasClass('active')); | |
102 | this.model.update_other_views(this); |
|
102 | this.model.update_other_views(this); | |
103 | this.user_invoked_update = false; |
|
103 | this.user_invoked_update = false; | |
104 | }, |
|
104 | }, | |
105 | }); |
|
105 | }); | |
106 |
|
106 | |||
107 |
IPython |
|
107 | IPython.widget_manager.register_widget_view('ToggleButtonView', ToggleButtonView); | |
108 |
|
108 | |||
109 | }); |
|
109 | }); |
@@ -1,39 +1,39 b'' | |||||
1 |
|
1 | |||
2 |
|
|
2 | define(["notebook/js/widget"], function(){ | |
3 |
|
3 | |||
4 | var ButtonWidgetModel = IPython.WidgetModel.extend({}); |
|
4 | var ButtonWidgetModel = IPython.WidgetModel.extend({}); | |
5 |
IPython |
|
5 | IPython.widget_manager.register_widget_model('ButtonWidgetModel', ButtonWidgetModel); | |
6 |
|
6 | |||
7 | var ButtonView = IPython.WidgetView.extend({ |
|
7 | var ButtonView = IPython.WidgetView.extend({ | |
8 |
|
8 | |||
9 | // Called when view is rendered. |
|
9 | // Called when view is rendered. | |
10 | render : function(){ |
|
10 | render : function(){ | |
11 | var that = this; |
|
11 | var that = this; | |
12 | this.$el = $("<button />") |
|
12 | this.$el = $("<button />") | |
13 | .addClass('btn') |
|
13 | .addClass('btn') | |
14 | .click(function() { |
|
14 | .click(function() { | |
15 | that.model.set('clicks', that.model.get('clicks') + 1); |
|
15 | that.model.set('clicks', that.model.get('clicks') + 1); | |
16 | that.model.update_other_views(that); |
|
16 | that.model.update_other_views(that); | |
17 | }); |
|
17 | }); | |
18 |
|
18 | |||
19 | this.update(); // Set defaults. |
|
19 | this.update(); // Set defaults. | |
20 | }, |
|
20 | }, | |
21 |
|
21 | |||
22 | // Handles: Backend -> Frontend Sync |
|
22 | // Handles: Backend -> Frontend Sync | |
23 | // Frontent -> Frontend Sync |
|
23 | // Frontent -> Frontend Sync | |
24 | update : function(){ |
|
24 | update : function(){ | |
25 | var description = this.model.get('description'); |
|
25 | var description = this.model.get('description'); | |
26 | if (description.length==0) { |
|
26 | if (description.length==0) { | |
27 | this.$el.html(' '); // Preserve button height |
|
27 | this.$el.html(' '); // Preserve button height | |
28 | } else { |
|
28 | } else { | |
29 | this.$el.html(description); |
|
29 | this.$el.html(description); | |
30 | } |
|
30 | } | |
31 |
|
31 | |||
32 | return IPython.WidgetView.prototype.update.call(this); |
|
32 | return IPython.WidgetView.prototype.update.call(this); | |
33 | }, |
|
33 | }, | |
34 |
|
34 | |||
35 | }); |
|
35 | }); | |
36 |
|
36 | |||
37 |
IPython |
|
37 | IPython.widget_manager.register_widget_view('ButtonView', ButtonView); | |
38 |
|
38 | |||
39 | }); |
|
39 | }); |
@@ -1,46 +1,46 b'' | |||||
1 |
|
|
1 | define(["notebook/js/widget"], function(){ | |
2 | var ContainerModel = IPython.WidgetModel.extend({}); |
|
2 | var ContainerModel = IPython.WidgetModel.extend({}); | |
3 |
IPython |
|
3 | IPython.widget_manager.register_widget_model('ContainerWidgetModel', ContainerModel); | |
4 |
|
4 | |||
5 | var ContainerView = IPython.WidgetView.extend({ |
|
5 | var ContainerView = IPython.WidgetView.extend({ | |
6 |
|
6 | |||
7 | render: function(){ |
|
7 | render: function(){ | |
8 | this.$el = $('<div />') |
|
8 | this.$el = $('<div />') | |
9 | .addClass('widget-container'); |
|
9 | .addClass('widget-container'); | |
10 | }, |
|
10 | }, | |
11 |
|
11 | |||
12 | update: function(){ |
|
12 | update: function(){ | |
13 |
|
13 | |||
14 | // Apply flexible box model properties by adding and removing |
|
14 | // Apply flexible box model properties by adding and removing | |
15 | // corrosponding CSS classes. |
|
15 | // corrosponding CSS classes. | |
16 | // Defined in IPython/html/static/base/less/flexbox.less |
|
16 | // Defined in IPython/html/static/base/less/flexbox.less | |
17 | this.set_flex_property('vbox', this.model.get('_vbox')); |
|
17 | this.set_flex_property('vbox', this.model.get('_vbox')); | |
18 | this.set_flex_property('hbox', this.model.get('_hbox')); |
|
18 | this.set_flex_property('hbox', this.model.get('_hbox')); | |
19 | this.set_flex_property('start', this.model.get('_pack_start')); |
|
19 | this.set_flex_property('start', this.model.get('_pack_start')); | |
20 | this.set_flex_property('center', this.model.get('_pack_center')); |
|
20 | this.set_flex_property('center', this.model.get('_pack_center')); | |
21 | this.set_flex_property('end', this.model.get('_pack_end')); |
|
21 | this.set_flex_property('end', this.model.get('_pack_end')); | |
22 | this.set_flex_property('align-start', this.model.get('_align_start')); |
|
22 | this.set_flex_property('align-start', this.model.get('_align_start')); | |
23 | this.set_flex_property('align-center', this.model.get('_align_center')); |
|
23 | this.set_flex_property('align-center', this.model.get('_align_center')); | |
24 | this.set_flex_property('align-end', this.model.get('_align_end')); |
|
24 | this.set_flex_property('align-end', this.model.get('_align_end')); | |
25 | this.set_flex_property('box-flex0', this.model.get('_flex0')); |
|
25 | this.set_flex_property('box-flex0', this.model.get('_flex0')); | |
26 | this.set_flex_property('box-flex1', this.model.get('_flex1')); |
|
26 | this.set_flex_property('box-flex1', this.model.get('_flex1')); | |
27 | this.set_flex_property('box-flex2', this.model.get('_flex2')); |
|
27 | this.set_flex_property('box-flex2', this.model.get('_flex2')); | |
28 |
|
28 | |||
29 | return IPython.WidgetView.prototype.update.call(this); |
|
29 | return IPython.WidgetView.prototype.update.call(this); | |
30 | }, |
|
30 | }, | |
31 |
|
31 | |||
32 | set_flex_property: function(property_name, enabled) { |
|
32 | set_flex_property: function(property_name, enabled) { | |
33 | if (enabled) { |
|
33 | if (enabled) { | |
34 | this.$el.addClass(property_name); |
|
34 | this.$el.addClass(property_name); | |
35 | } else { |
|
35 | } else { | |
36 | this.$el.removeClass(property_name); |
|
36 | this.$el.removeClass(property_name); | |
37 | } |
|
37 | } | |
38 | }, |
|
38 | }, | |
39 |
|
39 | |||
40 | display_child: function(view) { |
|
40 | display_child: function(view) { | |
41 | this.$el.append(view.$el); |
|
41 | this.$el.append(view.$el); | |
42 | }, |
|
42 | }, | |
43 | }); |
|
43 | }); | |
44 |
|
44 | |||
45 |
IPython |
|
45 | IPython.widget_manager.register_widget_view('ContainerView', ContainerView); | |
46 | }); No newline at end of file |
|
46 | }); |
@@ -1,4 +1,4 b'' | |||||
1 |
|
|
1 | define(["notebook/js/widget"], function(){ | |
2 | var FloatWidgetModel = IPython.WidgetModel.extend({}); |
|
2 | var FloatWidgetModel = IPython.WidgetModel.extend({}); | |
3 |
IPython |
|
3 | IPython.widget_manager.register_widget_model('FloatWidgetModel', FloatWidgetModel); | |
4 | }); No newline at end of file |
|
4 | }); |
@@ -1,239 +1,239 b'' | |||||
1 |
|
|
1 | define(["notebook/js/widget"], function(){ | |
2 | var FloatRangeWidgetModel = IPython.WidgetModel.extend({}); |
|
2 | var FloatRangeWidgetModel = IPython.WidgetModel.extend({}); | |
3 |
IPython |
|
3 | IPython.widget_manager.register_widget_model('FloatRangeWidgetModel', FloatRangeWidgetModel); | |
4 |
|
4 | |||
5 | var FloatSliderView = IPython.WidgetView.extend({ |
|
5 | var FloatSliderView = IPython.WidgetView.extend({ | |
6 |
|
6 | |||
7 | // Called when view is rendered. |
|
7 | // Called when view is rendered. | |
8 | render : function(){ |
|
8 | render : function(){ | |
9 | this.$el |
|
9 | this.$el | |
10 | .addClass('widget-hbox-single') |
|
10 | .addClass('widget-hbox-single') | |
11 | .html(''); |
|
11 | .html(''); | |
12 | this.$label = $('<div />') |
|
12 | this.$label = $('<div />') | |
13 | .appendTo(this.$el) |
|
13 | .appendTo(this.$el) | |
14 | .addClass('widget-hlabel') |
|
14 | .addClass('widget-hlabel') | |
15 | .hide(); |
|
15 | .hide(); | |
16 | this.$slider = $('<div />') |
|
16 | this.$slider = $('<div />') | |
17 | .slider({}) |
|
17 | .slider({}) | |
18 | .addClass('slider'); |
|
18 | .addClass('slider'); | |
19 |
|
19 | |||
20 | // Put the slider in a container |
|
20 | // Put the slider in a container | |
21 | this.$slider_container = $('<div />') |
|
21 | this.$slider_container = $('<div />') | |
22 | .addClass('widget-hslider') |
|
22 | .addClass('widget-hslider') | |
23 | .append(this.$slider); |
|
23 | .append(this.$slider); | |
24 | this.$el_to_style = this.$slider_container; // Set default element to style |
|
24 | this.$el_to_style = this.$slider_container; // Set default element to style | |
25 | this.$el.append(this.$slider_container); |
|
25 | this.$el.append(this.$slider_container); | |
26 |
|
26 | |||
27 | // Set defaults. |
|
27 | // Set defaults. | |
28 | this.update(); |
|
28 | this.update(); | |
29 | }, |
|
29 | }, | |
30 |
|
30 | |||
31 | // Handles: Backend -> Frontend Sync |
|
31 | // Handles: Backend -> Frontend Sync | |
32 | // Frontent -> Frontend Sync |
|
32 | // Frontent -> Frontend Sync | |
33 | update : function(){ |
|
33 | update : function(){ | |
34 | // Slider related keys. |
|
34 | // Slider related keys. | |
35 | var _keys = ['step', 'max', 'min', 'disabled']; |
|
35 | var _keys = ['step', 'max', 'min', 'disabled']; | |
36 | for (var index in _keys) { |
|
36 | for (var index in _keys) { | |
37 | var key = _keys[index]; |
|
37 | var key = _keys[index]; | |
38 | if (this.model.get(key) != undefined) { |
|
38 | if (this.model.get(key) != undefined) { | |
39 | this.$slider.slider("option", key, this.model.get(key)); |
|
39 | this.$slider.slider("option", key, this.model.get(key)); | |
40 | } |
|
40 | } | |
41 | } |
|
41 | } | |
42 |
|
42 | |||
43 | // WORKAROUND FOR JQUERY SLIDER BUG. |
|
43 | // WORKAROUND FOR JQUERY SLIDER BUG. | |
44 | // The horizontal position of the slider handle |
|
44 | // The horizontal position of the slider handle | |
45 | // depends on the value of the slider at the time |
|
45 | // depends on the value of the slider at the time | |
46 | // of orientation change. Before applying the new |
|
46 | // of orientation change. Before applying the new | |
47 | // workaround, we set the value to the minimum to |
|
47 | // workaround, we set the value to the minimum to | |
48 | // make sure that the horizontal placement of the |
|
48 | // make sure that the horizontal placement of the | |
49 | // handle in the vertical slider is always |
|
49 | // handle in the vertical slider is always | |
50 | // consistent. |
|
50 | // consistent. | |
51 | var orientation = this.model.get('orientation'); |
|
51 | var orientation = this.model.get('orientation'); | |
52 | var value = this.model.get('min'); |
|
52 | var value = this.model.get('min'); | |
53 | this.$slider.slider('option', 'value', value); |
|
53 | this.$slider.slider('option', 'value', value); | |
54 | this.$slider.slider('option', 'orientation', orientation); |
|
54 | this.$slider.slider('option', 'orientation', orientation); | |
55 | var value = this.model.get('value'); |
|
55 | var value = this.model.get('value'); | |
56 | this.$slider.slider('option', 'value', value); |
|
56 | this.$slider.slider('option', 'value', value); | |
57 |
|
57 | |||
58 | // Use the right CSS classes for vertical & horizontal sliders |
|
58 | // Use the right CSS classes for vertical & horizontal sliders | |
59 | if (orientation=='vertical') { |
|
59 | if (orientation=='vertical') { | |
60 | this.$slider_container |
|
60 | this.$slider_container | |
61 | .removeClass('widget-hslider') |
|
61 | .removeClass('widget-hslider') | |
62 | .addClass('widget-vslider'); |
|
62 | .addClass('widget-vslider'); | |
63 | this.$el |
|
63 | this.$el | |
64 | .removeClass('widget-hbox-single') |
|
64 | .removeClass('widget-hbox-single') | |
65 | .addClass('widget-vbox-single'); |
|
65 | .addClass('widget-vbox-single'); | |
66 | this.$label |
|
66 | this.$label | |
67 | .removeClass('widget-hlabel') |
|
67 | .removeClass('widget-hlabel') | |
68 | .addClass('widget-vlabel'); |
|
68 | .addClass('widget-vlabel'); | |
69 |
|
69 | |||
70 | } else { |
|
70 | } else { | |
71 | this.$slider_container |
|
71 | this.$slider_container | |
72 | .removeClass('widget-vslider') |
|
72 | .removeClass('widget-vslider') | |
73 | .addClass('widget-hslider'); |
|
73 | .addClass('widget-hslider'); | |
74 | this.$el |
|
74 | this.$el | |
75 | .removeClass('widget-vbox-single') |
|
75 | .removeClass('widget-vbox-single') | |
76 | .addClass('widget-hbox-single'); |
|
76 | .addClass('widget-hbox-single'); | |
77 | this.$label |
|
77 | this.$label | |
78 | .removeClass('widget-vlabel') |
|
78 | .removeClass('widget-vlabel') | |
79 | .addClass('widget-hlabel'); |
|
79 | .addClass('widget-hlabel'); | |
80 | } |
|
80 | } | |
81 |
|
81 | |||
82 | var description = this.model.get('description'); |
|
82 | var description = this.model.get('description'); | |
83 | if (description.length == 0) { |
|
83 | if (description.length == 0) { | |
84 | this.$label.hide(); |
|
84 | this.$label.hide(); | |
85 | } else { |
|
85 | } else { | |
86 | this.$label.html(description); |
|
86 | this.$label.html(description); | |
87 | this.$label.show(); |
|
87 | this.$label.show(); | |
88 | } |
|
88 | } | |
89 | return IPython.WidgetView.prototype.update.call(this); |
|
89 | return IPython.WidgetView.prototype.update.call(this); | |
90 | }, |
|
90 | }, | |
91 |
|
91 | |||
92 | // Handles: User input |
|
92 | // Handles: User input | |
93 | events: { "slide" : "handleSliderChange" }, |
|
93 | events: { "slide" : "handleSliderChange" }, | |
94 | handleSliderChange: function(e, ui) { |
|
94 | handleSliderChange: function(e, ui) { | |
95 | this.model.set('value', ui.value); |
|
95 | this.model.set('value', ui.value); | |
96 | this.model.update_other_views(this); |
|
96 | this.model.update_other_views(this); | |
97 | }, |
|
97 | }, | |
98 | }); |
|
98 | }); | |
99 |
|
99 | |||
100 |
IPython |
|
100 | IPython.widget_manager.register_widget_view('FloatSliderView', FloatSliderView); | |
101 |
|
101 | |||
102 |
|
102 | |||
103 | var FloatTextView = IPython.WidgetView.extend({ |
|
103 | var FloatTextView = IPython.WidgetView.extend({ | |
104 |
|
104 | |||
105 | // Called when view is rendered. |
|
105 | // Called when view is rendered. | |
106 | render : function(){ |
|
106 | render : function(){ | |
107 | this.$el |
|
107 | this.$el | |
108 | .addClass('widget-hbox-single') |
|
108 | .addClass('widget-hbox-single') | |
109 | .html(''); |
|
109 | .html(''); | |
110 | this.$label = $('<div />') |
|
110 | this.$label = $('<div />') | |
111 | .appendTo(this.$el) |
|
111 | .appendTo(this.$el) | |
112 | .addClass('widget-hlabel') |
|
112 | .addClass('widget-hlabel') | |
113 | .hide(); |
|
113 | .hide(); | |
114 | this.$textbox = $('<input type="text" />') |
|
114 | this.$textbox = $('<input type="text" />') | |
115 | .addClass('input') |
|
115 | .addClass('input') | |
116 | .addClass('widget-numeric-text') |
|
116 | .addClass('widget-numeric-text') | |
117 | .appendTo(this.$el); |
|
117 | .appendTo(this.$el); | |
118 | this.$el_to_style = this.$textbox; // Set default element to style |
|
118 | this.$el_to_style = this.$textbox; // Set default element to style | |
119 | this.update(); // Set defaults. |
|
119 | this.update(); // Set defaults. | |
120 | }, |
|
120 | }, | |
121 |
|
121 | |||
122 | // Handles: Backend -> Frontend Sync |
|
122 | // Handles: Backend -> Frontend Sync | |
123 | // Frontent -> Frontend Sync |
|
123 | // Frontent -> Frontend Sync | |
124 | update : function(){ |
|
124 | update : function(){ | |
125 | var value = this.model.get('value'); |
|
125 | var value = this.model.get('value'); | |
126 | if (!this.changing && parseFloat(this.$textbox.val()) != value) { |
|
126 | if (!this.changing && parseFloat(this.$textbox.val()) != value) { | |
127 | this.$textbox.val(value); |
|
127 | this.$textbox.val(value); | |
128 | } |
|
128 | } | |
129 |
|
129 | |||
130 | if (this.model.get('disabled')) { |
|
130 | if (this.model.get('disabled')) { | |
131 | this.$textbox.attr('disabled','disabled'); |
|
131 | this.$textbox.attr('disabled','disabled'); | |
132 | } else { |
|
132 | } else { | |
133 | this.$textbox.removeAttr('disabled'); |
|
133 | this.$textbox.removeAttr('disabled'); | |
134 | } |
|
134 | } | |
135 |
|
135 | |||
136 | var description = this.model.get('description'); |
|
136 | var description = this.model.get('description'); | |
137 | if (description.length == 0) { |
|
137 | if (description.length == 0) { | |
138 | this.$label.hide(); |
|
138 | this.$label.hide(); | |
139 | } else { |
|
139 | } else { | |
140 | this.$label.html(description); |
|
140 | this.$label.html(description); | |
141 | this.$label.show(); |
|
141 | this.$label.show(); | |
142 | } |
|
142 | } | |
143 | return IPython.WidgetView.prototype.update.call(this); |
|
143 | return IPython.WidgetView.prototype.update.call(this); | |
144 | }, |
|
144 | }, | |
145 |
|
145 | |||
146 |
|
146 | |||
147 | events: {"keyup input" : "handleChanging", |
|
147 | events: {"keyup input" : "handleChanging", | |
148 | "paste input" : "handleChanging", |
|
148 | "paste input" : "handleChanging", | |
149 | "cut input" : "handleChanging", |
|
149 | "cut input" : "handleChanging", | |
150 | "change input" : "handleChanged"}, // Fires only when control is validated or looses focus. |
|
150 | "change input" : "handleChanged"}, // Fires only when control is validated or looses focus. | |
151 |
|
151 | |||
152 | // Handles and validates user input. |
|
152 | // Handles and validates user input. | |
153 | handleChanging: function(e) { |
|
153 | handleChanging: function(e) { | |
154 |
|
154 | |||
155 | // Try to parse value as a float. |
|
155 | // Try to parse value as a float. | |
156 | var numericalValue = 0.0; |
|
156 | var numericalValue = 0.0; | |
157 | if (e.target.value != '') { |
|
157 | if (e.target.value != '') { | |
158 | numericalValue = parseFloat(e.target.value); |
|
158 | numericalValue = parseFloat(e.target.value); | |
159 | } |
|
159 | } | |
160 |
|
160 | |||
161 | // If parse failed, reset value to value stored in model. |
|
161 | // If parse failed, reset value to value stored in model. | |
162 | if (isNaN(numericalValue)) { |
|
162 | if (isNaN(numericalValue)) { | |
163 | e.target.value = this.model.get('value'); |
|
163 | e.target.value = this.model.get('value'); | |
164 | } else if (!isNaN(numericalValue)) { |
|
164 | } else if (!isNaN(numericalValue)) { | |
165 | if (this.model.get('max') != undefined) { |
|
165 | if (this.model.get('max') != undefined) { | |
166 | numericalValue = Math.min(this.model.get('max'), numericalValue); |
|
166 | numericalValue = Math.min(this.model.get('max'), numericalValue); | |
167 | } |
|
167 | } | |
168 | if (this.model.get('min') != undefined) { |
|
168 | if (this.model.get('min') != undefined) { | |
169 | numericalValue = Math.max(this.model.get('min'), numericalValue); |
|
169 | numericalValue = Math.max(this.model.get('min'), numericalValue); | |
170 | } |
|
170 | } | |
171 |
|
171 | |||
172 | // Apply the value if it has changed. |
|
172 | // Apply the value if it has changed. | |
173 | if (numericalValue != this.model.get('value')) { |
|
173 | if (numericalValue != this.model.get('value')) { | |
174 | this.changing = true; |
|
174 | this.changing = true; | |
175 | this.model.set('value', numericalValue); |
|
175 | this.model.set('value', numericalValue); | |
176 | this.model.update_other_views(this); |
|
176 | this.model.update_other_views(this); | |
177 | this.changing = false; |
|
177 | this.changing = false; | |
178 | } |
|
178 | } | |
179 | } |
|
179 | } | |
180 | }, |
|
180 | }, | |
181 |
|
181 | |||
182 | // Applies validated input. |
|
182 | // Applies validated input. | |
183 | handleChanged: function(e) { |
|
183 | handleChanged: function(e) { | |
184 | // Update the textbox |
|
184 | // Update the textbox | |
185 | if (this.model.get('value') != e.target.value) { |
|
185 | if (this.model.get('value') != e.target.value) { | |
186 | e.target.value = this.model.get('value'); |
|
186 | e.target.value = this.model.get('value'); | |
187 | } |
|
187 | } | |
188 | } |
|
188 | } | |
189 | }); |
|
189 | }); | |
190 |
|
190 | |||
191 |
IPython |
|
191 | IPython.widget_manager.register_widget_view('FloatTextView', FloatTextView); | |
192 |
|
192 | |||
193 |
|
193 | |||
194 | var ProgressView = IPython.WidgetView.extend({ |
|
194 | var ProgressView = IPython.WidgetView.extend({ | |
195 |
|
195 | |||
196 | // Called when view is rendered. |
|
196 | // Called when view is rendered. | |
197 | render : function(){ |
|
197 | render : function(){ | |
198 | this.$el |
|
198 | this.$el | |
199 | .addClass('widget-hbox-single') |
|
199 | .addClass('widget-hbox-single') | |
200 | .html(''); |
|
200 | .html(''); | |
201 | this.$label = $('<div />') |
|
201 | this.$label = $('<div />') | |
202 | .appendTo(this.$el) |
|
202 | .appendTo(this.$el) | |
203 | .addClass('widget-hlabel') |
|
203 | .addClass('widget-hlabel') | |
204 | .hide(); |
|
204 | .hide(); | |
205 | this.$progress = $('<div />') |
|
205 | this.$progress = $('<div />') | |
206 | .addClass('progress') |
|
206 | .addClass('progress') | |
207 | .addClass('widget-progress') |
|
207 | .addClass('widget-progress') | |
208 | .appendTo(this.$el); |
|
208 | .appendTo(this.$el); | |
209 | this.$el_to_style = this.$progress; // Set default element to style |
|
209 | this.$el_to_style = this.$progress; // Set default element to style | |
210 | this.$bar = $('<div />') |
|
210 | this.$bar = $('<div />') | |
211 | .addClass('bar') |
|
211 | .addClass('bar') | |
212 | .css('width', '50%') |
|
212 | .css('width', '50%') | |
213 | .appendTo(this.$progress); |
|
213 | .appendTo(this.$progress); | |
214 | this.update(); // Set defaults. |
|
214 | this.update(); // Set defaults. | |
215 | }, |
|
215 | }, | |
216 |
|
216 | |||
217 | // Handles: Backend -> Frontend Sync |
|
217 | // Handles: Backend -> Frontend Sync | |
218 | // Frontent -> Frontend Sync |
|
218 | // Frontent -> Frontend Sync | |
219 | update : function(){ |
|
219 | update : function(){ | |
220 | var value = this.model.get('value'); |
|
220 | var value = this.model.get('value'); | |
221 | var max = this.model.get('max'); |
|
221 | var max = this.model.get('max'); | |
222 | var min = this.model.get('min'); |
|
222 | var min = this.model.get('min'); | |
223 | var percent = 100.0 * (value - min) / (max - min); |
|
223 | var percent = 100.0 * (value - min) / (max - min); | |
224 | this.$bar.css('width', percent + '%'); |
|
224 | this.$bar.css('width', percent + '%'); | |
225 |
|
225 | |||
226 | var description = this.model.get('description'); |
|
226 | var description = this.model.get('description'); | |
227 | if (description.length == 0) { |
|
227 | if (description.length == 0) { | |
228 | this.$label.hide(); |
|
228 | this.$label.hide(); | |
229 | } else { |
|
229 | } else { | |
230 | this.$label.html(description); |
|
230 | this.$label.html(description); | |
231 | this.$label.show(); |
|
231 | this.$label.show(); | |
232 | } |
|
232 | } | |
233 | return IPython.WidgetView.prototype.update.call(this); |
|
233 | return IPython.WidgetView.prototype.update.call(this); | |
234 | }, |
|
234 | }, | |
235 |
|
235 | |||
236 | }); |
|
236 | }); | |
237 |
|
237 | |||
238 |
IPython |
|
238 | IPython.widget_manager.register_widget_view('ProgressView', ProgressView); | |
239 | }); |
|
239 | }); |
@@ -1,4 +1,4 b'' | |||||
1 |
|
|
1 | define(["notebook/js/widget"], function(){ | |
2 | var IntWidgetModel = IPython.WidgetModel.extend({}); |
|
2 | var IntWidgetModel = IPython.WidgetModel.extend({}); | |
3 |
IPython |
|
3 | IPython.widget_manager.register_widget_model('IntWidgetModel', IntWidgetModel); | |
4 | }); No newline at end of file |
|
4 | }); |
@@ -1,191 +1,191 b'' | |||||
1 |
|
|
1 | define(["notebook/js/widget"], function(){ | |
2 | var IntRangeWidgetModel = IPython.WidgetModel.extend({}); |
|
2 | var IntRangeWidgetModel = IPython.WidgetModel.extend({}); | |
3 |
IPython |
|
3 | IPython.widget_manager.register_widget_model('IntRangeWidgetModel', IntRangeWidgetModel); | |
4 |
|
4 | |||
5 | var IntSliderView = IPython.WidgetView.extend({ |
|
5 | var IntSliderView = IPython.WidgetView.extend({ | |
6 |
|
6 | |||
7 | // Called when view is rendered. |
|
7 | // Called when view is rendered. | |
8 | render : function(){ |
|
8 | render : function(){ | |
9 | this.$el |
|
9 | this.$el | |
10 | .addClass('widget-hbox-single') |
|
10 | .addClass('widget-hbox-single') | |
11 | .html(''); |
|
11 | .html(''); | |
12 | this.$label = $('<div />') |
|
12 | this.$label = $('<div />') | |
13 | .appendTo(this.$el) |
|
13 | .appendTo(this.$el) | |
14 | .addClass('widget-hlabel') |
|
14 | .addClass('widget-hlabel') | |
15 | .hide(); |
|
15 | .hide(); | |
16 | this.$slider = $('<div />') |
|
16 | this.$slider = $('<div />') | |
17 | .slider({}) |
|
17 | .slider({}) | |
18 | .addClass('slider'); |
|
18 | .addClass('slider'); | |
19 |
|
19 | |||
20 | // Put the slider in a container |
|
20 | // Put the slider in a container | |
21 | this.$slider_container = $('<div />') |
|
21 | this.$slider_container = $('<div />') | |
22 | .addClass('widget-hslider') |
|
22 | .addClass('widget-hslider') | |
23 | .append(this.$slider); |
|
23 | .append(this.$slider); | |
24 | this.$el_to_style = this.$slider_container; // Set default element to style |
|
24 | this.$el_to_style = this.$slider_container; // Set default element to style | |
25 | this.$el.append(this.$slider_container); |
|
25 | this.$el.append(this.$slider_container); | |
26 |
|
26 | |||
27 | // Set defaults. |
|
27 | // Set defaults. | |
28 | this.update(); |
|
28 | this.update(); | |
29 | }, |
|
29 | }, | |
30 |
|
30 | |||
31 | // Handles: Backend -> Frontend Sync |
|
31 | // Handles: Backend -> Frontend Sync | |
32 | // Frontent -> Frontend Sync |
|
32 | // Frontent -> Frontend Sync | |
33 | update : function(){ |
|
33 | update : function(){ | |
34 | // Slider related keys. |
|
34 | // Slider related keys. | |
35 | var _keys = ['step', 'max', 'min', 'disabled']; |
|
35 | var _keys = ['step', 'max', 'min', 'disabled']; | |
36 | for (var index in _keys) { |
|
36 | for (var index in _keys) { | |
37 | var key = _keys[index]; |
|
37 | var key = _keys[index]; | |
38 | if (this.model.get(key) != undefined) { |
|
38 | if (this.model.get(key) != undefined) { | |
39 | this.$slider.slider("option", key, this.model.get(key)); |
|
39 | this.$slider.slider("option", key, this.model.get(key)); | |
40 | } |
|
40 | } | |
41 | } |
|
41 | } | |
42 |
|
42 | |||
43 | // WORKAROUND FOR JQUERY SLIDER BUG. |
|
43 | // WORKAROUND FOR JQUERY SLIDER BUG. | |
44 | // The horizontal position of the slider handle |
|
44 | // The horizontal position of the slider handle | |
45 | // depends on the value of the slider at the time |
|
45 | // depends on the value of the slider at the time | |
46 | // of orientation change. Before applying the new |
|
46 | // of orientation change. Before applying the new | |
47 | // workaround, we set the value to the minimum to |
|
47 | // workaround, we set the value to the minimum to | |
48 | // make sure that the horizontal placement of the |
|
48 | // make sure that the horizontal placement of the | |
49 | // handle in the vertical slider is always |
|
49 | // handle in the vertical slider is always | |
50 | // consistent. |
|
50 | // consistent. | |
51 | var orientation = this.model.get('orientation'); |
|
51 | var orientation = this.model.get('orientation'); | |
52 | var value = this.model.get('min'); |
|
52 | var value = this.model.get('min'); | |
53 | this.$slider.slider('option', 'value', value); |
|
53 | this.$slider.slider('option', 'value', value); | |
54 | this.$slider.slider('option', 'orientation', orientation); |
|
54 | this.$slider.slider('option', 'orientation', orientation); | |
55 | var value = this.model.get('value'); |
|
55 | var value = this.model.get('value'); | |
56 | this.$slider.slider('option', 'value', value); |
|
56 | this.$slider.slider('option', 'value', value); | |
57 |
|
57 | |||
58 | // Use the right CSS classes for vertical & horizontal sliders |
|
58 | // Use the right CSS classes for vertical & horizontal sliders | |
59 | if (orientation=='vertical') { |
|
59 | if (orientation=='vertical') { | |
60 | this.$slider_container |
|
60 | this.$slider_container | |
61 | .removeClass('widget-hslider') |
|
61 | .removeClass('widget-hslider') | |
62 | .addClass('widget-vslider'); |
|
62 | .addClass('widget-vslider'); | |
63 | this.$el |
|
63 | this.$el | |
64 | .removeClass('widget-hbox-single') |
|
64 | .removeClass('widget-hbox-single') | |
65 | .addClass('widget-vbox-single'); |
|
65 | .addClass('widget-vbox-single'); | |
66 | this.$label |
|
66 | this.$label | |
67 | .removeClass('widget-hlabel') |
|
67 | .removeClass('widget-hlabel') | |
68 | .addClass('widget-vlabel'); |
|
68 | .addClass('widget-vlabel'); | |
69 |
|
69 | |||
70 | } else { |
|
70 | } else { | |
71 | this.$slider_container |
|
71 | this.$slider_container | |
72 | .removeClass('widget-vslider') |
|
72 | .removeClass('widget-vslider') | |
73 | .addClass('widget-hslider'); |
|
73 | .addClass('widget-hslider'); | |
74 | this.$el |
|
74 | this.$el | |
75 | .removeClass('widget-vbox-single') |
|
75 | .removeClass('widget-vbox-single') | |
76 | .addClass('widget-hbox-single'); |
|
76 | .addClass('widget-hbox-single'); | |
77 | this.$label |
|
77 | this.$label | |
78 | .removeClass('widget-vlabel') |
|
78 | .removeClass('widget-vlabel') | |
79 | .addClass('widget-hlabel'); |
|
79 | .addClass('widget-hlabel'); | |
80 | } |
|
80 | } | |
81 |
|
81 | |||
82 | var description = this.model.get('description'); |
|
82 | var description = this.model.get('description'); | |
83 | if (description.length == 0) { |
|
83 | if (description.length == 0) { | |
84 | this.$label.hide(); |
|
84 | this.$label.hide(); | |
85 | } else { |
|
85 | } else { | |
86 | this.$label.html(description); |
|
86 | this.$label.html(description); | |
87 | this.$label.show(); |
|
87 | this.$label.show(); | |
88 | } |
|
88 | } | |
89 | return IPython.WidgetView.prototype.update.call(this); |
|
89 | return IPython.WidgetView.prototype.update.call(this); | |
90 | }, |
|
90 | }, | |
91 |
|
91 | |||
92 | // Handles: User input |
|
92 | // Handles: User input | |
93 | events: { "slide" : "handleSliderChange" }, |
|
93 | events: { "slide" : "handleSliderChange" }, | |
94 | handleSliderChange: function(e, ui) { |
|
94 | handleSliderChange: function(e, ui) { | |
95 | this.model.set('value', ~~ui.value); // Double bit-wise not to truncate decimel |
|
95 | this.model.set('value', ~~ui.value); // Double bit-wise not to truncate decimel | |
96 | this.model.update_other_views(this); |
|
96 | this.model.update_other_views(this); | |
97 | }, |
|
97 | }, | |
98 | }); |
|
98 | }); | |
99 |
|
99 | |||
100 |
IPython |
|
100 | IPython.widget_manager.register_widget_view('IntSliderView', IntSliderView); | |
101 |
|
101 | |||
102 | var IntTextView = IPython.WidgetView.extend({ |
|
102 | var IntTextView = IPython.WidgetView.extend({ | |
103 |
|
103 | |||
104 | // Called when view is rendered. |
|
104 | // Called when view is rendered. | |
105 | render : function(){ |
|
105 | render : function(){ | |
106 | this.$el |
|
106 | this.$el | |
107 | .addClass('widget-hbox-single') |
|
107 | .addClass('widget-hbox-single') | |
108 | .html(''); |
|
108 | .html(''); | |
109 | this.$label = $('<div />') |
|
109 | this.$label = $('<div />') | |
110 | .appendTo(this.$el) |
|
110 | .appendTo(this.$el) | |
111 | .addClass('widget-hlabel') |
|
111 | .addClass('widget-hlabel') | |
112 | .hide(); |
|
112 | .hide(); | |
113 | this.$textbox = $('<input type="text" />') |
|
113 | this.$textbox = $('<input type="text" />') | |
114 | .addClass('input') |
|
114 | .addClass('input') | |
115 | .addClass('widget-numeric-text') |
|
115 | .addClass('widget-numeric-text') | |
116 | .appendTo(this.$el); |
|
116 | .appendTo(this.$el); | |
117 | this.$el_to_style = this.$textbox; // Set default element to style |
|
117 | this.$el_to_style = this.$textbox; // Set default element to style | |
118 | this.update(); // Set defaults. |
|
118 | this.update(); // Set defaults. | |
119 | }, |
|
119 | }, | |
120 |
|
120 | |||
121 | // Handles: Backend -> Frontend Sync |
|
121 | // Handles: Backend -> Frontend Sync | |
122 | // Frontent -> Frontend Sync |
|
122 | // Frontent -> Frontend Sync | |
123 | update : function(){ |
|
123 | update : function(){ | |
124 | var value = this.model.get('value'); |
|
124 | var value = this.model.get('value'); | |
125 | if (!this.changing && parseInt(this.$textbox.val()) != value) { |
|
125 | if (!this.changing && parseInt(this.$textbox.val()) != value) { | |
126 | this.$textbox.val(value); |
|
126 | this.$textbox.val(value); | |
127 | } |
|
127 | } | |
128 |
|
128 | |||
129 | if (this.model.get('disabled')) { |
|
129 | if (this.model.get('disabled')) { | |
130 | this.$textbox.attr('disabled','disabled'); |
|
130 | this.$textbox.attr('disabled','disabled'); | |
131 | } else { |
|
131 | } else { | |
132 | this.$textbox.removeAttr('disabled'); |
|
132 | this.$textbox.removeAttr('disabled'); | |
133 | } |
|
133 | } | |
134 |
|
134 | |||
135 | var description = this.model.get('description'); |
|
135 | var description = this.model.get('description'); | |
136 | if (description.length == 0) { |
|
136 | if (description.length == 0) { | |
137 | this.$label.hide(); |
|
137 | this.$label.hide(); | |
138 | } else { |
|
138 | } else { | |
139 | this.$label.html(description); |
|
139 | this.$label.html(description); | |
140 | this.$label.show(); |
|
140 | this.$label.show(); | |
141 | } |
|
141 | } | |
142 | return IPython.WidgetView.prototype.update.call(this); |
|
142 | return IPython.WidgetView.prototype.update.call(this); | |
143 | }, |
|
143 | }, | |
144 |
|
144 | |||
145 |
|
145 | |||
146 | events: {"keyup input" : "handleChanging", |
|
146 | events: {"keyup input" : "handleChanging", | |
147 | "paste input" : "handleChanging", |
|
147 | "paste input" : "handleChanging", | |
148 | "cut input" : "handleChanging", |
|
148 | "cut input" : "handleChanging", | |
149 | "change input" : "handleChanged"}, // Fires only when control is validated or looses focus. |
|
149 | "change input" : "handleChanged"}, // Fires only when control is validated or looses focus. | |
150 |
|
150 | |||
151 | // Handles and validates user input. |
|
151 | // Handles and validates user input. | |
152 | handleChanging: function(e) { |
|
152 | handleChanging: function(e) { | |
153 |
|
153 | |||
154 | // Try to parse value as a float. |
|
154 | // Try to parse value as a float. | |
155 | var numericalValue = 0; |
|
155 | var numericalValue = 0; | |
156 | if (e.target.value != '') { |
|
156 | if (e.target.value != '') { | |
157 | numericalValue = parseInt(e.target.value); |
|
157 | numericalValue = parseInt(e.target.value); | |
158 | } |
|
158 | } | |
159 |
|
159 | |||
160 | // If parse failed, reset value to value stored in model. |
|
160 | // If parse failed, reset value to value stored in model. | |
161 | if (isNaN(numericalValue)) { |
|
161 | if (isNaN(numericalValue)) { | |
162 | e.target.value = this.model.get('value'); |
|
162 | e.target.value = this.model.get('value'); | |
163 | } else if (!isNaN(numericalValue)) { |
|
163 | } else if (!isNaN(numericalValue)) { | |
164 | if (this.model.get('max') != undefined) { |
|
164 | if (this.model.get('max') != undefined) { | |
165 | numericalValue = Math.min(this.model.get('max'), numericalValue); |
|
165 | numericalValue = Math.min(this.model.get('max'), numericalValue); | |
166 | } |
|
166 | } | |
167 | if (this.model.get('min') != undefined) { |
|
167 | if (this.model.get('min') != undefined) { | |
168 | numericalValue = Math.max(this.model.get('min'), numericalValue); |
|
168 | numericalValue = Math.max(this.model.get('min'), numericalValue); | |
169 | } |
|
169 | } | |
170 |
|
170 | |||
171 | // Apply the value if it has changed. |
|
171 | // Apply the value if it has changed. | |
172 | if (numericalValue != this.model.get('value')) { |
|
172 | if (numericalValue != this.model.get('value')) { | |
173 | this.changing = true; |
|
173 | this.changing = true; | |
174 | this.model.set('value', numericalValue); |
|
174 | this.model.set('value', numericalValue); | |
175 | this.model.update_other_views(this); |
|
175 | this.model.update_other_views(this); | |
176 | this.changing = false; |
|
176 | this.changing = false; | |
177 | } |
|
177 | } | |
178 | } |
|
178 | } | |
179 | }, |
|
179 | }, | |
180 |
|
180 | |||
181 | // Applies validated input. |
|
181 | // Applies validated input. | |
182 | handleChanged: function(e) { |
|
182 | handleChanged: function(e) { | |
183 | // Update the textbox |
|
183 | // Update the textbox | |
184 | if (this.model.get('value') != e.target.value) { |
|
184 | if (this.model.get('value') != e.target.value) { | |
185 | e.target.value = this.model.get('value'); |
|
185 | e.target.value = this.model.get('value'); | |
186 | } |
|
186 | } | |
187 | } |
|
187 | } | |
188 | }); |
|
188 | }); | |
189 |
|
189 | |||
190 |
IPython |
|
190 | IPython.widget_manager.register_widget_view('IntTextView', IntTextView); | |
191 | }); |
|
191 | }); |
@@ -1,139 +1,139 b'' | |||||
1 |
|
|
1 | define(["notebook/js/widget"], function(){ | |
2 | var MulticontainerModel = IPython.WidgetModel.extend({}); |
|
2 | var MulticontainerModel = IPython.WidgetModel.extend({}); | |
3 |
IPython |
|
3 | IPython.widget_manager.register_widget_model('MulticontainerWidgetModel', MulticontainerModel); | |
4 |
|
4 | |||
5 | var AccordionView = IPython.WidgetView.extend({ |
|
5 | var AccordionView = IPython.WidgetView.extend({ | |
6 |
|
6 | |||
7 | render: function(){ |
|
7 | render: function(){ | |
8 | this.$el = $('<div />', {id: IPython.utils.uuid()}) |
|
8 | this.$el = $('<div />', {id: IPython.utils.uuid()}) | |
9 | .addClass('accordion'); |
|
9 | .addClass('accordion'); | |
10 | this.containers = []; |
|
10 | this.containers = []; | |
11 | }, |
|
11 | }, | |
12 |
|
12 | |||
13 | update: function() { |
|
13 | update: function() { | |
14 | // Set tab titles |
|
14 | // Set tab titles | |
15 | var titles = this.model.get('_titles'); |
|
15 | var titles = this.model.get('_titles'); | |
16 | for (var page_index in titles) { |
|
16 | for (var page_index in titles) { | |
17 |
|
17 | |||
18 | var accordian = this.containers[page_index] |
|
18 | var accordian = this.containers[page_index] | |
19 | if (accordian != undefined) { |
|
19 | if (accordian != undefined) { | |
20 | accordian |
|
20 | accordian | |
21 | .find('.accordion-heading') |
|
21 | .find('.accordion-heading') | |
22 | .find('.accordion-toggle') |
|
22 | .find('.accordion-toggle') | |
23 | .html(titles[page_index]); |
|
23 | .html(titles[page_index]); | |
24 | } |
|
24 | } | |
25 | } |
|
25 | } | |
26 |
|
26 | |||
27 | return IPython.WidgetView.prototype.update.call(this); |
|
27 | return IPython.WidgetView.prototype.update.call(this); | |
28 | }, |
|
28 | }, | |
29 |
|
29 | |||
30 | display_child: function(view) { |
|
30 | display_child: function(view) { | |
31 |
|
31 | |||
32 | var index = this.containers.length; |
|
32 | var index = this.containers.length; | |
33 | var uuid = IPython.utils.uuid(); |
|
33 | var uuid = IPython.utils.uuid(); | |
34 | var accordion_group = $('<div />') |
|
34 | var accordion_group = $('<div />') | |
35 | .addClass('accordion-group') |
|
35 | .addClass('accordion-group') | |
36 | .appendTo(this.$el); |
|
36 | .appendTo(this.$el); | |
37 | var accordion_heading = $('<div />') |
|
37 | var accordion_heading = $('<div />') | |
38 | .addClass('accordion-heading') |
|
38 | .addClass('accordion-heading') | |
39 | .appendTo(accordion_group); |
|
39 | .appendTo(accordion_group); | |
40 | var accordion_toggle = $('<a />') |
|
40 | var accordion_toggle = $('<a />') | |
41 | .addClass('accordion-toggle') |
|
41 | .addClass('accordion-toggle') | |
42 | .attr('data-toggle', 'collapse') |
|
42 | .attr('data-toggle', 'collapse') | |
43 | .attr('data-parent', '#' + this.$el.attr('id')) |
|
43 | .attr('data-parent', '#' + this.$el.attr('id')) | |
44 | .attr('href', '#' + uuid) |
|
44 | .attr('href', '#' + uuid) | |
45 | .html('Page ' + index) |
|
45 | .html('Page ' + index) | |
46 | .appendTo(accordion_heading); |
|
46 | .appendTo(accordion_heading); | |
47 | var accordion_body = $('<div />', {id: uuid}) |
|
47 | var accordion_body = $('<div />', {id: uuid}) | |
48 | .addClass('accordion-body collapse') |
|
48 | .addClass('accordion-body collapse') | |
49 | .appendTo(accordion_group); |
|
49 | .appendTo(accordion_group); | |
50 | var accordion_inner = $('<div />') |
|
50 | var accordion_inner = $('<div />') | |
51 | .addClass('accordion-inner') |
|
51 | .addClass('accordion-inner') | |
52 | .appendTo(accordion_body); |
|
52 | .appendTo(accordion_body); | |
53 | this.containers.push(accordion_group); |
|
53 | this.containers.push(accordion_group); | |
54 |
|
54 | |||
55 | accordion_inner.append(view.$el); |
|
55 | accordion_inner.append(view.$el); | |
56 | this.update(); |
|
56 | this.update(); | |
57 | }, |
|
57 | }, | |
58 | }); |
|
58 | }); | |
59 |
|
59 | |||
60 |
IPython |
|
60 | IPython.widget_manager.register_widget_view('AccordionView', AccordionView); | |
61 |
|
61 | |||
62 | var TabView = IPython.WidgetView.extend({ |
|
62 | var TabView = IPython.WidgetView.extend({ | |
63 |
|
63 | |||
64 | render: function(){ |
|
64 | render: function(){ | |
65 | this.$el = $('<div />'); |
|
65 | this.$el = $('<div />'); | |
66 | var uuid = IPython.utils.uuid(); |
|
66 | var uuid = IPython.utils.uuid(); | |
67 | var that = this; |
|
67 | var that = this; | |
68 | this.$tabs = $('<div />', {id: uuid}) |
|
68 | this.$tabs = $('<div />', {id: uuid}) | |
69 | .addClass('nav') |
|
69 | .addClass('nav') | |
70 | .addClass('nav-tabs') |
|
70 | .addClass('nav-tabs') | |
71 | .appendTo(this.$el); |
|
71 | .appendTo(this.$el); | |
72 | this.$tab_contents = $('<div />', {id: uuid + 'Content'}) |
|
72 | this.$tab_contents = $('<div />', {id: uuid + 'Content'}) | |
73 | .addClass('tab-content') |
|
73 | .addClass('tab-content') | |
74 | .appendTo(this.$el); |
|
74 | .appendTo(this.$el); | |
75 |
|
75 | |||
76 | this.containers = []; |
|
76 | this.containers = []; | |
77 | }, |
|
77 | }, | |
78 |
|
78 | |||
79 | update: function() { |
|
79 | update: function() { | |
80 | // Set tab titles |
|
80 | // Set tab titles | |
81 | var titles = this.model.get('_titles'); |
|
81 | var titles = this.model.get('_titles'); | |
82 | for (var page_index in titles) { |
|
82 | for (var page_index in titles) { | |
83 | var tab_text = this.containers[page_index] |
|
83 | var tab_text = this.containers[page_index] | |
84 | if (tab_text != undefined) { |
|
84 | if (tab_text != undefined) { | |
85 | tab_text.html(titles[page_index]); |
|
85 | tab_text.html(titles[page_index]); | |
86 | } |
|
86 | } | |
87 | } |
|
87 | } | |
88 |
|
88 | |||
89 | var selected_index = this.model.get('selected_index'); |
|
89 | var selected_index = this.model.get('selected_index'); | |
90 | if (0 <= selected_index && selected_index < this.containers.length) { |
|
90 | if (0 <= selected_index && selected_index < this.containers.length) { | |
91 | this.select_page(selected_index); |
|
91 | this.select_page(selected_index); | |
92 | } |
|
92 | } | |
93 |
|
93 | |||
94 | return IPython.WidgetView.prototype.update.call(this); |
|
94 | return IPython.WidgetView.prototype.update.call(this); | |
95 | }, |
|
95 | }, | |
96 |
|
96 | |||
97 | display_child: function(view) { |
|
97 | display_child: function(view) { | |
98 |
|
98 | |||
99 | var index = this.containers.length; |
|
99 | var index = this.containers.length; | |
100 | var uuid = IPython.utils.uuid(); |
|
100 | var uuid = IPython.utils.uuid(); | |
101 |
|
101 | |||
102 | var that = this; |
|
102 | var that = this; | |
103 | var tab = $('<li />') |
|
103 | var tab = $('<li />') | |
104 | .css('list-style-type', 'none') |
|
104 | .css('list-style-type', 'none') | |
105 | .appendTo(this.$tabs); |
|
105 | .appendTo(this.$tabs); | |
106 | var tab_text = $('<a />') |
|
106 | var tab_text = $('<a />') | |
107 | .attr('href', '#' + uuid) |
|
107 | .attr('href', '#' + uuid) | |
108 | .attr('data-toggle', 'tab') |
|
108 | .attr('data-toggle', 'tab') | |
109 | .html('Page ' + index) |
|
109 | .html('Page ' + index) | |
110 | .appendTo(tab) |
|
110 | .appendTo(tab) | |
111 | .click(function (e) { |
|
111 | .click(function (e) { | |
112 | that.model.set("selected_index", index); |
|
112 | that.model.set("selected_index", index); | |
113 | that.model.update_other_views(that); |
|
113 | that.model.update_other_views(that); | |
114 | that.select_page(index); |
|
114 | that.select_page(index); | |
115 | }); |
|
115 | }); | |
116 | this.containers.push(tab_text); |
|
116 | this.containers.push(tab_text); | |
117 |
|
117 | |||
118 | var contents_div = $('<div />', {id: uuid}) |
|
118 | var contents_div = $('<div />', {id: uuid}) | |
119 | .addClass('tab-pane') |
|
119 | .addClass('tab-pane') | |
120 | .addClass('fade') |
|
120 | .addClass('fade') | |
121 | .append(view.$el) |
|
121 | .append(view.$el) | |
122 | .appendTo(this.$tab_contents); |
|
122 | .appendTo(this.$tab_contents); | |
123 |
|
123 | |||
124 | if (index==0) { |
|
124 | if (index==0) { | |
125 | tab_text.tab('show'); |
|
125 | tab_text.tab('show'); | |
126 | } |
|
126 | } | |
127 | this.update(); |
|
127 | this.update(); | |
128 | }, |
|
128 | }, | |
129 |
|
129 | |||
130 | select_page: function(index) { |
|
130 | select_page: function(index) { | |
131 | this.$tabs.find('li') |
|
131 | this.$tabs.find('li') | |
132 | .removeClass('active'); |
|
132 | .removeClass('active'); | |
133 | this.containers[index].tab('show'); |
|
133 | this.containers[index].tab('show'); | |
134 | }, |
|
134 | }, | |
135 | }); |
|
135 | }); | |
136 |
|
136 | |||
137 |
IPython |
|
137 | IPython.widget_manager.register_widget_view('TabView', TabView); | |
138 |
|
138 | |||
139 | }); |
|
139 | }); |
@@ -1,251 +1,251 b'' | |||||
1 |
|
|
1 | define(["notebook/js/widget"], function(){ | |
2 | var SelectionWidgetModel = IPython.WidgetModel.extend({}); |
|
2 | var SelectionWidgetModel = IPython.WidgetModel.extend({}); | |
3 |
IPython |
|
3 | IPython.widget_manager.register_widget_model('SelectionWidgetModel', SelectionWidgetModel); | |
4 |
|
4 | |||
5 | var DropdownView = IPython.WidgetView.extend({ |
|
5 | var DropdownView = IPython.WidgetView.extend({ | |
6 |
|
6 | |||
7 | // Called when view is rendered. |
|
7 | // Called when view is rendered. | |
8 | render : function(){ |
|
8 | render : function(){ | |
9 |
|
9 | |||
10 | this.$el |
|
10 | this.$el | |
11 | .addClass('widget-hbox-single') |
|
11 | .addClass('widget-hbox-single') | |
12 | .html(''); |
|
12 | .html(''); | |
13 | this.$label = $('<div />') |
|
13 | this.$label = $('<div />') | |
14 | .appendTo(this.$el) |
|
14 | .appendTo(this.$el) | |
15 | .addClass('widget-hlabel') |
|
15 | .addClass('widget-hlabel') | |
16 | .hide(); |
|
16 | .hide(); | |
17 | this.$buttongroup = $('<div />') |
|
17 | this.$buttongroup = $('<div />') | |
18 | .addClass('widget_item') |
|
18 | .addClass('widget_item') | |
19 | .addClass('btn-group') |
|
19 | .addClass('btn-group') | |
20 | .appendTo(this.$el); |
|
20 | .appendTo(this.$el); | |
21 | this.$el_to_style = this.$buttongroup; // Set default element to style |
|
21 | this.$el_to_style = this.$buttongroup; // Set default element to style | |
22 | this.$droplabel = $('<button />') |
|
22 | this.$droplabel = $('<button />') | |
23 | .addClass('btn') |
|
23 | .addClass('btn') | |
24 | .addClass('widget-combo-btn') |
|
24 | .addClass('widget-combo-btn') | |
25 | .appendTo(this.$buttongroup); |
|
25 | .appendTo(this.$buttongroup); | |
26 | this.$dropbutton = $('<button />') |
|
26 | this.$dropbutton = $('<button />') | |
27 | .addClass('btn') |
|
27 | .addClass('btn') | |
28 | .addClass('dropdown-toggle') |
|
28 | .addClass('dropdown-toggle') | |
29 | .attr('data-toggle', 'dropdown') |
|
29 | .attr('data-toggle', 'dropdown') | |
30 | .html('<span class="caret"></span>') |
|
30 | .html('<span class="caret"></span>') | |
31 | .appendTo(this.$buttongroup); |
|
31 | .appendTo(this.$buttongroup); | |
32 | this.$droplist = $('<ul />') |
|
32 | this.$droplist = $('<ul />') | |
33 | .addClass('dropdown-menu') |
|
33 | .addClass('dropdown-menu') | |
34 | .appendTo(this.$buttongroup); |
|
34 | .appendTo(this.$buttongroup); | |
35 |
|
35 | |||
36 | // Set defaults. |
|
36 | // Set defaults. | |
37 | this.update(); |
|
37 | this.update(); | |
38 | }, |
|
38 | }, | |
39 |
|
39 | |||
40 | // Handles: Backend -> Frontend Sync |
|
40 | // Handles: Backend -> Frontend Sync | |
41 | // Frontent -> Frontend Sync |
|
41 | // Frontent -> Frontend Sync | |
42 | update : function(){ |
|
42 | update : function(){ | |
43 | this.$droplabel.html(this.model.get('value')); |
|
43 | this.$droplabel.html(this.model.get('value')); | |
44 |
|
44 | |||
45 | var items = this.model.get('values'); |
|
45 | var items = this.model.get('values'); | |
46 | this.$droplist.html(''); |
|
46 | this.$droplist.html(''); | |
47 | for (var index in items) { |
|
47 | for (var index in items) { | |
48 | var that = this; |
|
48 | var that = this; | |
49 | var item_button = $('<a href="#"/>') |
|
49 | var item_button = $('<a href="#"/>') | |
50 | .html(items[index]) |
|
50 | .html(items[index]) | |
51 | .on('click', function(e){ |
|
51 | .on('click', function(e){ | |
52 | that.model.set('value', $(e.target).html(), this); |
|
52 | that.model.set('value', $(e.target).html(), this); | |
53 | that.model.update_other_views(that); |
|
53 | that.model.update_other_views(that); | |
54 | }) |
|
54 | }) | |
55 |
|
55 | |||
56 | this.$droplist.append($('<li />').append(item_button)) |
|
56 | this.$droplist.append($('<li />').append(item_button)) | |
57 | } |
|
57 | } | |
58 |
|
58 | |||
59 | if (this.model.get('disabled')) { |
|
59 | if (this.model.get('disabled')) { | |
60 | this.$buttongroup.attr('disabled','disabled'); |
|
60 | this.$buttongroup.attr('disabled','disabled'); | |
61 | this.$droplabel.attr('disabled','disabled'); |
|
61 | this.$droplabel.attr('disabled','disabled'); | |
62 | this.$dropbutton.attr('disabled','disabled'); |
|
62 | this.$dropbutton.attr('disabled','disabled'); | |
63 | this.$droplist.attr('disabled','disabled'); |
|
63 | this.$droplist.attr('disabled','disabled'); | |
64 | } else { |
|
64 | } else { | |
65 | this.$buttongroup.removeAttr('disabled'); |
|
65 | this.$buttongroup.removeAttr('disabled'); | |
66 | this.$droplabel.removeAttr('disabled'); |
|
66 | this.$droplabel.removeAttr('disabled'); | |
67 | this.$dropbutton.removeAttr('disabled'); |
|
67 | this.$dropbutton.removeAttr('disabled'); | |
68 | this.$droplist.removeAttr('disabled'); |
|
68 | this.$droplist.removeAttr('disabled'); | |
69 | } |
|
69 | } | |
70 |
|
70 | |||
71 | var description = this.model.get('description'); |
|
71 | var description = this.model.get('description'); | |
72 | if (description.length == 0) { |
|
72 | if (description.length == 0) { | |
73 | this.$label.hide(); |
|
73 | this.$label.hide(); | |
74 | } else { |
|
74 | } else { | |
75 | this.$label.html(description); |
|
75 | this.$label.html(description); | |
76 | this.$label.show(); |
|
76 | this.$label.show(); | |
77 | } |
|
77 | } | |
78 | return IPython.WidgetView.prototype.update.call(this); |
|
78 | return IPython.WidgetView.prototype.update.call(this); | |
79 | }, |
|
79 | }, | |
80 |
|
80 | |||
81 | }); |
|
81 | }); | |
82 |
|
82 | |||
83 |
IPython |
|
83 | IPython.widget_manager.register_widget_view('DropdownView', DropdownView); | |
84 |
|
84 | |||
85 | var RadioButtonsView = IPython.WidgetView.extend({ |
|
85 | var RadioButtonsView = IPython.WidgetView.extend({ | |
86 |
|
86 | |||
87 | // Called when view is rendered. |
|
87 | // Called when view is rendered. | |
88 | render : function(){ |
|
88 | render : function(){ | |
89 | this.$el |
|
89 | this.$el | |
90 | .addClass('widget-hbox') |
|
90 | .addClass('widget-hbox') | |
91 | .html(''); |
|
91 | .html(''); | |
92 | this.$label = $('<div />') |
|
92 | this.$label = $('<div />') | |
93 | .appendTo(this.$el) |
|
93 | .appendTo(this.$el) | |
94 | .addClass('widget-hlabel') |
|
94 | .addClass('widget-hlabel') | |
95 | .hide(); |
|
95 | .hide(); | |
96 | this.$container = $('<div />') |
|
96 | this.$container = $('<div />') | |
97 | .appendTo(this.$el) |
|
97 | .appendTo(this.$el) | |
98 | .addClass('widget-container') |
|
98 | .addClass('widget-container') | |
99 | .addClass('vbox'); |
|
99 | .addClass('vbox'); | |
100 | this.$el_to_style = this.$container; // Set default element to style |
|
100 | this.$el_to_style = this.$container; // Set default element to style | |
101 | this.update(); |
|
101 | this.update(); | |
102 | }, |
|
102 | }, | |
103 |
|
103 | |||
104 | // Handles: Backend -> Frontend Sync |
|
104 | // Handles: Backend -> Frontend Sync | |
105 | // Frontent -> Frontend Sync |
|
105 | // Frontent -> Frontend Sync | |
106 | update : function(){ |
|
106 | update : function(){ | |
107 |
|
107 | |||
108 | // Add missing items to the DOM. |
|
108 | // Add missing items to the DOM. | |
109 | var items = this.model.get('values'); |
|
109 | var items = this.model.get('values'); | |
110 | var disabled = this.model.get('disabled'); |
|
110 | var disabled = this.model.get('disabled'); | |
111 | for (var index in items) { |
|
111 | for (var index in items) { | |
112 | var item_query = ' :input[value="' + items[index] + '"]'; |
|
112 | var item_query = ' :input[value="' + items[index] + '"]'; | |
113 | if (this.$el.find(item_query).length == 0) { |
|
113 | if (this.$el.find(item_query).length == 0) { | |
114 | var $label = $('<label />') |
|
114 | var $label = $('<label />') | |
115 | .addClass('radio') |
|
115 | .addClass('radio') | |
116 | .html(items[index]) |
|
116 | .html(items[index]) | |
117 | .appendTo(this.$container); |
|
117 | .appendTo(this.$container); | |
118 |
|
118 | |||
119 | var that = this; |
|
119 | var that = this; | |
120 | $('<input />') |
|
120 | $('<input />') | |
121 | .attr('type', 'radio') |
|
121 | .attr('type', 'radio') | |
122 | .addClass(this.model) |
|
122 | .addClass(this.model) | |
123 | .val(items[index]) |
|
123 | .val(items[index]) | |
124 | .prependTo($label) |
|
124 | .prependTo($label) | |
125 | .on('click', function(e){ |
|
125 | .on('click', function(e){ | |
126 | that.model.set('value', $(e.target).val(), this); |
|
126 | that.model.set('value', $(e.target).val(), this); | |
127 | that.model.update_other_views(that); |
|
127 | that.model.update_other_views(that); | |
128 | }); |
|
128 | }); | |
129 | } |
|
129 | } | |
130 |
|
130 | |||
131 | var $item_element = this.$container.find(item_query); |
|
131 | var $item_element = this.$container.find(item_query); | |
132 | if (this.model.get('value') == items[index]) { |
|
132 | if (this.model.get('value') == items[index]) { | |
133 | $item_element.prop('checked', true); |
|
133 | $item_element.prop('checked', true); | |
134 | } else { |
|
134 | } else { | |
135 | $item_element.prop('checked', false); |
|
135 | $item_element.prop('checked', false); | |
136 | } |
|
136 | } | |
137 | $item_element.prop('disabled', disabled); |
|
137 | $item_element.prop('disabled', disabled); | |
138 | } |
|
138 | } | |
139 |
|
139 | |||
140 | // Remove items that no longer exist. |
|
140 | // Remove items that no longer exist. | |
141 | this.$container.find('input').each(function(i, obj) { |
|
141 | this.$container.find('input').each(function(i, obj) { | |
142 | var value = $(obj).val(); |
|
142 | var value = $(obj).val(); | |
143 | var found = false; |
|
143 | var found = false; | |
144 | for (var index in items) { |
|
144 | for (var index in items) { | |
145 | if (items[index] == value) { |
|
145 | if (items[index] == value) { | |
146 | found = true; |
|
146 | found = true; | |
147 | break; |
|
147 | break; | |
148 | } |
|
148 | } | |
149 | } |
|
149 | } | |
150 |
|
150 | |||
151 | if (!found) { |
|
151 | if (!found) { | |
152 | $(obj).parent().remove(); |
|
152 | $(obj).parent().remove(); | |
153 | } |
|
153 | } | |
154 | }); |
|
154 | }); | |
155 |
|
155 | |||
156 | var description = this.model.get('description'); |
|
156 | var description = this.model.get('description'); | |
157 | if (description.length == 0) { |
|
157 | if (description.length == 0) { | |
158 | this.$label.hide(); |
|
158 | this.$label.hide(); | |
159 | } else { |
|
159 | } else { | |
160 | this.$label.html(description); |
|
160 | this.$label.html(description); | |
161 | this.$label.show(); |
|
161 | this.$label.show(); | |
162 | } |
|
162 | } | |
163 | return IPython.WidgetView.prototype.update.call(this); |
|
163 | return IPython.WidgetView.prototype.update.call(this); | |
164 | }, |
|
164 | }, | |
165 |
|
165 | |||
166 | }); |
|
166 | }); | |
167 |
|
167 | |||
168 |
IPython |
|
168 | IPython.widget_manager.register_widget_view('RadioButtonsView', RadioButtonsView); | |
169 |
|
169 | |||
170 |
|
170 | |||
171 | var ToggleButtonsView = IPython.WidgetView.extend({ |
|
171 | var ToggleButtonsView = IPython.WidgetView.extend({ | |
172 |
|
172 | |||
173 | // Called when view is rendered. |
|
173 | // Called when view is rendered. | |
174 | render : function(){ |
|
174 | render : function(){ | |
175 | this.$el |
|
175 | this.$el | |
176 | .addClass('widget-hbox-single') |
|
176 | .addClass('widget-hbox-single') | |
177 | .html(''); |
|
177 | .html(''); | |
178 | this.$label = $('<div />') |
|
178 | this.$label = $('<div />') | |
179 | .appendTo(this.$el) |
|
179 | .appendTo(this.$el) | |
180 | .addClass('widget-hlabel') |
|
180 | .addClass('widget-hlabel') | |
181 | .hide(); |
|
181 | .hide(); | |
182 | this.$buttongroup = $('<div />') |
|
182 | this.$buttongroup = $('<div />') | |
183 | .addClass('btn-group') |
|
183 | .addClass('btn-group') | |
184 | .attr('data-toggle', 'buttons-radio') |
|
184 | .attr('data-toggle', 'buttons-radio') | |
185 | .appendTo(this.$el); |
|
185 | .appendTo(this.$el); | |
186 | this.$el_to_style = this.$buttongroup; // Set default element to style |
|
186 | this.$el_to_style = this.$buttongroup; // Set default element to style | |
187 | this.update(); |
|
187 | this.update(); | |
188 | }, |
|
188 | }, | |
189 |
|
189 | |||
190 | // Handles: Backend -> Frontend Sync |
|
190 | // Handles: Backend -> Frontend Sync | |
191 | // Frontent -> Frontend Sync |
|
191 | // Frontent -> Frontend Sync | |
192 | update : function(){ |
|
192 | update : function(){ | |
193 |
|
193 | |||
194 | // Add missing items to the DOM. |
|
194 | // Add missing items to the DOM. | |
195 | var items = this.model.get('values'); |
|
195 | var items = this.model.get('values'); | |
196 | var disabled = this.model.get('disabled'); |
|
196 | var disabled = this.model.get('disabled'); | |
197 | for (var index in items) { |
|
197 | for (var index in items) { | |
198 | var item_query = ' :contains("' + items[index] + '")'; |
|
198 | var item_query = ' :contains("' + items[index] + '")'; | |
199 | if (this.$buttongroup.find(item_query).length == 0) { |
|
199 | if (this.$buttongroup.find(item_query).length == 0) { | |
200 |
|
200 | |||
201 | var that = this; |
|
201 | var that = this; | |
202 | $('<button />') |
|
202 | $('<button />') | |
203 | .attr('type', 'button') |
|
203 | .attr('type', 'button') | |
204 | .addClass('btn') |
|
204 | .addClass('btn') | |
205 | .html(items[index]) |
|
205 | .html(items[index]) | |
206 | .appendTo(this.$buttongroup) |
|
206 | .appendTo(this.$buttongroup) | |
207 | .on('click', function(e){ |
|
207 | .on('click', function(e){ | |
208 | that.model.set('value', $(e.target).html(), this); |
|
208 | that.model.set('value', $(e.target).html(), this); | |
209 | that.model.update_other_views(that); |
|
209 | that.model.update_other_views(that); | |
210 | }); |
|
210 | }); | |
211 | } |
|
211 | } | |
212 |
|
212 | |||
213 | var $item_element = this.$buttongroup.find(item_query); |
|
213 | var $item_element = this.$buttongroup.find(item_query); | |
214 | if (this.model.get('value') == items[index]) { |
|
214 | if (this.model.get('value') == items[index]) { | |
215 | $item_element.addClass('active'); |
|
215 | $item_element.addClass('active'); | |
216 | } else { |
|
216 | } else { | |
217 | $item_element.removeClass('active'); |
|
217 | $item_element.removeClass('active'); | |
218 | } |
|
218 | } | |
219 | $item_element.prop('disabled', disabled); |
|
219 | $item_element.prop('disabled', disabled); | |
220 | } |
|
220 | } | |
221 |
|
221 | |||
222 | // Remove items that no longer exist. |
|
222 | // Remove items that no longer exist. | |
223 | this.$buttongroup.find('button').each(function(i, obj) { |
|
223 | this.$buttongroup.find('button').each(function(i, obj) { | |
224 | var value = $(obj).html(); |
|
224 | var value = $(obj).html(); | |
225 | var found = false; |
|
225 | var found = false; | |
226 | for (var index in items) { |
|
226 | for (var index in items) { | |
227 | if (items[index] == value) { |
|
227 | if (items[index] == value) { | |
228 | found = true; |
|
228 | found = true; | |
229 | break; |
|
229 | break; | |
230 | } |
|
230 | } | |
231 | } |
|
231 | } | |
232 |
|
232 | |||
233 | if (!found) { |
|
233 | if (!found) { | |
234 | $(obj).remove(); |
|
234 | $(obj).remove(); | |
235 | } |
|
235 | } | |
236 | }); |
|
236 | }); | |
237 |
|
237 | |||
238 | var description = this.model.get('description'); |
|
238 | var description = this.model.get('description'); | |
239 | if (description.length == 0) { |
|
239 | if (description.length == 0) { | |
240 | this.$label.hide(); |
|
240 | this.$label.hide(); | |
241 | } else { |
|
241 | } else { | |
242 | this.$label.html(description); |
|
242 | this.$label.html(description); | |
243 | this.$label.show(); |
|
243 | this.$label.show(); | |
244 | } |
|
244 | } | |
245 | return IPython.WidgetView.prototype.update.call(this); |
|
245 | return IPython.WidgetView.prototype.update.call(this); | |
246 | }, |
|
246 | }, | |
247 |
|
247 | |||
248 | }); |
|
248 | }); | |
249 |
|
249 | |||
250 |
IPython |
|
250 | IPython.widget_manager.register_widget_view('ToggleButtonsView', ToggleButtonsView); | |
251 | }); |
|
251 | }); |
@@ -1,131 +1,131 b'' | |||||
1 |
|
|
1 | define(["notebook/js/widget"], function(){ | |
2 | var StringWidgetModel = IPython.WidgetModel.extend({}); |
|
2 | var StringWidgetModel = IPython.WidgetModel.extend({}); | |
3 |
IPython |
|
3 | IPython.widget_manager.register_widget_model('StringWidgetModel', StringWidgetModel); | |
4 |
|
4 | |||
5 | var LabelView = IPython.WidgetView.extend({ |
|
5 | var LabelView = IPython.WidgetView.extend({ | |
6 |
|
6 | |||
7 | // Called when view is rendered. |
|
7 | // Called when view is rendered. | |
8 | render : function(){ |
|
8 | render : function(){ | |
9 | this.$el = $('<div />'); |
|
9 | this.$el = $('<div />'); | |
10 | this.update(); // Set defaults. |
|
10 | this.update(); // Set defaults. | |
11 | }, |
|
11 | }, | |
12 |
|
12 | |||
13 | // Handles: Backend -> Frontend Sync |
|
13 | // Handles: Backend -> Frontend Sync | |
14 | // Frontent -> Frontend Sync |
|
14 | // Frontent -> Frontend Sync | |
15 | update : function(){ |
|
15 | update : function(){ | |
16 | this.$el.html(this.model.get('value')); |
|
16 | this.$el.html(this.model.get('value')); | |
17 | return IPython.WidgetView.prototype.update.call(this); |
|
17 | return IPython.WidgetView.prototype.update.call(this); | |
18 | }, |
|
18 | }, | |
19 |
|
19 | |||
20 | }); |
|
20 | }); | |
21 |
|
21 | |||
22 |
IPython |
|
22 | IPython.widget_manager.register_widget_view('LabelView', LabelView); | |
23 |
|
23 | |||
24 | var TextAreaView = IPython.WidgetView.extend({ |
|
24 | var TextAreaView = IPython.WidgetView.extend({ | |
25 |
|
25 | |||
26 | // Called when view is rendered. |
|
26 | // Called when view is rendered. | |
27 | render : function(){ |
|
27 | render : function(){ | |
28 | this.$el |
|
28 | this.$el | |
29 | .addClass('widget-hbox') |
|
29 | .addClass('widget-hbox') | |
30 | .html(''); |
|
30 | .html(''); | |
31 | this.$label = $('<div />') |
|
31 | this.$label = $('<div />') | |
32 | .appendTo(this.$el) |
|
32 | .appendTo(this.$el) | |
33 | .addClass('widget-hlabel') |
|
33 | .addClass('widget-hlabel') | |
34 | .hide(); |
|
34 | .hide(); | |
35 | this.$textbox = $('<textarea />') |
|
35 | this.$textbox = $('<textarea />') | |
36 | .attr('rows', 5) |
|
36 | .attr('rows', 5) | |
37 | .addClass('widget-text') |
|
37 | .addClass('widget-text') | |
38 | .appendTo(this.$el); |
|
38 | .appendTo(this.$el); | |
39 | this.$el_to_style = this.$textbox; // Set default element to style |
|
39 | this.$el_to_style = this.$textbox; // Set default element to style | |
40 | this.update(); // Set defaults. |
|
40 | this.update(); // Set defaults. | |
41 | }, |
|
41 | }, | |
42 |
|
42 | |||
43 | // Handles: Backend -> Frontend Sync |
|
43 | // Handles: Backend -> Frontend Sync | |
44 | // Frontent -> Frontend Sync |
|
44 | // Frontent -> Frontend Sync | |
45 | update : function(){ |
|
45 | update : function(){ | |
46 | if (!this.user_invoked_update) { |
|
46 | if (!this.user_invoked_update) { | |
47 | this.$textbox.val(this.model.get('value')); |
|
47 | this.$textbox.val(this.model.get('value')); | |
48 | } |
|
48 | } | |
49 |
|
49 | |||
50 | var disabled = this.model.get('disabled'); |
|
50 | var disabled = this.model.get('disabled'); | |
51 | this.$textbox.prop('disabled', disabled); |
|
51 | this.$textbox.prop('disabled', disabled); | |
52 |
|
52 | |||
53 | var description = this.model.get('description'); |
|
53 | var description = this.model.get('description'); | |
54 | if (description.length == 0) { |
|
54 | if (description.length == 0) { | |
55 | this.$label.hide(); |
|
55 | this.$label.hide(); | |
56 | } else { |
|
56 | } else { | |
57 | this.$label.html(description); |
|
57 | this.$label.html(description); | |
58 | this.$label.show(); |
|
58 | this.$label.show(); | |
59 | } |
|
59 | } | |
60 | return IPython.WidgetView.prototype.update.call(this); |
|
60 | return IPython.WidgetView.prototype.update.call(this); | |
61 | }, |
|
61 | }, | |
62 |
|
62 | |||
63 | events: {"keyup textarea" : "handleChanging", |
|
63 | events: {"keyup textarea" : "handleChanging", | |
64 | "paste textarea" : "handleChanging", |
|
64 | "paste textarea" : "handleChanging", | |
65 | "cut textarea" : "handleChanging"}, |
|
65 | "cut textarea" : "handleChanging"}, | |
66 |
|
66 | |||
67 | // Handles and validates user input. |
|
67 | // Handles and validates user input. | |
68 | handleChanging: function(e) { |
|
68 | handleChanging: function(e) { | |
69 | this.user_invoked_update = true; |
|
69 | this.user_invoked_update = true; | |
70 | this.model.set('value', e.target.value); |
|
70 | this.model.set('value', e.target.value); | |
71 | this.model.update_other_views(this); |
|
71 | this.model.update_other_views(this); | |
72 | this.user_invoked_update = false; |
|
72 | this.user_invoked_update = false; | |
73 | }, |
|
73 | }, | |
74 | }); |
|
74 | }); | |
75 |
|
75 | |||
76 |
IPython |
|
76 | IPython.widget_manager.register_widget_view('TextAreaView', TextAreaView); | |
77 |
|
77 | |||
78 | var TextBoxView = IPython.WidgetView.extend({ |
|
78 | var TextBoxView = IPython.WidgetView.extend({ | |
79 |
|
79 | |||
80 | // Called when view is rendered. |
|
80 | // Called when view is rendered. | |
81 | render : function(){ |
|
81 | render : function(){ | |
82 | this.$el |
|
82 | this.$el | |
83 | .addClass('widget-hbox-single') |
|
83 | .addClass('widget-hbox-single') | |
84 | .html(''); |
|
84 | .html(''); | |
85 | this.$label = $('<div />') |
|
85 | this.$label = $('<div />') | |
86 | .addClass('widget-hlabel') |
|
86 | .addClass('widget-hlabel') | |
87 | .appendTo(this.$el) |
|
87 | .appendTo(this.$el) | |
88 | .hide(); |
|
88 | .hide(); | |
89 | this.$textbox = $('<input type="text" />') |
|
89 | this.$textbox = $('<input type="text" />') | |
90 | .addClass('input') |
|
90 | .addClass('input') | |
91 | .addClass('widget-text') |
|
91 | .addClass('widget-text') | |
92 | .appendTo(this.$el); |
|
92 | .appendTo(this.$el); | |
93 | this.$el_to_style = this.$textbox; // Set default element to style |
|
93 | this.$el_to_style = this.$textbox; // Set default element to style | |
94 | this.update(); // Set defaults. |
|
94 | this.update(); // Set defaults. | |
95 | }, |
|
95 | }, | |
96 |
|
96 | |||
97 | // Handles: Backend -> Frontend Sync |
|
97 | // Handles: Backend -> Frontend Sync | |
98 | // Frontent -> Frontend Sync |
|
98 | // Frontent -> Frontend Sync | |
99 | update : function(){ |
|
99 | update : function(){ | |
100 | if (!this.user_invoked_update) { |
|
100 | if (!this.user_invoked_update) { | |
101 | this.$textbox.val(this.model.get('value')); |
|
101 | this.$textbox.val(this.model.get('value')); | |
102 | } |
|
102 | } | |
103 |
|
103 | |||
104 | var disabled = this.model.get('disabled'); |
|
104 | var disabled = this.model.get('disabled'); | |
105 | this.$textbox.prop('disabled', disabled); |
|
105 | this.$textbox.prop('disabled', disabled); | |
106 |
|
106 | |||
107 | var description = this.model.get('description'); |
|
107 | var description = this.model.get('description'); | |
108 | if (description.length == 0) { |
|
108 | if (description.length == 0) { | |
109 | this.$label.hide(); |
|
109 | this.$label.hide(); | |
110 | } else { |
|
110 | } else { | |
111 | this.$label.html(description); |
|
111 | this.$label.html(description); | |
112 | this.$label.show(); |
|
112 | this.$label.show(); | |
113 | } |
|
113 | } | |
114 | return IPython.WidgetView.prototype.update.call(this); |
|
114 | return IPython.WidgetView.prototype.update.call(this); | |
115 | }, |
|
115 | }, | |
116 |
|
116 | |||
117 | events: {"keyup input" : "handleChanging", |
|
117 | events: {"keyup input" : "handleChanging", | |
118 | "paste input" : "handleChanging", |
|
118 | "paste input" : "handleChanging", | |
119 | "cut input" : "handleChanging"}, |
|
119 | "cut input" : "handleChanging"}, | |
120 |
|
120 | |||
121 | // Handles and validates user input. |
|
121 | // Handles and validates user input. | |
122 | handleChanging: function(e) { |
|
122 | handleChanging: function(e) { | |
123 | this.user_invoked_update = true; |
|
123 | this.user_invoked_update = true; | |
124 | this.model.set('value', e.target.value); |
|
124 | this.model.set('value', e.target.value); | |
125 | this.model.update_other_views(this); |
|
125 | this.model.update_other_views(this); | |
126 | this.user_invoked_update = false; |
|
126 | this.user_invoked_update = false; | |
127 | }, |
|
127 | }, | |
128 | }); |
|
128 | }); | |
129 |
|
129 | |||
130 |
IPython |
|
130 | IPython.widget_manager.register_widget_view('TextBoxView', TextBoxView); | |
131 | }); |
|
131 | }); |
@@ -1,12 +1,12 b'' | |||||
1 |
from .widget import Widget |
|
1 | from .widget import Widget | |
2 |
|
2 | |||
3 | from .widget_bool import BoolWidget |
|
3 | from .widget_bool import BoolWidget | |
4 | from .widget_button import ButtonWidget |
|
4 | from .widget_button import ButtonWidget | |
5 | from .widget_container import ContainerWidget |
|
5 | from .widget_container import ContainerWidget | |
6 | from .widget_float import FloatWidget |
|
6 | from .widget_float import FloatWidget | |
7 | from .widget_float_range import FloatRangeWidget |
|
7 | from .widget_float_range import FloatRangeWidget | |
8 | from .widget_int import IntWidget |
|
8 | from .widget_int import IntWidget | |
9 | from .widget_int_range import IntRangeWidget |
|
9 | from .widget_int_range import IntRangeWidget | |
10 | from .widget_multicontainer import MulticontainerWidget |
|
10 | from .widget_multicontainer import MulticontainerWidget | |
11 | from .widget_selection import SelectionWidget |
|
11 | from .widget_selection import SelectionWidget | |
12 | from .widget_string import StringWidget |
|
12 | from .widget_string import StringWidget |
@@ -1,365 +1,352 b'' | |||||
1 | """Base Widget class. Allows user to create widgets in the backend that render |
|
1 | """Base Widget class. Allows user to create widgets in the backend that render | |
2 | in the IPython notebook frontend. |
|
2 | in the IPython notebook frontend. | |
3 | """ |
|
3 | """ | |
4 | #----------------------------------------------------------------------------- |
|
4 | #----------------------------------------------------------------------------- | |
5 | # Copyright (c) 2013, the IPython Development Team. |
|
5 | # Copyright (c) 2013, the IPython Development Team. | |
6 | # |
|
6 | # | |
7 | # Distributed under the terms of the Modified BSD License. |
|
7 | # Distributed under the terms of the Modified BSD License. | |
8 | # |
|
8 | # | |
9 | # The full license is in the file COPYING.txt, distributed with this software. |
|
9 | # The full license is in the file COPYING.txt, distributed with this software. | |
10 | #----------------------------------------------------------------------------- |
|
10 | #----------------------------------------------------------------------------- | |
11 |
|
11 | |||
12 | #----------------------------------------------------------------------------- |
|
12 | #----------------------------------------------------------------------------- | |
13 | # Imports |
|
13 | # Imports | |
14 | #----------------------------------------------------------------------------- |
|
14 | #----------------------------------------------------------------------------- | |
15 | from copy import copy |
|
15 | from copy import copy | |
16 | from glob import glob |
|
16 | from glob import glob | |
17 | import uuid |
|
17 | import uuid | |
18 | import sys |
|
18 | import sys | |
19 | import os |
|
19 | import os | |
20 | import inspect |
|
20 | import inspect | |
21 |
|
21 | |||
22 | import IPython |
|
22 | import IPython | |
23 | from IPython.kernel.comm import Comm |
|
23 | from IPython.kernel.comm import Comm | |
24 | from IPython.config import LoggingConfigurable |
|
24 | from IPython.config import LoggingConfigurable | |
25 | from IPython.utils.traitlets import Unicode, Dict, List, Instance, Bool |
|
25 | from IPython.utils.traitlets import Unicode, Dict, List, Instance, Bool | |
26 | from IPython.display import Javascript, display |
|
26 | from IPython.display import Javascript, display | |
27 | from IPython.utils.py3compat import string_types |
|
27 | from IPython.utils.py3compat import string_types | |
28 |
|
28 | |||
29 | #----------------------------------------------------------------------------- |
|
|||
30 | # Shared |
|
|||
31 | #----------------------------------------------------------------------------- |
|
|||
32 | def init_widget_js(): |
|
|||
33 | path = os.path.split(os.path.abspath( __file__ ))[0] |
|
|||
34 | for filepath in glob(os.path.join(path, "*.py")): |
|
|||
35 | filename = os.path.split(filepath)[1] |
|
|||
36 | name = filename.rsplit('.', 1)[0] |
|
|||
37 | if not (name == 'widget' or name == '__init__') and name.startswith('widget_'): |
|
|||
38 | # Remove 'widget_' from the start of the name before compiling the path. |
|
|||
39 | js_path = 'static/notebook/js/widgets/%s.js' % name[7:] |
|
|||
40 | display(Javascript(data='$.getScript($("body").data("baseProjectUrl") + "%s");' % js_path), exclude="text/plain") |
|
|||
41 |
|
||||
42 |
|
29 | |||
43 | #----------------------------------------------------------------------------- |
|
30 | #----------------------------------------------------------------------------- | |
44 | # Classes |
|
31 | # Classes | |
45 | #----------------------------------------------------------------------------- |
|
32 | #----------------------------------------------------------------------------- | |
46 | class Widget(LoggingConfigurable): |
|
33 | class Widget(LoggingConfigurable): | |
47 |
|
34 | |||
48 | # Shared declarations |
|
35 | # Shared declarations | |
49 | _keys = [] |
|
36 | _keys = [] | |
50 |
|
37 | |||
51 | # Public declarations |
|
38 | # Public declarations | |
52 | target_name = Unicode('widget', help="""Name of the backbone model |
|
39 | target_name = Unicode('widget', help="""Name of the backbone model | |
53 | registered in the frontend to create and sync this widget with.""") |
|
40 | registered in the frontend to create and sync this widget with.""") | |
54 | default_view_name = Unicode(help="""Default view registered in the frontend |
|
41 | default_view_name = Unicode(help="""Default view registered in the frontend | |
55 | to use to represent the widget.""") |
|
42 | to use to represent the widget.""") | |
56 | parent = Instance('IPython.html.widgets.widget.Widget') |
|
43 | parent = Instance('IPython.html.widgets.widget.Widget') | |
57 | visible = Bool(True, help="Whether or not the widget is visible.") |
|
44 | visible = Bool(True, help="Whether or not the widget is visible.") | |
58 |
|
45 | |||
59 | def _parent_changed(self, name, old, new): |
|
46 | def _parent_changed(self, name, old, new): | |
60 | if self._displayed: |
|
47 | if self._displayed: | |
61 | raise Exception('Parent cannot be set because widget has been displayed.') |
|
48 | raise Exception('Parent cannot be set because widget has been displayed.') | |
62 | elif new == self: |
|
49 | elif new == self: | |
63 | raise Exception('Parent cannot be set to self.') |
|
50 | raise Exception('Parent cannot be set to self.') | |
64 | else: |
|
51 | else: | |
65 |
|
52 | |||
66 | # Parent/child association |
|
53 | # Parent/child association | |
67 | if new is not None and not self in new._children: |
|
54 | if new is not None and not self in new._children: | |
68 | new._children.append(self) |
|
55 | new._children.append(self) | |
69 | if old is not None and self in old._children: |
|
56 | if old is not None and self in old._children: | |
70 | old._children.remove(self) |
|
57 | old._children.remove(self) | |
71 |
|
58 | |||
72 | # Private/protected declarations |
|
59 | # Private/protected declarations | |
73 | _property_lock = False |
|
60 | _property_lock = False | |
74 | _css = Dict() # Internal CSS property dict |
|
61 | _css = Dict() # Internal CSS property dict | |
75 | _add_class = List() # Used to add a js class to a DOM element (call#, selector, class_name) |
|
62 | _add_class = List() # Used to add a js class to a DOM element (call#, selector, class_name) | |
76 | _remove_class = List() # Used to remove a js class from a DOM element (call#, selector, class_name) |
|
63 | _remove_class = List() # Used to remove a js class from a DOM element (call#, selector, class_name) | |
77 | _displayed = False |
|
64 | _displayed = False | |
78 | _comm = None |
|
65 | _comm = None | |
79 |
|
66 | |||
80 |
|
67 | |||
81 | def __init__(self, **kwargs): |
|
68 | def __init__(self, **kwargs): | |
82 | """Public constructor |
|
69 | """Public constructor | |
83 |
|
70 | |||
84 | Parameters |
|
71 | Parameters | |
85 | ---------- |
|
72 | ---------- | |
86 | parent : Widget instance (optional) |
|
73 | parent : Widget instance (optional) | |
87 | Widget that this widget instance is child of. When the widget is |
|
74 | Widget that this widget instance is child of. When the widget is | |
88 | displayed in the frontend, it's corresponding view will be made |
|
75 | displayed in the frontend, it's corresponding view will be made | |
89 | child of the parent's view if the parent's view exists already. If |
|
76 | child of the parent's view if the parent's view exists already. If | |
90 | the parent's view is displayed, it will automatically display this |
|
77 | the parent's view is displayed, it will automatically display this | |
91 | widget's default view as it's child. The default view can be set |
|
78 | widget's default view as it's child. The default view can be set | |
92 | via the default_view_name property. |
|
79 | via the default_view_name property. | |
93 | """ |
|
80 | """ | |
94 | self._children = [] |
|
81 | self._children = [] | |
95 | self._add_class = [0] |
|
82 | self._add_class = [0] | |
96 | self._remove_class = [0] |
|
83 | self._remove_class = [0] | |
97 | self._display_callbacks = [] |
|
84 | self._display_callbacks = [] | |
98 | super(Widget, self).__init__(**kwargs) |
|
85 | super(Widget, self).__init__(**kwargs) | |
99 |
|
86 | |||
100 | # Register after init to allow default values to be specified |
|
87 | # Register after init to allow default values to be specified | |
101 | self.on_trait_change(self._handle_property_changed, self.keys) |
|
88 | self.on_trait_change(self._handle_property_changed, self.keys) | |
102 |
|
89 | |||
103 |
|
90 | |||
104 | def __del__(self): |
|
91 | def __del__(self): | |
105 | """Object disposal""" |
|
92 | """Object disposal""" | |
106 | self.close() |
|
93 | self.close() | |
107 |
|
94 | |||
108 |
|
95 | |||
109 | def close(self): |
|
96 | def close(self): | |
110 | """Close method. Closes the widget which closes the underlying comm. |
|
97 | """Close method. Closes the widget which closes the underlying comm. | |
111 | When the comm is closed, all of the widget views are automatically |
|
98 | When the comm is closed, all of the widget views are automatically | |
112 | removed from the frontend.""" |
|
99 | removed from the frontend.""" | |
113 | self._comm.close() |
|
100 | self._comm.close() | |
114 | del self._comm |
|
101 | del self._comm | |
115 |
|
102 | |||
116 |
|
103 | |||
117 | # Properties |
|
104 | # Properties | |
118 | def _get_keys(self): |
|
105 | def _get_keys(self): | |
119 | keys = ['visible', '_css', '_add_class', '_remove_class'] |
|
106 | keys = ['visible', '_css', '_add_class', '_remove_class'] | |
120 | keys.extend(self._keys) |
|
107 | keys.extend(self._keys) | |
121 | return keys |
|
108 | return keys | |
122 | keys = property(_get_keys) |
|
109 | keys = property(_get_keys) | |
123 |
|
110 | |||
124 |
|
111 | |||
125 | # Event handlers |
|
112 | # Event handlers | |
126 | def _handle_msg(self, msg): |
|
113 | def _handle_msg(self, msg): | |
127 | """Called when a msg is recieved from the frontend""" |
|
114 | """Called when a msg is recieved from the frontend""" | |
128 | # Handle backbone sync methods CREATE, PATCH, and UPDATE |
|
115 | # Handle backbone sync methods CREATE, PATCH, and UPDATE | |
129 | sync_method = msg['content']['data']['sync_method'] |
|
116 | sync_method = msg['content']['data']['sync_method'] | |
130 | sync_data = msg['content']['data']['sync_data'] |
|
117 | sync_data = msg['content']['data']['sync_data'] | |
131 | self._handle_recieve_state(sync_data) # handles all methods |
|
118 | self._handle_recieve_state(sync_data) # handles all methods | |
132 |
|
119 | |||
133 |
|
120 | |||
134 | def _handle_recieve_state(self, sync_data): |
|
121 | def _handle_recieve_state(self, sync_data): | |
135 | """Called when a state is recieved from the frontend.""" |
|
122 | """Called when a state is recieved from the frontend.""" | |
136 | self._property_lock = True |
|
123 | self._property_lock = True | |
137 | try: |
|
124 | try: | |
138 |
|
125 | |||
139 | # Use _keys instead of keys - Don't get retrieve the css from the client side. |
|
126 | # Use _keys instead of keys - Don't get retrieve the css from the client side. | |
140 | for name in self._keys: |
|
127 | for name in self._keys: | |
141 | if name in sync_data: |
|
128 | if name in sync_data: | |
142 | setattr(self, name, sync_data[name]) |
|
129 | setattr(self, name, sync_data[name]) | |
143 | finally: |
|
130 | finally: | |
144 | self._property_lock = False |
|
131 | self._property_lock = False | |
145 |
|
132 | |||
146 |
|
133 | |||
147 | def _handle_property_changed(self, name, old, new): |
|
134 | def _handle_property_changed(self, name, old, new): | |
148 | """Called when a proeprty has been changed.""" |
|
135 | """Called when a proeprty has been changed.""" | |
149 | if not self._property_lock and self._comm is not None: |
|
136 | if not self._property_lock and self._comm is not None: | |
150 | # TODO: Validate properties. |
|
137 | # TODO: Validate properties. | |
151 | # Send new state to frontend |
|
138 | # Send new state to frontend | |
152 | self.send_state(key=name) |
|
139 | self.send_state(key=name) | |
153 |
|
140 | |||
154 |
|
141 | |||
155 | def _handle_close(self): |
|
142 | def _handle_close(self): | |
156 | """Called when the comm is closed by the frontend.""" |
|
143 | """Called when the comm is closed by the frontend.""" | |
157 | self._comm = None |
|
144 | self._comm = None | |
158 |
|
145 | |||
159 |
|
146 | |||
160 | # Public methods |
|
147 | # Public methods | |
161 | def send_state(self, key=None): |
|
148 | def send_state(self, key=None): | |
162 | """Sends the widget state, or a piece of it, to the frontend. |
|
149 | """Sends the widget state, or a piece of it, to the frontend. | |
163 |
|
150 | |||
164 | Parameters |
|
151 | Parameters | |
165 | ---------- |
|
152 | ---------- | |
166 | key : unicode (optional) |
|
153 | key : unicode (optional) | |
167 | A single property's name to sync with the frontend. |
|
154 | A single property's name to sync with the frontend. | |
168 | """ |
|
155 | """ | |
169 | if self._comm is not None: |
|
156 | if self._comm is not None: | |
170 | state = {} |
|
157 | state = {} | |
171 |
|
158 | |||
172 | # If a key is provided, just send the state of that key. |
|
159 | # If a key is provided, just send the state of that key. | |
173 | keys = [] |
|
160 | keys = [] | |
174 | if key is None: |
|
161 | if key is None: | |
175 | keys.extend(self.keys) |
|
162 | keys.extend(self.keys) | |
176 | else: |
|
163 | else: | |
177 | keys.append(key) |
|
164 | keys.append(key) | |
178 | for key in self.keys: |
|
165 | for key in self.keys: | |
179 | try: |
|
166 | try: | |
180 | state[key] = getattr(self, key) |
|
167 | state[key] = getattr(self, key) | |
181 | except Exception as e: |
|
168 | except Exception as e: | |
182 | pass # Eat errors, nom nom nom |
|
169 | pass # Eat errors, nom nom nom | |
183 | self._comm.send({"method": "update", |
|
170 | self._comm.send({"method": "update", | |
184 | "state": state}) |
|
171 | "state": state}) | |
185 |
|
172 | |||
186 |
|
173 | |||
187 | def get_css(self, key, selector=""): |
|
174 | def get_css(self, key, selector=""): | |
188 | """Get a CSS property of the widget. Note, this function does not |
|
175 | """Get a CSS property of the widget. Note, this function does not | |
189 | actually request the CSS from the front-end; Only properties that have |
|
176 | actually request the CSS from the front-end; Only properties that have | |
190 | been set with set_css can be read. |
|
177 | been set with set_css can be read. | |
191 |
|
178 | |||
192 | Parameters |
|
179 | Parameters | |
193 | ---------- |
|
180 | ---------- | |
194 | key: unicode |
|
181 | key: unicode | |
195 | CSS key |
|
182 | CSS key | |
196 | selector: unicode (optional) |
|
183 | selector: unicode (optional) | |
197 | JQuery selector used when the CSS key/value was set. |
|
184 | JQuery selector used when the CSS key/value was set. | |
198 | """ |
|
185 | """ | |
199 | if selector in self._css and key in self._css[selector]: |
|
186 | if selector in self._css and key in self._css[selector]: | |
200 | return self._css[selector][key] |
|
187 | return self._css[selector][key] | |
201 | else: |
|
188 | else: | |
202 | return None |
|
189 | return None | |
203 |
|
190 | |||
204 |
|
191 | |||
205 | def set_css(self, *args, **kwargs): |
|
192 | def set_css(self, *args, **kwargs): | |
206 | """Set one or more CSS properties of the widget (shared among all of the |
|
193 | """Set one or more CSS properties of the widget (shared among all of the | |
207 | views). This function has two signatures: |
|
194 | views). This function has two signatures: | |
208 | - set_css(css_dict, [selector='']) |
|
195 | - set_css(css_dict, [selector='']) | |
209 | - set_css(key, value, [selector='']) |
|
196 | - set_css(key, value, [selector='']) | |
210 |
|
197 | |||
211 | Parameters |
|
198 | Parameters | |
212 | ---------- |
|
199 | ---------- | |
213 | css_dict : dict |
|
200 | css_dict : dict | |
214 | CSS key/value pairs to apply |
|
201 | CSS key/value pairs to apply | |
215 | key: unicode |
|
202 | key: unicode | |
216 | CSS key |
|
203 | CSS key | |
217 | value |
|
204 | value | |
218 | CSS value |
|
205 | CSS value | |
219 | selector: unicode (optional) |
|
206 | selector: unicode (optional) | |
220 | JQuery selector to use to apply the CSS key/value. |
|
207 | JQuery selector to use to apply the CSS key/value. | |
221 | """ |
|
208 | """ | |
222 | selector = kwargs.get('selector', '') |
|
209 | selector = kwargs.get('selector', '') | |
223 |
|
210 | |||
224 | # Signature 1: set_css(css_dict, [selector='']) |
|
211 | # Signature 1: set_css(css_dict, [selector='']) | |
225 | if len(args) == 1: |
|
212 | if len(args) == 1: | |
226 | if isinstance(args[0], dict): |
|
213 | if isinstance(args[0], dict): | |
227 | for (key, value) in args[0].items(): |
|
214 | for (key, value) in args[0].items(): | |
228 | self.set_css(key, value, selector=selector) |
|
215 | self.set_css(key, value, selector=selector) | |
229 | else: |
|
216 | else: | |
230 | raise Exception('css_dict must be a dict.') |
|
217 | raise Exception('css_dict must be a dict.') | |
231 |
|
218 | |||
232 | # Signature 2: set_css(key, value, [selector='']) |
|
219 | # Signature 2: set_css(key, value, [selector='']) | |
233 | elif len(args) == 2 or len(args) == 3: |
|
220 | elif len(args) == 2 or len(args) == 3: | |
234 |
|
221 | |||
235 | # Selector can be a positional arg if it's the 3rd value |
|
222 | # Selector can be a positional arg if it's the 3rd value | |
236 | if len(args) == 3: |
|
223 | if len(args) == 3: | |
237 | selector = args[2] |
|
224 | selector = args[2] | |
238 | if selector not in self._css: |
|
225 | if selector not in self._css: | |
239 | self._css[selector] = {} |
|
226 | self._css[selector] = {} | |
240 |
|
227 | |||
241 | # Only update the property if it has changed. |
|
228 | # Only update the property if it has changed. | |
242 | key = args[0] |
|
229 | key = args[0] | |
243 | value = args[1] |
|
230 | value = args[1] | |
244 | if not (key in self._css[selector] and value in self._css[selector][key]): |
|
231 | if not (key in self._css[selector] and value in self._css[selector][key]): | |
245 | self._css[selector][key] = value |
|
232 | self._css[selector][key] = value | |
246 | self.send_state('_css') # Send new state to client. |
|
233 | self.send_state('_css') # Send new state to client. | |
247 | else: |
|
234 | else: | |
248 | raise Exception('set_css only accepts 1-3 arguments') |
|
235 | raise Exception('set_css only accepts 1-3 arguments') | |
249 |
|
236 | |||
250 |
|
237 | |||
251 | def add_class(self, class_name, selector=""): |
|
238 | def add_class(self, class_name, selector=""): | |
252 | """Add class[es] to a DOM element |
|
239 | """Add class[es] to a DOM element | |
253 |
|
240 | |||
254 | Parameters |
|
241 | Parameters | |
255 | ---------- |
|
242 | ---------- | |
256 | class_name: unicode |
|
243 | class_name: unicode | |
257 | Class name(s) to add to the DOM element(s). Multiple class names |
|
244 | Class name(s) to add to the DOM element(s). Multiple class names | |
258 | must be space separated. |
|
245 | must be space separated. | |
259 | selector: unicode (optional) |
|
246 | selector: unicode (optional) | |
260 | JQuery selector to select the DOM element(s) that the class(es) will |
|
247 | JQuery selector to select the DOM element(s) that the class(es) will | |
261 | be added to. |
|
248 | be added to. | |
262 | """ |
|
249 | """ | |
263 | self._add_class = [self._add_class[0] + 1, selector, class_name] |
|
250 | self._add_class = [self._add_class[0] + 1, selector, class_name] | |
264 | self.send_state(key='_add_class') |
|
251 | self.send_state(key='_add_class') | |
265 |
|
252 | |||
266 |
|
253 | |||
267 | def remove_class(self, class_name, selector=""): |
|
254 | def remove_class(self, class_name, selector=""): | |
268 | """Remove class[es] from a DOM element |
|
255 | """Remove class[es] from a DOM element | |
269 |
|
256 | |||
270 | Parameters |
|
257 | Parameters | |
271 | ---------- |
|
258 | ---------- | |
272 | class_name: unicode |
|
259 | class_name: unicode | |
273 | Class name(s) to remove from the DOM element(s). Multiple class |
|
260 | Class name(s) to remove from the DOM element(s). Multiple class | |
274 | names must be space separated. |
|
261 | names must be space separated. | |
275 | selector: unicode (optional) |
|
262 | selector: unicode (optional) | |
276 | JQuery selector to select the DOM element(s) that the class(es) will |
|
263 | JQuery selector to select the DOM element(s) that the class(es) will | |
277 | be removed from. |
|
264 | be removed from. | |
278 | """ |
|
265 | """ | |
279 | self._remove_class = [self._remove_class[0] + 1, selector, class_name] |
|
266 | self._remove_class = [self._remove_class[0] + 1, selector, class_name] | |
280 | self.send_state(key='_remove_class') |
|
267 | self.send_state(key='_remove_class') | |
281 |
|
268 | |||
282 |
|
269 | |||
283 | def on_displayed(self, callback, remove=False): |
|
270 | def on_displayed(self, callback, remove=False): | |
284 | """Register a callback to be called when the widget has been displayed |
|
271 | """Register a callback to be called when the widget has been displayed | |
285 |
|
272 | |||
286 | Parameters |
|
273 | Parameters | |
287 | ---------- |
|
274 | ---------- | |
288 | callback: method handler |
|
275 | callback: method handler | |
289 | Can have a signature of: |
|
276 | Can have a signature of: | |
290 | - callback() |
|
277 | - callback() | |
291 | - callback(sender) |
|
278 | - callback(sender) | |
292 | - callback(sender, view_name) |
|
279 | - callback(sender, view_name) | |
293 | remove: bool |
|
280 | remove: bool | |
294 | True if the callback should be unregistered.""" |
|
281 | True if the callback should be unregistered.""" | |
295 | if remove: |
|
282 | if remove: | |
296 | self._display_callbacks.remove(callback) |
|
283 | self._display_callbacks.remove(callback) | |
297 | elif not callback in self._display_callbacks: |
|
284 | elif not callback in self._display_callbacks: | |
298 | self._display_callbacks.append(callback) |
|
285 | self._display_callbacks.append(callback) | |
299 |
|
286 | |||
300 |
|
287 | |||
301 | def handle_displayed(self, view_name): |
|
288 | def handle_displayed(self, view_name): | |
302 | """Called when a view has been displayed for this widget instance |
|
289 | """Called when a view has been displayed for this widget instance | |
303 |
|
290 | |||
304 | Parameters |
|
291 | Parameters | |
305 | ---------- |
|
292 | ---------- | |
306 | view_name: unicode |
|
293 | view_name: unicode | |
307 | Name of the view that was displayed.""" |
|
294 | Name of the view that was displayed.""" | |
308 | for handler in self._display_callbacks: |
|
295 | for handler in self._display_callbacks: | |
309 | if callable(handler): |
|
296 | if callable(handler): | |
310 | argspec = inspect.getargspec(handler) |
|
297 | argspec = inspect.getargspec(handler) | |
311 | nargs = len(argspec[0]) |
|
298 | nargs = len(argspec[0]) | |
312 |
|
299 | |||
313 | # Bound methods have an additional 'self' argument |
|
300 | # Bound methods have an additional 'self' argument | |
314 | if isinstance(handler, types.MethodType): |
|
301 | if isinstance(handler, types.MethodType): | |
315 | nargs -= 1 |
|
302 | nargs -= 1 | |
316 |
|
303 | |||
317 | # Call the callback |
|
304 | # Call the callback | |
318 | if nargs == 0: |
|
305 | if nargs == 0: | |
319 | handler() |
|
306 | handler() | |
320 | elif nargs == 1: |
|
307 | elif nargs == 1: | |
321 | handler(self) |
|
308 | handler(self) | |
322 | elif nargs == 2: |
|
309 | elif nargs == 2: | |
323 | handler(self, view_name) |
|
310 | handler(self, view_name) | |
324 | else: |
|
311 | else: | |
325 | raise TypeError('Widget display callback must ' \ |
|
312 | raise TypeError('Widget display callback must ' \ | |
326 | 'accept 0-2 arguments, not %d.' % nargs) |
|
313 | 'accept 0-2 arguments, not %d.' % nargs) | |
327 |
|
314 | |||
328 |
|
315 | |||
329 | # Support methods |
|
316 | # Support methods | |
330 | def _repr_widget_(self, view_name=None): |
|
317 | def _repr_widget_(self, view_name=None): | |
331 | """Function that is called when `IPython.display.display` is called on |
|
318 | """Function that is called when `IPython.display.display` is called on | |
332 | the widget. |
|
319 | the widget. | |
333 |
|
320 | |||
334 | Parameters |
|
321 | Parameters | |
335 | ---------- |
|
322 | ---------- | |
336 | view_name: unicode (optional) |
|
323 | view_name: unicode (optional) | |
337 | View to display in the frontend. Overrides default_view_name.""" |
|
324 | View to display in the frontend. Overrides default_view_name.""" | |
338 |
|
325 | |||
339 | if not view_name: |
|
326 | if not view_name: | |
340 | view_name = self.default_view_name |
|
327 | view_name = self.default_view_name | |
341 |
|
328 | |||
342 | # Create a comm. |
|
329 | # Create a comm. | |
343 | if self._comm is None: |
|
330 | if self._comm is None: | |
344 | self._comm = Comm(target_name=self.target_name) |
|
331 | self._comm = Comm(target_name=self.target_name) | |
345 | self._comm.on_msg(self._handle_msg) |
|
332 | self._comm.on_msg(self._handle_msg) | |
346 | self._comm.on_close(self._handle_close) |
|
333 | self._comm.on_close(self._handle_close) | |
347 |
|
334 | |||
348 | # Make sure model is syncronized |
|
335 | # Make sure model is syncronized | |
349 | self.send_state() |
|
336 | self.send_state() | |
350 |
|
337 | |||
351 | # Show view. |
|
338 | # Show view. | |
352 | if self.parent is None or self.parent._comm is None: |
|
339 | if self.parent is None or self.parent._comm is None: | |
353 | self._comm.send({"method": "display", "view_name": view_name}) |
|
340 | self._comm.send({"method": "display", "view_name": view_name}) | |
354 | else: |
|
341 | else: | |
355 | self._comm.send({"method": "display", |
|
342 | self._comm.send({"method": "display", | |
356 | "view_name": view_name, |
|
343 | "view_name": view_name, | |
357 | "parent": self.parent._comm.comm_id}) |
|
344 | "parent": self.parent._comm.comm_id}) | |
358 | self._displayed = True |
|
345 | self._displayed = True | |
359 | self.handle_displayed(view_name) |
|
346 | self.handle_displayed(view_name) | |
360 |
|
347 | |||
361 | # Now display children if any. |
|
348 | # Now display children if any. | |
362 | for child in self._children: |
|
349 | for child in self._children: | |
363 | if child != self: |
|
350 | if child != self: | |
364 | child._repr_widget_() |
|
351 | child._repr_widget_() | |
365 | return None |
|
352 | return None |
@@ -1,295 +1,220 b'' | |||||
1 | { |
|
1 | { | |
2 | "metadata": { |
|
2 | "metadata": { | |
3 | "cell_tags": [ |
|
3 | "cell_tags": [ | |
4 | [ |
|
4 | [ | |
5 | "<None>", |
|
5 | "<None>", | |
6 | null |
|
6 | null | |
7 | ] |
|
7 | ] | |
8 | ], |
|
8 | ], | |
9 | "name": "" |
|
9 | "name": "" | |
10 | }, |
|
10 | }, | |
11 | "nbformat": 3, |
|
11 | "nbformat": 3, | |
12 | "nbformat_minor": 0, |
|
12 | "nbformat_minor": 0, | |
13 | "worksheets": [ |
|
13 | "worksheets": [ | |
14 | { |
|
14 | { | |
15 | "cells": [ |
|
15 | "cells": [ | |
16 | { |
|
16 | { | |
17 | "cell_type": "code", |
|
17 | "cell_type": "code", | |
18 | "collapsed": false, |
|
18 | "collapsed": false, | |
19 | "input": [ |
|
19 | "input": [ | |
20 | "from IPython.html import widgets # Widget definitions\n", |
|
20 | "from IPython.html import widgets # Widget definitions\n", | |
21 |
"from IPython.display import display # Used to display widgets in the notebook |
|
21 | "from IPython.display import display # Used to display widgets in the notebook" | |
22 | "\n", |
|
|||
23 | "# Enable widgets in this notebook\n", |
|
|||
24 | "widgets.init_widget_js()" |
|
|||
25 | ], |
|
22 | ], | |
26 | "language": "python", |
|
23 | "language": "python", | |
27 | "metadata": {}, |
|
24 | "metadata": {}, | |
28 | "outputs": [ |
|
25 | "outputs": [], | |
29 | { |
|
|||
30 | "javascript": [ |
|
|||
31 | "$.getScript($(\"body\").data(\"baseProjectUrl\") + \"static/notebook/js/widgets/button.js\");" |
|
|||
32 | ], |
|
|||
33 | "metadata": {}, |
|
|||
34 | "output_type": "display_data" |
|
|||
35 | }, |
|
|||
36 | { |
|
|||
37 | "javascript": [ |
|
|||
38 | "$.getScript($(\"body\").data(\"baseProjectUrl\") + \"static/notebook/js/widgets/int_range.js\");" |
|
|||
39 | ], |
|
|||
40 | "metadata": {}, |
|
|||
41 | "output_type": "display_data" |
|
|||
42 | }, |
|
|||
43 | { |
|
|||
44 | "javascript": [ |
|
|||
45 | "$.getScript($(\"body\").data(\"baseProjectUrl\") + \"static/notebook/js/widgets/string.js\");" |
|
|||
46 | ], |
|
|||
47 | "metadata": {}, |
|
|||
48 | "output_type": "display_data" |
|
|||
49 | }, |
|
|||
50 | { |
|
|||
51 | "javascript": [ |
|
|||
52 | "$.getScript($(\"body\").data(\"baseProjectUrl\") + \"static/notebook/js/widgets/multicontainer.js\");" |
|
|||
53 | ], |
|
|||
54 | "metadata": {}, |
|
|||
55 | "output_type": "display_data" |
|
|||
56 | }, |
|
|||
57 | { |
|
|||
58 | "javascript": [ |
|
|||
59 | "$.getScript($(\"body\").data(\"baseProjectUrl\") + \"static/notebook/js/widgets/bool.js\");" |
|
|||
60 | ], |
|
|||
61 | "metadata": {}, |
|
|||
62 | "output_type": "display_data" |
|
|||
63 | }, |
|
|||
64 | { |
|
|||
65 | "javascript": [ |
|
|||
66 | "$.getScript($(\"body\").data(\"baseProjectUrl\") + \"static/notebook/js/widgets/int.js\");" |
|
|||
67 | ], |
|
|||
68 | "metadata": {}, |
|
|||
69 | "output_type": "display_data" |
|
|||
70 | }, |
|
|||
71 | { |
|
|||
72 | "javascript": [ |
|
|||
73 | "$.getScript($(\"body\").data(\"baseProjectUrl\") + \"static/notebook/js/widgets/selection.js\");" |
|
|||
74 | ], |
|
|||
75 | "metadata": {}, |
|
|||
76 | "output_type": "display_data" |
|
|||
77 | }, |
|
|||
78 | { |
|
|||
79 | "javascript": [ |
|
|||
80 | "$.getScript($(\"body\").data(\"baseProjectUrl\") + \"static/notebook/js/widgets/float.js\");" |
|
|||
81 | ], |
|
|||
82 | "metadata": {}, |
|
|||
83 | "output_type": "display_data" |
|
|||
84 | }, |
|
|||
85 | { |
|
|||
86 | "javascript": [ |
|
|||
87 | "$.getScript($(\"body\").data(\"baseProjectUrl\") + \"static/notebook/js/widgets/float_range.js\");" |
|
|||
88 | ], |
|
|||
89 | "metadata": {}, |
|
|||
90 | "output_type": "display_data" |
|
|||
91 | }, |
|
|||
92 | { |
|
|||
93 | "javascript": [ |
|
|||
94 | "$.getScript($(\"body\").data(\"baseProjectUrl\") + \"static/notebook/js/widgets/container.js\");" |
|
|||
95 | ], |
|
|||
96 | "metadata": {}, |
|
|||
97 | "output_type": "display_data" |
|
|||
98 | } |
|
|||
99 | ], |
|
|||
100 | "prompt_number": 1 |
|
26 | "prompt_number": 1 | |
101 | }, |
|
27 | }, | |
102 | { |
|
28 | { | |
103 | "cell_type": "heading", |
|
29 | "cell_type": "heading", | |
104 | "level": 1, |
|
30 | "level": 1, | |
105 | "metadata": {}, |
|
31 | "metadata": {}, | |
106 | "source": [ |
|
32 | "source": [ | |
107 | "Custom Widget" |
|
33 | "Custom Widget" | |
108 | ] |
|
34 | ] | |
109 | }, |
|
35 | }, | |
110 | { |
|
36 | { | |
111 | "cell_type": "code", |
|
37 | "cell_type": "code", | |
112 | "collapsed": false, |
|
38 | "collapsed": false, | |
113 | "input": [ |
|
39 | "input": [ | |
114 | "# Import the base Widget class and the traitlets Unicode class.\n", |
|
40 | "# Import the base Widget class and the traitlets Unicode class.\n", | |
115 | "from IPython.html.widgets import Widget\n", |
|
41 | "from IPython.html.widgets import Widget\n", | |
116 | "from IPython.utils.traitlets import Unicode, Int\n", |
|
42 | "from IPython.utils.traitlets import Unicode, Int\n", | |
117 | "\n", |
|
43 | "\n", | |
118 | "# Define our FileWidget and its target model and default view.\n", |
|
44 | "# Define our FileWidget and its target model and default view.\n", | |
119 | "class FileWidget(Widget):\n", |
|
45 | "class FileWidget(Widget):\n", | |
120 | " target_name = Unicode('FileWidgetModel')\n", |
|
46 | " target_name = Unicode('FileWidgetModel')\n", | |
121 | " default_view_name = Unicode('FilePickerView')\n", |
|
47 | " default_view_name = Unicode('FilePickerView')\n", | |
122 | " \n", |
|
48 | " \n", | |
123 | " # Define the custom state properties to sync with the front-end\n", |
|
49 | " # Define the custom state properties to sync with the front-end\n", | |
124 | " _keys = ['value', 'filename']\n", |
|
50 | " _keys = ['value', 'filename']\n", | |
125 | " value = Unicode('')\n", |
|
51 | " value = Unicode('')\n", | |
126 | " filename = Unicode('')\n", |
|
52 | " filename = Unicode('')\n", | |
127 | " on_failed = Int(0)" |
|
53 | " on_failed = Int(0)" | |
128 | ], |
|
54 | ], | |
129 | "language": "python", |
|
55 | "language": "python", | |
130 | "metadata": {}, |
|
56 | "metadata": {}, | |
131 | "outputs": [], |
|
57 | "outputs": [], | |
132 | "prompt_number": 2 |
|
58 | "prompt_number": 2 | |
133 | }, |
|
59 | }, | |
134 | { |
|
60 | { | |
135 | "cell_type": "code", |
|
61 | "cell_type": "code", | |
136 | "collapsed": false, |
|
62 | "collapsed": false, | |
137 | "input": [ |
|
63 | "input": [ | |
138 | "%%javascript\n", |
|
64 | "%%javascript\n", | |
139 | "\n", |
|
65 | "\n", | |
140 | "require([\"notebook/js/widget\"], function(){\n", |
|
66 | "require([\"notebook/js/widget\"], function(){\n", | |
141 | " \n", |
|
67 | " \n", | |
142 | " // Define the FileModel and register it with the widget manager.\n", |
|
68 | " // Define the FileModel and register it with the widget manager.\n", | |
143 | " var FileModel = IPython.WidgetModel.extend({});\n", |
|
69 | " var FileModel = IPython.WidgetModel.extend({});\n", | |
144 |
" IPython. |
|
70 | " IPython.widget_manager.register_widget_model('FileWidgetModel', FileModel);\n", | |
145 | " \n", |
|
71 | " \n", | |
146 | " // Define the FilePickerView\n", |
|
72 | " // Define the FilePickerView\n", | |
147 | " var FilePickerView = IPython.WidgetView.extend({\n", |
|
73 | " var FilePickerView = IPython.WidgetView.extend({\n", | |
148 | " \n", |
|
74 | " \n", | |
149 | " render: function(){\n", |
|
75 | " render: function(){\n", | |
150 | " var that = this;\n", |
|
76 | " var that = this;\n", | |
151 | " this.$el = $('<input />')\n", |
|
77 | " this.$el = $('<input />')\n", | |
152 | " .attr('type', 'file')\n", |
|
78 | " .attr('type', 'file')\n", | |
153 | " .change(function(evt){ that.handleFileChange(evt) });\n", |
|
79 | " .change(function(evt){ that.handleFileChange(evt) });\n", | |
154 | " },\n", |
|
80 | " },\n", | |
155 | " \n", |
|
81 | " \n", | |
156 | " // Handles: User input\n", |
|
82 | " // Handles: User input\n", | |
157 | " handleFileChange: function(evt) { \n", |
|
83 | " handleFileChange: function(evt) { \n", | |
158 | " \n", |
|
84 | " \n", | |
159 | " //Retrieve the first (and only!) File from the FileList object\n", |
|
85 | " //Retrieve the first (and only!) File from the FileList object\n", | |
160 | " var that = this;\n", |
|
86 | " var that = this;\n", | |
161 | " var f = evt.target.files[0];\n", |
|
87 | " var f = evt.target.files[0];\n", | |
162 | " if (f) {\n", |
|
88 | " if (f) {\n", | |
163 | " var r = new FileReader();\n", |
|
89 | " var r = new FileReader();\n", | |
164 | " r.onload = function(e) {\n", |
|
90 | " r.onload = function(e) {\n", | |
165 | " that.model.set('value', e.target.result);\n", |
|
91 | " that.model.set('value', e.target.result);\n", | |
166 | " that.model.update_other_views(that);\n", |
|
92 | " that.model.update_other_views(that);\n", | |
167 | " }\n", |
|
93 | " }\n", | |
168 | " r.readAsText(f);\n", |
|
94 | " r.readAsText(f);\n", | |
169 | " } else {\n", |
|
95 | " } else {\n", | |
170 | " this.model.set('on_failed', this.model.get('on_failed') + 1);\n", |
|
96 | " this.model.set('on_failed', this.model.get('on_failed') + 1);\n", | |
171 | " this.model.update_other_views(this);\n", |
|
97 | " this.model.update_other_views(this);\n", | |
172 | " }\n", |
|
98 | " }\n", | |
173 | " this.model.set('filename', f.name);\n", |
|
99 | " this.model.set('filename', f.name);\n", | |
174 | " this.model.update_other_views(this);\n", |
|
100 | " this.model.update_other_views(this);\n", | |
175 | " },\n", |
|
101 | " },\n", | |
176 | " });\n", |
|
102 | " });\n", | |
177 | " \n", |
|
103 | " \n", | |
178 | " // Register the DatePickerView with the widget manager.\n", |
|
104 | " // Register the DatePickerView with the widget manager.\n", | |
179 |
" IPython. |
|
105 | " IPython.widget_manager.register_widget_view('FilePickerView', FilePickerView);\n", | |
180 | "});" |
|
106 | "});" | |
181 | ], |
|
107 | ], | |
182 | "language": "python", |
|
108 | "language": "python", | |
183 | "metadata": {}, |
|
109 | "metadata": {}, | |
184 | "outputs": [ |
|
110 | "outputs": [ | |
185 | { |
|
111 | { | |
186 | "javascript": [ |
|
112 | "javascript": [ | |
187 | "\n", |
|
113 | "\n", | |
188 | "require([\"notebook/js/widget\"], function(){\n", |
|
114 | "require([\"notebook/js/widget\"], function(){\n", | |
189 | " \n", |
|
115 | " \n", | |
190 | " // Define the FileModel and register it with the widget manager.\n", |
|
116 | " // Define the FileModel and register it with the widget manager.\n", | |
191 | " var FileModel = IPython.WidgetModel.extend({});\n", |
|
117 | " var FileModel = IPython.WidgetModel.extend({});\n", | |
192 |
" IPython. |
|
118 | " IPython.widget_manager.register_widget_model('FileWidgetModel', FileModel);\n", | |
193 | " \n", |
|
119 | " \n", | |
194 | " // Define the FilePickerView\n", |
|
120 | " // Define the FilePickerView\n", | |
195 | " var FilePickerView = IPython.WidgetView.extend({\n", |
|
121 | " var FilePickerView = IPython.WidgetView.extend({\n", | |
196 | " \n", |
|
122 | " \n", | |
197 | " render: function(){\n", |
|
123 | " render: function(){\n", | |
198 | " var that = this;\n", |
|
124 | " var that = this;\n", | |
199 | " this.$el = $('<input />')\n", |
|
125 | " this.$el = $('<input />')\n", | |
200 | " .attr('type', 'file')\n", |
|
126 | " .attr('type', 'file')\n", | |
201 | " .change(function(evt){ that.handleFileChange(evt) });\n", |
|
127 | " .change(function(evt){ that.handleFileChange(evt) });\n", | |
202 | " },\n", |
|
128 | " },\n", | |
203 | " \n", |
|
129 | " \n", | |
204 | " // Handles: User input\n", |
|
130 | " // Handles: User input\n", | |
205 | " events: { \"change\" : \"handleFileChange\" }, \n", |
|
|||
206 | " handleFileChange: function(evt) { \n", |
|
131 | " handleFileChange: function(evt) { \n", | |
207 | " \n", |
|
132 | " \n", | |
208 | " //Retrieve the first (and only!) File from the FileList object\n", |
|
133 | " //Retrieve the first (and only!) File from the FileList object\n", | |
209 | " var that = this;\n", |
|
134 | " var that = this;\n", | |
210 | " var f = evt.target.files[0];\n", |
|
135 | " var f = evt.target.files[0];\n", | |
211 | " if (f) {\n", |
|
136 | " if (f) {\n", | |
212 | " var r = new FileReader();\n", |
|
137 | " var r = new FileReader();\n", | |
213 | " r.onload = function(e) {\n", |
|
138 | " r.onload = function(e) {\n", | |
214 | " that.model.set('value', e.target.result);\n", |
|
139 | " that.model.set('value', e.target.result);\n", | |
215 | " that.model.update_other_views(that);\n", |
|
140 | " that.model.update_other_views(that);\n", | |
216 | " }\n", |
|
141 | " }\n", | |
217 | " r.readAsText(f);\n", |
|
142 | " r.readAsText(f);\n", | |
218 | " } else {\n", |
|
143 | " } else {\n", | |
219 | " this.model.set('on_failed', this.model.get('on_failed') + 1);\n", |
|
144 | " this.model.set('on_failed', this.model.get('on_failed') + 1);\n", | |
220 | " this.model.update_other_views(this);\n", |
|
145 | " this.model.update_other_views(this);\n", | |
221 | " }\n", |
|
146 | " }\n", | |
222 | " this.model.set('filename', f.name);\n", |
|
147 | " this.model.set('filename', f.name);\n", | |
223 | " this.model.update_other_views(this);\n", |
|
148 | " this.model.update_other_views(this);\n", | |
224 | " },\n", |
|
149 | " },\n", | |
225 | " });\n", |
|
150 | " });\n", | |
226 | " \n", |
|
151 | " \n", | |
227 | " // Register the DatePickerView with the widget manager.\n", |
|
152 | " // Register the DatePickerView with the widget manager.\n", | |
228 |
" IPython. |
|
153 | " IPython.widget_manager.register_widget_view('FilePickerView', FilePickerView);\n", | |
229 | "});" |
|
154 | "});" | |
230 | ], |
|
155 | ], | |
231 | "metadata": {}, |
|
156 | "metadata": {}, | |
232 | "output_type": "display_data", |
|
157 | "output_type": "display_data", | |
233 | "text": [ |
|
158 | "text": [ | |
234 |
"<IPython.core.display.Javascript at 0x |
|
159 | "<IPython.core.display.Javascript at 0x319fe90>" | |
235 | ] |
|
160 | ] | |
236 | } |
|
161 | } | |
237 | ], |
|
162 | ], | |
238 | "prompt_number": 3 |
|
163 | "prompt_number": 3 | |
239 | }, |
|
164 | }, | |
240 | { |
|
165 | { | |
241 | "cell_type": "heading", |
|
166 | "cell_type": "heading", | |
242 | "level": 1, |
|
167 | "level": 1, | |
243 | "metadata": {}, |
|
168 | "metadata": {}, | |
244 | "source": [ |
|
169 | "source": [ | |
245 | "Usage" |
|
170 | "Usage" | |
246 | ] |
|
171 | ] | |
247 | }, |
|
172 | }, | |
248 | { |
|
173 | { | |
249 | "cell_type": "code", |
|
174 | "cell_type": "code", | |
250 | "collapsed": false, |
|
175 | "collapsed": false, | |
251 | "input": [ |
|
176 | "input": [ | |
252 | "file_widget = FileWidget()\n", |
|
177 | "file_widget = FileWidget()\n", | |
253 | "display(file_widget)\n", |
|
178 | "display(file_widget)\n", | |
254 | "\n", |
|
179 | "\n", | |
255 | "def file_loading():\n", |
|
180 | "def file_loading():\n", | |
256 | " print \"Loading %s\" % file_widget.filename\n", |
|
181 | " print \"Loading %s\" % file_widget.filename\n", | |
257 | "\n", |
|
182 | "\n", | |
258 | "def file_loaded():\n", |
|
183 | "def file_loaded():\n", | |
259 | " print \"Loaded, file contents: %s\" % file_widget.value\n", |
|
184 | " print \"Loaded, file contents: %s\" % file_widget.value\n", | |
260 | "\n", |
|
185 | "\n", | |
261 | "def file_failed(name, old_value, new_value):\n", |
|
186 | "def file_failed(name, old_value, new_value):\n", | |
262 | " if new_value > old_value:\n", |
|
187 | " if new_value > old_value:\n", | |
263 | " print \"Could not load file contents of %s\" % file_widget.filename\n", |
|
188 | " print \"Could not load file contents of %s\" % file_widget.filename\n", | |
264 | "\n", |
|
189 | "\n", | |
265 | "\n", |
|
190 | "\n", | |
266 | "file_widget.on_trait_change(file_loading, 'filename')\n", |
|
191 | "file_widget.on_trait_change(file_loading, 'filename')\n", | |
267 | "file_widget.on_trait_change(file_loaded, 'value')\n", |
|
192 | "file_widget.on_trait_change(file_loaded, 'value')\n", | |
268 | "file_widget.on_trait_change(file_failed, 'on_failed')" |
|
193 | "file_widget.on_trait_change(file_failed, 'on_failed')" | |
269 | ], |
|
194 | ], | |
270 | "language": "python", |
|
195 | "language": "python", | |
271 | "metadata": {}, |
|
196 | "metadata": {}, | |
272 | "outputs": [ |
|
197 | "outputs": [ | |
273 | { |
|
198 | { | |
274 | "output_type": "stream", |
|
199 | "output_type": "stream", | |
275 | "stream": "stdout", |
|
200 | "stream": "stdout", | |
276 | "text": [ |
|
201 | "text": [ | |
277 | "Loading test.txt\n" |
|
202 | "Loading test.txt\n" | |
278 | ] |
|
203 | ] | |
279 | }, |
|
204 | }, | |
280 | { |
|
205 | { | |
281 | "output_type": "stream", |
|
206 | "output_type": "stream", | |
282 | "stream": "stdout", |
|
207 | "stream": "stdout", | |
283 | "text": [ |
|
208 | "text": [ | |
284 | "Loaded, file contents: \n", |
|
209 | "Loaded, file contents: \n", | |
285 | "hello world!\n" |
|
210 | "hello world!\n" | |
286 | ] |
|
211 | ] | |
287 | } |
|
212 | } | |
288 | ], |
|
213 | ], | |
289 | "prompt_number": 4 |
|
214 | "prompt_number": 4 | |
290 | } |
|
215 | } | |
291 | ], |
|
216 | ], | |
292 | "metadata": {} |
|
217 | "metadata": {} | |
293 | } |
|
218 | } | |
294 | ] |
|
219 | ] | |
295 | } No newline at end of file |
|
220 | } |
@@ -1,391 +1,323 b'' | |||||
1 | { |
|
1 | { | |
2 | "metadata": { |
|
2 | "metadata": { | |
|
3 | "cell_tags": [ | |||
|
4 | [ | |||
|
5 | "<None>", | |||
|
6 | null | |||
|
7 | ] | |||
|
8 | ], | |||
3 | "name": "" |
|
9 | "name": "" | |
4 | }, |
|
10 | }, | |
5 | "nbformat": 3, |
|
11 | "nbformat": 3, | |
6 | "nbformat_minor": 0, |
|
12 | "nbformat_minor": 0, | |
7 | "worksheets": [ |
|
13 | "worksheets": [ | |
8 | { |
|
14 | { | |
9 | "cells": [ |
|
15 | "cells": [ | |
10 | { |
|
16 | { | |
11 | "cell_type": "markdown", |
|
17 | "cell_type": "markdown", | |
12 | "metadata": {}, |
|
18 | "metadata": {}, | |
13 | "source": [ |
|
19 | "source": [ | |
14 | "To enable the use IPython widgets in the notebook, the widget namespace and display function need to be imported. The Javascript dependencies need to be loaded via `IPython.html.widgets.init_widget_js()`. This method needs to be called each time the notebook webpage is refreshed." |
|
20 | "To use IPython widgets in the notebook, the widget namespace and display function need to be imported." | |
15 | ] |
|
21 | ] | |
16 | }, |
|
22 | }, | |
17 | { |
|
23 | { | |
18 | "cell_type": "code", |
|
24 | "cell_type": "code", | |
19 | "collapsed": false, |
|
25 | "collapsed": false, | |
20 | "input": [ |
|
26 | "input": [ | |
21 | "from IPython.html import widgets # Widget definitions\n", |
|
27 | "from IPython.html import widgets # Widget definitions\n", | |
22 |
"from IPython.display import display # Used to display widgets in the notebook |
|
28 | "from IPython.display import display # Used to display widgets in the notebook" | |
23 | "\n", |
|
|||
24 | "# Enable widgets in this notebook\n", |
|
|||
25 | "widgets.init_widget_js()" |
|
|||
26 | ], |
|
29 | ], | |
27 | "language": "python", |
|
30 | "language": "python", | |
28 | "metadata": {}, |
|
31 | "metadata": {}, | |
29 | "outputs": [ |
|
32 | "outputs": [], | |
30 | { |
|
|||
31 | "javascript": [ |
|
|||
32 | "$.getScript(\"/static/notebook/js/widgets/bool.js\");" |
|
|||
33 | ], |
|
|||
34 | "metadata": {}, |
|
|||
35 | "output_type": "display_data" |
|
|||
36 | }, |
|
|||
37 | { |
|
|||
38 | "javascript": [ |
|
|||
39 | "$.getScript(\"/static/notebook/js/widgets/int_range.js\");" |
|
|||
40 | ], |
|
|||
41 | "metadata": {}, |
|
|||
42 | "output_type": "display_data" |
|
|||
43 | }, |
|
|||
44 | { |
|
|||
45 | "javascript": [ |
|
|||
46 | "$.getScript(\"/static/notebook/js/widgets/int.js\");" |
|
|||
47 | ], |
|
|||
48 | "metadata": {}, |
|
|||
49 | "output_type": "display_data" |
|
|||
50 | }, |
|
|||
51 | { |
|
|||
52 | "javascript": [ |
|
|||
53 | "$.getScript(\"/static/notebook/js/widgets/selection.js\");" |
|
|||
54 | ], |
|
|||
55 | "metadata": {}, |
|
|||
56 | "output_type": "display_data" |
|
|||
57 | }, |
|
|||
58 | { |
|
|||
59 | "javascript": [ |
|
|||
60 | "$.getScript(\"/static/notebook/js/widgets/string.js\");" |
|
|||
61 | ], |
|
|||
62 | "metadata": {}, |
|
|||
63 | "output_type": "display_data" |
|
|||
64 | }, |
|
|||
65 | { |
|
|||
66 | "javascript": [ |
|
|||
67 | "$.getScript(\"/static/notebook/js/widgets/float.js\");" |
|
|||
68 | ], |
|
|||
69 | "metadata": {}, |
|
|||
70 | "output_type": "display_data" |
|
|||
71 | }, |
|
|||
72 | { |
|
|||
73 | "javascript": [ |
|
|||
74 | "$.getScript(\"/static/notebook/js/widgets/container.js\");" |
|
|||
75 | ], |
|
|||
76 | "metadata": {}, |
|
|||
77 | "output_type": "display_data" |
|
|||
78 | }, |
|
|||
79 | { |
|
|||
80 | "javascript": [ |
|
|||
81 | "$.getScript(\"/static/notebook/js/widgets/multicontainer.js\");" |
|
|||
82 | ], |
|
|||
83 | "metadata": {}, |
|
|||
84 | "output_type": "display_data" |
|
|||
85 | }, |
|
|||
86 | { |
|
|||
87 | "javascript": [ |
|
|||
88 | "$.getScript(\"/static/notebook/js/widgets/button.js\");" |
|
|||
89 | ], |
|
|||
90 | "metadata": {}, |
|
|||
91 | "output_type": "display_data" |
|
|||
92 | }, |
|
|||
93 | { |
|
|||
94 | "javascript": [ |
|
|||
95 | "$.getScript(\"/static/notebook/js/widgets/float_range.js\");" |
|
|||
96 | ], |
|
|||
97 | "metadata": {}, |
|
|||
98 | "output_type": "display_data" |
|
|||
99 | } |
|
|||
100 | ], |
|
|||
101 | "prompt_number": 1 |
|
33 | "prompt_number": 1 | |
102 | }, |
|
34 | }, | |
103 | { |
|
35 | { | |
104 | "cell_type": "heading", |
|
36 | "cell_type": "heading", | |
105 | "level": 1, |
|
37 | "level": 1, | |
106 | "metadata": {}, |
|
38 | "metadata": {}, | |
107 | "source": [ |
|
39 | "source": [ | |
108 | "Basic Widgets" |
|
40 | "Basic Widgets" | |
109 | ] |
|
41 | ] | |
110 | }, |
|
42 | }, | |
111 | { |
|
43 | { | |
112 | "cell_type": "markdown", |
|
44 | "cell_type": "markdown", | |
113 | "metadata": {}, |
|
45 | "metadata": {}, | |
114 | "source": [ |
|
46 | "source": [ | |
115 | "The IPython notebook comes preloaded with basic widgets that represent common data types. These widgets are\n", |
|
47 | "The IPython notebook comes preloaded with basic widgets that represent common data types. These widgets are\n", | |
116 | "\n", |
|
48 | "\n", | |
117 | "- BoolWidget : boolean \n", |
|
49 | "- BoolWidget : boolean \n", | |
118 | "- FloatRangeWidget : bounded float \n", |
|
50 | "- FloatRangeWidget : bounded float \n", | |
119 | "- FloatWidget : unbounded float \n", |
|
51 | "- FloatWidget : unbounded float \n", | |
120 | "- IntRangeWidget : bounded integer \n", |
|
52 | "- IntRangeWidget : bounded integer \n", | |
121 | "- IntWidget : unbounded integer \n", |
|
53 | "- IntWidget : unbounded integer \n", | |
122 | "- SelectionWidget : enumeration \n", |
|
54 | "- SelectionWidget : enumeration \n", | |
123 | "- StringWidget : string \n", |
|
55 | "- StringWidget : string \n", | |
124 | "\n", |
|
56 | "\n", | |
125 | "A few special widgets are also included, that can be used to capture events and change how other widgets are displayed. These widgets are\n", |
|
57 | "A few special widgets are also included, that can be used to capture events and change how other widgets are displayed. These widgets are\n", | |
126 | "\n", |
|
58 | "\n", | |
127 | "- ButtonWidget \n", |
|
59 | "- ButtonWidget \n", | |
128 | "- ContainerWidget \n", |
|
60 | "- ContainerWidget \n", | |
129 | "- MulticontainerWidget \n", |
|
61 | "- MulticontainerWidget \n", | |
130 | "\n", |
|
62 | "\n", | |
131 | "To see the complete list of widgets, one can execute the following" |
|
63 | "To see the complete list of widgets, one can execute the following" | |
132 | ] |
|
64 | ] | |
133 | }, |
|
65 | }, | |
134 | { |
|
66 | { | |
135 | "cell_type": "code", |
|
67 | "cell_type": "code", | |
136 | "collapsed": false, |
|
68 | "collapsed": false, | |
137 | "input": [ |
|
69 | "input": [ | |
138 | "[widget for widget in dir(widgets) if widget.endswith('Widget')]" |
|
70 | "[widget for widget in dir(widgets) if widget.endswith('Widget')]" | |
139 | ], |
|
71 | ], | |
140 | "language": "python", |
|
72 | "language": "python", | |
141 | "metadata": {}, |
|
73 | "metadata": {}, | |
142 | "outputs": [ |
|
74 | "outputs": [ | |
143 | { |
|
75 | { | |
144 | "metadata": {}, |
|
76 | "metadata": {}, | |
145 | "output_type": "pyout", |
|
77 | "output_type": "pyout", | |
146 | "prompt_number": 2, |
|
78 | "prompt_number": 2, | |
147 | "text": [ |
|
79 | "text": [ | |
148 | "['BoolWidget',\n", |
|
80 | "['BoolWidget',\n", | |
149 | " 'ButtonWidget',\n", |
|
81 | " 'ButtonWidget',\n", | |
150 | " 'ContainerWidget',\n", |
|
82 | " 'ContainerWidget',\n", | |
151 | " 'FloatRangeWidget',\n", |
|
83 | " 'FloatRangeWidget',\n", | |
152 | " 'FloatWidget',\n", |
|
84 | " 'FloatWidget',\n", | |
153 | " 'IntRangeWidget',\n", |
|
85 | " 'IntRangeWidget',\n", | |
154 | " 'IntWidget',\n", |
|
86 | " 'IntWidget',\n", | |
155 | " 'MulticontainerWidget',\n", |
|
87 | " 'MulticontainerWidget',\n", | |
156 | " 'SelectionWidget',\n", |
|
88 | " 'SelectionWidget',\n", | |
157 | " 'StringWidget',\n", |
|
89 | " 'StringWidget',\n", | |
158 | " 'Widget']" |
|
90 | " 'Widget']" | |
159 | ] |
|
91 | ] | |
160 | } |
|
92 | } | |
161 | ], |
|
93 | ], | |
162 | "prompt_number": 2 |
|
94 | "prompt_number": 2 | |
163 | }, |
|
95 | }, | |
164 | { |
|
96 | { | |
165 | "cell_type": "markdown", |
|
97 | "cell_type": "markdown", | |
166 | "metadata": {}, |
|
98 | "metadata": {}, | |
167 | "source": [ |
|
99 | "source": [ | |
168 | "The basic widgets can all be constructed without arguments. The following creates a FloatRangeWidget without displaying it" |
|
100 | "The basic widgets can all be constructed without arguments. The following creates a FloatRangeWidget without displaying it" | |
169 | ] |
|
101 | ] | |
170 | }, |
|
102 | }, | |
171 | { |
|
103 | { | |
172 | "cell_type": "code", |
|
104 | "cell_type": "code", | |
173 | "collapsed": false, |
|
105 | "collapsed": false, | |
174 | "input": [ |
|
106 | "input": [ | |
175 | "mywidget = widgets.FloatRangeWidget()" |
|
107 | "mywidget = widgets.FloatRangeWidget()" | |
176 | ], |
|
108 | ], | |
177 | "language": "python", |
|
109 | "language": "python", | |
178 | "metadata": {}, |
|
110 | "metadata": {}, | |
179 | "outputs": [], |
|
111 | "outputs": [], | |
180 | "prompt_number": 3 |
|
112 | "prompt_number": 3 | |
181 | }, |
|
113 | }, | |
182 | { |
|
114 | { | |
183 | "cell_type": "markdown", |
|
115 | "cell_type": "markdown", | |
184 | "metadata": {}, |
|
116 | "metadata": {}, | |
185 | "source": [ |
|
117 | "source": [ | |
186 | "Constructing a widget does not display it on the page. To display a widget, the widget must be passed to the IPython `display(object)` method. `mywidget` is displayed by" |
|
118 | "Constructing a widget does not display it on the page. To display a widget, the widget must be passed to the IPython `display(object)` method. `mywidget` is displayed by" | |
187 | ] |
|
119 | ] | |
188 | }, |
|
120 | }, | |
189 | { |
|
121 | { | |
190 | "cell_type": "code", |
|
122 | "cell_type": "code", | |
191 | "collapsed": false, |
|
123 | "collapsed": false, | |
192 | "input": [ |
|
124 | "input": [ | |
193 | "display(mywidget)" |
|
125 | "display(mywidget)" | |
194 | ], |
|
126 | ], | |
195 | "language": "python", |
|
127 | "language": "python", | |
196 | "metadata": {}, |
|
128 | "metadata": {}, | |
197 | "outputs": [], |
|
129 | "outputs": [], | |
198 | "prompt_number": 4 |
|
130 | "prompt_number": 4 | |
199 | }, |
|
131 | }, | |
200 | { |
|
132 | { | |
201 | "cell_type": "markdown", |
|
133 | "cell_type": "markdown", | |
202 | "metadata": {}, |
|
134 | "metadata": {}, | |
203 | "source": [ |
|
135 | "source": [ | |
204 | "It's important to realize that widgets are not the same as output, even though they are displayed with `display`. Widgets are drawn in a special widget area. That area is marked with a close button which allows you to collapse the widgets. Widgets cannot be interleaved with output. Doing so would break the ability to make simple animations using `clear_output`.\n", |
|
136 | "It's important to realize that widgets are not the same as output, even though they are displayed with `display`. Widgets are drawn in a special widget area. That area is marked with a close button which allows you to collapse the widgets. Widgets cannot be interleaved with output. Doing so would break the ability to make simple animations using `clear_output`.\n", | |
205 | "\n", |
|
137 | "\n", | |
206 | "Widgets are manipulated via special instance properties (traitlets). The names of these instance properties are listed in the widget's `keys` property (as seen below). A few of these properties are common to most, if not all, widgets. The common properties are `value`, `description`, `visible`, and `disabled`. `_css`, `_add_class`, and `_remove_class` are internal properties that exist in all widgets and should not be modified." |
|
138 | "Widgets are manipulated via special instance properties (traitlets). The names of these instance properties are listed in the widget's `keys` property (as seen below). A few of these properties are common to most, if not all, widgets. The common properties are `value`, `description`, `visible`, and `disabled`. `_css`, `_add_class`, and `_remove_class` are internal properties that exist in all widgets and should not be modified." | |
207 | ] |
|
139 | ] | |
208 | }, |
|
140 | }, | |
209 | { |
|
141 | { | |
210 | "cell_type": "code", |
|
142 | "cell_type": "code", | |
211 | "collapsed": false, |
|
143 | "collapsed": false, | |
212 | "input": [ |
|
144 | "input": [ | |
213 | "mywidget.keys" |
|
145 | "mywidget.keys" | |
214 | ], |
|
146 | ], | |
215 | "language": "python", |
|
147 | "language": "python", | |
216 | "metadata": {}, |
|
148 | "metadata": {}, | |
217 | "outputs": [ |
|
149 | "outputs": [ | |
218 | { |
|
150 | { | |
219 | "metadata": {}, |
|
151 | "metadata": {}, | |
220 | "output_type": "pyout", |
|
152 | "output_type": "pyout", | |
221 | "prompt_number": 5, |
|
153 | "prompt_number": 5, | |
222 | "text": [ |
|
154 | "text": [ | |
223 | "['visible',\n", |
|
155 | "['visible',\n", | |
224 | " '_css',\n", |
|
156 | " '_css',\n", | |
225 | " '_add_class',\n", |
|
157 | " '_add_class',\n", | |
226 | " '_remove_class',\n", |
|
158 | " '_remove_class',\n", | |
227 | " 'value',\n", |
|
159 | " 'value',\n", | |
228 | " 'step',\n", |
|
160 | " 'step',\n", | |
229 | " 'max',\n", |
|
161 | " 'max',\n", | |
230 | " 'min',\n", |
|
162 | " 'min',\n", | |
231 | " 'disabled',\n", |
|
163 | " 'disabled',\n", | |
232 | " 'orientation',\n", |
|
164 | " 'orientation',\n", | |
233 | " 'description']" |
|
165 | " 'description']" | |
234 | ] |
|
166 | ] | |
235 | } |
|
167 | } | |
236 | ], |
|
168 | ], | |
237 | "prompt_number": 5 |
|
169 | "prompt_number": 5 | |
238 | }, |
|
170 | }, | |
239 | { |
|
171 | { | |
240 | "cell_type": "markdown", |
|
172 | "cell_type": "markdown", | |
241 | "metadata": {}, |
|
173 | "metadata": {}, | |
242 | "source": [ |
|
174 | "source": [ | |
243 | "Changing a widget's property value will automatically update that widget everywhere it is displayed in the notebook. Here the value of `mywidget` is set. The slider shown above (after input 4) updates automatically to the new value. In reverse, changing the value of the displayed widget will update the property's value." |
|
175 | "Changing a widget's property value will automatically update that widget everywhere it is displayed in the notebook. Here the value of `mywidget` is set. The slider shown above (after input 4) updates automatically to the new value. In reverse, changing the value of the displayed widget will update the property's value." | |
244 | ] |
|
176 | ] | |
245 | }, |
|
177 | }, | |
246 | { |
|
178 | { | |
247 | "cell_type": "code", |
|
179 | "cell_type": "code", | |
248 | "collapsed": false, |
|
180 | "collapsed": false, | |
249 | "input": [ |
|
181 | "input": [ | |
250 | "mywidget.value = 25.0" |
|
182 | "mywidget.value = 25.0" | |
251 | ], |
|
183 | ], | |
252 | "language": "python", |
|
184 | "language": "python", | |
253 | "metadata": {}, |
|
185 | "metadata": {}, | |
254 | "outputs": [], |
|
186 | "outputs": [], | |
255 | "prompt_number": 6 |
|
187 | "prompt_number": 6 | |
256 | }, |
|
188 | }, | |
257 | { |
|
189 | { | |
258 | "cell_type": "markdown", |
|
190 | "cell_type": "markdown", | |
259 | "metadata": {}, |
|
191 | "metadata": {}, | |
260 | "source": [ |
|
192 | "source": [ | |
261 | "After changing the widget's value in the notebook by hand to 0.0 (sliding the bar to the far left)." |
|
193 | "After changing the widget's value in the notebook by hand to 0.0 (sliding the bar to the far left)." | |
262 | ] |
|
194 | ] | |
263 | }, |
|
195 | }, | |
264 | { |
|
196 | { | |
265 | "cell_type": "code", |
|
197 | "cell_type": "code", | |
266 | "collapsed": false, |
|
198 | "collapsed": false, | |
267 | "input": [ |
|
199 | "input": [ | |
268 | "mywidget.value" |
|
200 | "mywidget.value" | |
269 | ], |
|
201 | ], | |
270 | "language": "python", |
|
202 | "language": "python", | |
271 | "metadata": {}, |
|
203 | "metadata": {}, | |
272 | "outputs": [ |
|
204 | "outputs": [ | |
273 | { |
|
205 | { | |
274 | "metadata": {}, |
|
206 | "metadata": {}, | |
275 | "output_type": "pyout", |
|
207 | "output_type": "pyout", | |
276 | "prompt_number": 7, |
|
208 | "prompt_number": 7, | |
277 | "text": [ |
|
209 | "text": [ | |
278 | "0.0" |
|
210 | "0.0" | |
279 | ] |
|
211 | ] | |
280 | } |
|
212 | } | |
281 | ], |
|
213 | ], | |
282 | "prompt_number": 7 |
|
214 | "prompt_number": 7 | |
283 | }, |
|
215 | }, | |
284 | { |
|
216 | { | |
285 | "cell_type": "markdown", |
|
217 | "cell_type": "markdown", | |
286 | "metadata": {}, |
|
218 | "metadata": {}, | |
287 | "source": [ |
|
219 | "source": [ | |
288 | "Widget property values can also be set with kwargs during the construction of the widget (as seen below)." |
|
220 | "Widget property values can also be set with kwargs during the construction of the widget (as seen below)." | |
289 | ] |
|
221 | ] | |
290 | }, |
|
222 | }, | |
291 | { |
|
223 | { | |
292 | "cell_type": "code", |
|
224 | "cell_type": "code", | |
293 | "collapsed": false, |
|
225 | "collapsed": false, | |
294 | "input": [ |
|
226 | "input": [ | |
295 | "mysecondwidget = widgets.SelectionWidget(values=[\"Item A\", \"Item B\", \"Item C\"], value=\"Nothing Selected\")\n", |
|
227 | "mysecondwidget = widgets.SelectionWidget(values=[\"Item A\", \"Item B\", \"Item C\"], value=\"Nothing Selected\")\n", | |
296 | "display(mysecondwidget)" |
|
228 | "display(mysecondwidget)" | |
297 | ], |
|
229 | ], | |
298 | "language": "python", |
|
230 | "language": "python", | |
299 | "metadata": {}, |
|
231 | "metadata": {}, | |
300 | "outputs": [], |
|
232 | "outputs": [], | |
301 | "prompt_number": 8 |
|
233 | "prompt_number": 8 | |
302 | }, |
|
234 | }, | |
303 | { |
|
235 | { | |
304 | "cell_type": "heading", |
|
236 | "cell_type": "heading", | |
305 | "level": 1, |
|
237 | "level": 1, | |
306 | "metadata": {}, |
|
238 | "metadata": {}, | |
307 | "source": [ |
|
239 | "source": [ | |
308 | "Views" |
|
240 | "Views" | |
309 | ] |
|
241 | ] | |
310 | }, |
|
242 | }, | |
311 | { |
|
243 | { | |
312 | "cell_type": "markdown", |
|
244 | "cell_type": "markdown", | |
313 | "metadata": {}, |
|
245 | "metadata": {}, | |
314 | "source": [ |
|
246 | "source": [ | |
315 | "The data types that most of the widgets represent can be displayed more than one way. A `view` is a visual representation of a widget in the notebook. In the example in the section above, the default `view` for the `FloatRangeWidget` is used. The default view is set in the widgets `default_view_name` instance property (as seen below)." |
|
247 | "The data types that most of the widgets represent can be displayed more than one way. A `view` is a visual representation of a widget in the notebook. In the example in the section above, the default `view` for the `FloatRangeWidget` is used. The default view is set in the widgets `default_view_name` instance property (as seen below)." | |
316 | ] |
|
248 | ] | |
317 | }, |
|
249 | }, | |
318 | { |
|
250 | { | |
319 | "cell_type": "code", |
|
251 | "cell_type": "code", | |
320 | "collapsed": false, |
|
252 | "collapsed": false, | |
321 | "input": [ |
|
253 | "input": [ | |
322 | "mywidget.default_view_name" |
|
254 | "mywidget.default_view_name" | |
323 | ], |
|
255 | ], | |
324 | "language": "python", |
|
256 | "language": "python", | |
325 | "metadata": {}, |
|
257 | "metadata": {}, | |
326 | "outputs": [ |
|
258 | "outputs": [ | |
327 | { |
|
259 | { | |
328 | "metadata": {}, |
|
260 | "metadata": {}, | |
329 | "output_type": "pyout", |
|
261 | "output_type": "pyout", | |
330 | "prompt_number": 9, |
|
262 | "prompt_number": 9, | |
331 | "text": [ |
|
263 | "text": [ | |
332 | "u'FloatSliderView'" |
|
264 | "u'FloatSliderView'" | |
333 | ] |
|
265 | ] | |
334 | } |
|
266 | } | |
335 | ], |
|
267 | ], | |
336 | "prompt_number": 9 |
|
268 | "prompt_number": 9 | |
337 | }, |
|
269 | }, | |
338 | { |
|
270 | { | |
339 | "cell_type": "markdown", |
|
271 | "cell_type": "markdown", | |
340 | "metadata": {}, |
|
272 | "metadata": {}, | |
341 | "source": [ |
|
273 | "source": [ | |
342 | "When a widget is displayed using `display(...)`, the `default_view_name` is used to determine what view type should be used to display the widget. View names are case sensitive. Sometimes the default view isn't the best view to represent a piece of data. To change what view is used, either the `default_view_name` can be changed or the `view_name` kwarg of `display` can be set. This also can be used to display one widget multiple ways in one output (as seen below)." |
|
274 | "When a widget is displayed using `display(...)`, the `default_view_name` is used to determine what view type should be used to display the widget. View names are case sensitive. Sometimes the default view isn't the best view to represent a piece of data. To change what view is used, either the `default_view_name` can be changed or the `view_name` kwarg of `display` can be set. This also can be used to display one widget multiple ways in one output (as seen below)." | |
343 | ] |
|
275 | ] | |
344 | }, |
|
276 | }, | |
345 | { |
|
277 | { | |
346 | "cell_type": "code", |
|
278 | "cell_type": "code", | |
347 | "collapsed": false, |
|
279 | "collapsed": false, | |
348 | "input": [ |
|
280 | "input": [ | |
349 | "display(mywidget)\n", |
|
281 | "display(mywidget)\n", | |
350 | "display(mywidget, view_name=\"FloatTextView\")" |
|
282 | "display(mywidget, view_name=\"FloatTextView\")" | |
351 | ], |
|
283 | ], | |
352 | "language": "python", |
|
284 | "language": "python", | |
353 | "metadata": {}, |
|
285 | "metadata": {}, | |
354 | "outputs": [], |
|
286 | "outputs": [], | |
355 | "prompt_number": 10 |
|
287 | "prompt_number": 10 | |
356 | }, |
|
288 | }, | |
357 | { |
|
289 | { | |
358 | "cell_type": "markdown", |
|
290 | "cell_type": "markdown", | |
359 | "metadata": {}, |
|
291 | "metadata": {}, | |
360 | "source": [ |
|
292 | "source": [ | |
361 | "Some views work with multiple different widget types and some views only work with one. The complete list of views and supported widgets is below. The default views are italicized.\n", |
|
293 | "Some views work with multiple different widget types and some views only work with one. The complete list of views and supported widgets is below. The default views are italicized.\n", | |
362 | "\n", |
|
294 | "\n", | |
363 | "| Widget Name | View Names |\n", |
|
295 | "| Widget Name | View Names |\n", | |
364 | "|:-----------------------|:--------------------|\n", |
|
296 | "|:-----------------------|:--------------------|\n", | |
365 | "| BoolWidget | *CheckboxView* |\n", |
|
297 | "| BoolWidget | *CheckboxView* |\n", | |
366 | "| | ToggleButtonView |\n", |
|
298 | "| | ToggleButtonView |\n", | |
367 | "| ButtonWidget | *ButtonView* |\n", |
|
299 | "| ButtonWidget | *ButtonView* |\n", | |
368 | "| ContainerWidget | *ContainerView* |\n", |
|
300 | "| ContainerWidget | *ContainerView* |\n", | |
369 | "| FloatRangeWidget | *FloatSliderView* |\n", |
|
301 | "| FloatRangeWidget | *FloatSliderView* |\n", | |
370 | "| | FloatTextView |\n", |
|
302 | "| | FloatTextView |\n", | |
371 | "| | ProgressView |\n", |
|
303 | "| | ProgressView |\n", | |
372 | "| FloatWidget | *FloatTextView* |\n", |
|
304 | "| FloatWidget | *FloatTextView* |\n", | |
373 | "| IntRangeWidget | *IntSliderView* |\n", |
|
305 | "| IntRangeWidget | *IntSliderView* |\n", | |
374 | "| | IntTextView |\n", |
|
306 | "| | IntTextView |\n", | |
375 | "| | ProgressView |\n", |
|
307 | "| | ProgressView |\n", | |
376 | "| IntWidget | *IntTextView* |\n", |
|
308 | "| IntWidget | *IntTextView* |\n", | |
377 | "| MulticontainerWidget | AccordionView |\n", |
|
309 | "| MulticontainerWidget | AccordionView |\n", | |
378 | "| | *TabView* |\n", |
|
310 | "| | *TabView* |\n", | |
379 | "| SelectionWidget | ToggleButtonsView |\n", |
|
311 | "| SelectionWidget | ToggleButtonsView |\n", | |
380 | "| | RadioButtonsView |\n", |
|
312 | "| | RadioButtonsView |\n", | |
381 | "| | *DropdownView* |\n", |
|
313 | "| | *DropdownView* |\n", | |
382 | "| StringWidget | LabelView |\n", |
|
314 | "| StringWidget | LabelView |\n", | |
383 | "| | TextAreaView |\n", |
|
315 | "| | TextAreaView |\n", | |
384 | "| | *TextBoxView* |\n" |
|
316 | "| | *TextBoxView* |\n" | |
385 | ] |
|
317 | ] | |
386 | } |
|
318 | } | |
387 | ], |
|
319 | ], | |
388 | "metadata": {} |
|
320 | "metadata": {} | |
389 | } |
|
321 | } | |
390 | ] |
|
322 | ] | |
391 | } No newline at end of file |
|
323 | } |
@@ -1,310 +1,242 b'' | |||||
1 | { |
|
1 | { | |
2 | "metadata": { |
|
2 | "metadata": { | |
|
3 | "cell_tags": [ | |||
|
4 | [ | |||
|
5 | "<None>", | |||
|
6 | null | |||
|
7 | ] | |||
|
8 | ], | |||
3 | "name": "" |
|
9 | "name": "" | |
4 | }, |
|
10 | }, | |
5 | "nbformat": 3, |
|
11 | "nbformat": 3, | |
6 | "nbformat_minor": 0, |
|
12 | "nbformat_minor": 0, | |
7 | "worksheets": [ |
|
13 | "worksheets": [ | |
8 | { |
|
14 | { | |
9 | "cells": [ |
|
15 | "cells": [ | |
10 | { |
|
16 | { | |
11 | "cell_type": "code", |
|
17 | "cell_type": "code", | |
12 | "collapsed": false, |
|
18 | "collapsed": false, | |
13 | "input": [ |
|
19 | "input": [ | |
14 | "from IPython.html import widgets # Widget definitions\n", |
|
20 | "from IPython.html import widgets # Widget definitions\n", | |
15 |
"from IPython.display import display # Used to display widgets in the notebook |
|
21 | "from IPython.display import display # Used to display widgets in the notebook" | |
16 | "\n", |
|
|||
17 | "# Enable widgets in this notebook\n", |
|
|||
18 | "widgets.init_widget_js()" |
|
|||
19 | ], |
|
22 | ], | |
20 | "language": "python", |
|
23 | "language": "python", | |
21 | "metadata": {}, |
|
24 | "metadata": {}, | |
22 | "outputs": [ |
|
25 | "outputs": [], | |
23 | { |
|
|||
24 | "javascript": [ |
|
|||
25 | "$.getScript(\"/static/notebook/js/widgets/bool.js\");" |
|
|||
26 | ], |
|
|||
27 | "metadata": {}, |
|
|||
28 | "output_type": "display_data" |
|
|||
29 | }, |
|
|||
30 | { |
|
|||
31 | "javascript": [ |
|
|||
32 | "$.getScript(\"/static/notebook/js/widgets/int_range.js\");" |
|
|||
33 | ], |
|
|||
34 | "metadata": {}, |
|
|||
35 | "output_type": "display_data" |
|
|||
36 | }, |
|
|||
37 | { |
|
|||
38 | "javascript": [ |
|
|||
39 | "$.getScript(\"/static/notebook/js/widgets/int.js\");" |
|
|||
40 | ], |
|
|||
41 | "metadata": {}, |
|
|||
42 | "output_type": "display_data" |
|
|||
43 | }, |
|
|||
44 | { |
|
|||
45 | "javascript": [ |
|
|||
46 | "$.getScript(\"/static/notebook/js/widgets/selection.js\");" |
|
|||
47 | ], |
|
|||
48 | "metadata": {}, |
|
|||
49 | "output_type": "display_data" |
|
|||
50 | }, |
|
|||
51 | { |
|
|||
52 | "javascript": [ |
|
|||
53 | "$.getScript(\"/static/notebook/js/widgets/string.js\");" |
|
|||
54 | ], |
|
|||
55 | "metadata": {}, |
|
|||
56 | "output_type": "display_data" |
|
|||
57 | }, |
|
|||
58 | { |
|
|||
59 | "javascript": [ |
|
|||
60 | "$.getScript(\"/static/notebook/js/widgets/float.js\");" |
|
|||
61 | ], |
|
|||
62 | "metadata": {}, |
|
|||
63 | "output_type": "display_data" |
|
|||
64 | }, |
|
|||
65 | { |
|
|||
66 | "javascript": [ |
|
|||
67 | "$.getScript(\"/static/notebook/js/widgets/container.js\");" |
|
|||
68 | ], |
|
|||
69 | "metadata": {}, |
|
|||
70 | "output_type": "display_data" |
|
|||
71 | }, |
|
|||
72 | { |
|
|||
73 | "javascript": [ |
|
|||
74 | "$.getScript(\"/static/notebook/js/widgets/multicontainer.js\");" |
|
|||
75 | ], |
|
|||
76 | "metadata": {}, |
|
|||
77 | "output_type": "display_data" |
|
|||
78 | }, |
|
|||
79 | { |
|
|||
80 | "javascript": [ |
|
|||
81 | "$.getScript(\"/static/notebook/js/widgets/button.js\");" |
|
|||
82 | ], |
|
|||
83 | "metadata": {}, |
|
|||
84 | "output_type": "display_data" |
|
|||
85 | }, |
|
|||
86 | { |
|
|||
87 | "javascript": [ |
|
|||
88 | "$.getScript(\"/static/notebook/js/widgets/float_range.js\");" |
|
|||
89 | ], |
|
|||
90 | "metadata": {}, |
|
|||
91 | "output_type": "display_data" |
|
|||
92 | } |
|
|||
93 | ], |
|
|||
94 | "prompt_number": 1 |
|
26 | "prompt_number": 1 | |
95 | }, |
|
27 | }, | |
96 | { |
|
28 | { | |
97 | "cell_type": "heading", |
|
29 | "cell_type": "heading", | |
98 | "level": 1, |
|
30 | "level": 1, | |
99 | "metadata": {}, |
|
31 | "metadata": {}, | |
100 | "source": [ |
|
32 | "source": [ | |
101 | "Traitlet Events" |
|
33 | "Traitlet Events" | |
102 | ] |
|
34 | ] | |
103 | }, |
|
35 | }, | |
104 | { |
|
36 | { | |
105 | "cell_type": "markdown", |
|
37 | "cell_type": "markdown", | |
106 | "metadata": {}, |
|
38 | "metadata": {}, | |
107 | "source": [ |
|
39 | "source": [ | |
108 | "The widget properties are IPython traitlets. Traitlets are eventful. To handle property value changes, the `on_trait_change` method of the widget can be used to register an event handling callback. The doc string for `on_trait_change` can be seen below. Both the `name` and `remove` properties are optional." |
|
40 | "The widget properties are IPython traitlets. Traitlets are eventful. To handle property value changes, the `on_trait_change` method of the widget can be used to register an event handling callback. The doc string for `on_trait_change` can be seen below. Both the `name` and `remove` properties are optional." | |
109 | ] |
|
41 | ] | |
110 | }, |
|
42 | }, | |
111 | { |
|
43 | { | |
112 | "cell_type": "code", |
|
44 | "cell_type": "code", | |
113 | "collapsed": false, |
|
45 | "collapsed": false, | |
114 | "input": [ |
|
46 | "input": [ | |
115 | "print(widgets.Widget.on_trait_change.__doc__)" |
|
47 | "print(widgets.Widget.on_trait_change.__doc__)" | |
116 | ], |
|
48 | ], | |
117 | "language": "python", |
|
49 | "language": "python", | |
118 | "metadata": {}, |
|
50 | "metadata": {}, | |
119 | "outputs": [ |
|
51 | "outputs": [ | |
120 | { |
|
52 | { | |
121 | "output_type": "stream", |
|
53 | "output_type": "stream", | |
122 | "stream": "stdout", |
|
54 | "stream": "stdout", | |
123 | "text": [ |
|
55 | "text": [ | |
124 | "Setup a handler to be called when a trait changes.\n", |
|
56 | "Setup a handler to be called when a trait changes.\n", | |
125 | "\n", |
|
57 | "\n", | |
126 | " This is used to setup dynamic notifications of trait changes.\n", |
|
58 | " This is used to setup dynamic notifications of trait changes.\n", | |
127 | "\n", |
|
59 | "\n", | |
128 | " Static handlers can be created by creating methods on a HasTraits\n", |
|
60 | " Static handlers can be created by creating methods on a HasTraits\n", | |
129 | " subclass with the naming convention '_[traitname]_changed'. Thus,\n", |
|
61 | " subclass with the naming convention '_[traitname]_changed'. Thus,\n", | |
130 | " to create static handler for the trait 'a', create the method\n", |
|
62 | " to create static handler for the trait 'a', create the method\n", | |
131 | " _a_changed(self, name, old, new) (fewer arguments can be used, see\n", |
|
63 | " _a_changed(self, name, old, new) (fewer arguments can be used, see\n", | |
132 | " below).\n", |
|
64 | " below).\n", | |
133 | "\n", |
|
65 | "\n", | |
134 | " Parameters\n", |
|
66 | " Parameters\n", | |
135 | " ----------\n", |
|
67 | " ----------\n", | |
136 | " handler : callable\n", |
|
68 | " handler : callable\n", | |
137 | " A callable that is called when a trait changes. Its\n", |
|
69 | " A callable that is called when a trait changes. Its\n", | |
138 | " signature can be handler(), handler(name), handler(name, new)\n", |
|
70 | " signature can be handler(), handler(name), handler(name, new)\n", | |
139 | " or handler(name, old, new).\n", |
|
71 | " or handler(name, old, new).\n", | |
140 | " name : list, str, None\n", |
|
72 | " name : list, str, None\n", | |
141 | " If None, the handler will apply to all traits. If a list\n", |
|
73 | " If None, the handler will apply to all traits. If a list\n", | |
142 | " of str, handler will apply to all names in the list. If a\n", |
|
74 | " of str, handler will apply to all names in the list. If a\n", | |
143 | " str, the handler will apply just to that name.\n", |
|
75 | " str, the handler will apply just to that name.\n", | |
144 | " remove : bool\n", |
|
76 | " remove : bool\n", | |
145 | " If False (the default), then install the handler. If True\n", |
|
77 | " If False (the default), then install the handler. If True\n", | |
146 | " then unintall it.\n", |
|
78 | " then unintall it.\n", | |
147 | " \n" |
|
79 | " \n" | |
148 | ] |
|
80 | ] | |
149 | } |
|
81 | } | |
150 | ], |
|
82 | ], | |
151 | "prompt_number": 2 |
|
83 | "prompt_number": 2 | |
152 | }, |
|
84 | }, | |
153 | { |
|
85 | { | |
154 | "cell_type": "markdown", |
|
86 | "cell_type": "markdown", | |
155 | "metadata": {}, |
|
87 | "metadata": {}, | |
156 | "source": [ |
|
88 | "source": [ | |
157 | "Mentioned in the doc string, the callback registered can have 4 possible signatures:\n", |
|
89 | "Mentioned in the doc string, the callback registered can have 4 possible signatures:\n", | |
158 | "\n", |
|
90 | "\n", | |
159 | "- callback()\n", |
|
91 | "- callback()\n", | |
160 | "- callback(trait_name)\n", |
|
92 | "- callback(trait_name)\n", | |
161 | "- callback(trait_name, new_value)\n", |
|
93 | "- callback(trait_name, new_value)\n", | |
162 | "- callback(trait_name, old_value, new_value)\n", |
|
94 | "- callback(trait_name, old_value, new_value)\n", | |
163 | "\n", |
|
95 | "\n", | |
164 | "An example of how to output an IntRangeWiget's value as it is changed can be seen below." |
|
96 | "An example of how to output an IntRangeWiget's value as it is changed can be seen below." | |
165 | ] |
|
97 | ] | |
166 | }, |
|
98 | }, | |
167 | { |
|
99 | { | |
168 | "cell_type": "code", |
|
100 | "cell_type": "code", | |
169 | "collapsed": false, |
|
101 | "collapsed": false, | |
170 | "input": [ |
|
102 | "input": [ | |
171 | "intrange = widgets.IntRangeWidget()\n", |
|
103 | "intrange = widgets.IntRangeWidget()\n", | |
172 | "display(intrange)\n", |
|
104 | "display(intrange)\n", | |
173 | "\n", |
|
105 | "\n", | |
174 | "def on_value_change(name, value):\n", |
|
106 | "def on_value_change(name, value):\n", | |
175 | " print value\n", |
|
107 | " print value\n", | |
176 | "\n", |
|
108 | "\n", | |
177 | "intrange.on_trait_change(on_value_change, 'value')" |
|
109 | "intrange.on_trait_change(on_value_change, 'value')" | |
178 | ], |
|
110 | ], | |
179 | "language": "python", |
|
111 | "language": "python", | |
180 | "metadata": {}, |
|
112 | "metadata": {}, | |
181 | "outputs": [], |
|
113 | "outputs": [], | |
182 | "prompt_number": 3 |
|
114 | "prompt_number": 3 | |
183 | }, |
|
115 | }, | |
184 | { |
|
116 | { | |
185 | "cell_type": "heading", |
|
117 | "cell_type": "heading", | |
186 | "level": 1, |
|
118 | "level": 1, | |
187 | "metadata": {}, |
|
119 | "metadata": {}, | |
188 | "source": [ |
|
120 | "source": [ | |
189 | "Specialized Events" |
|
121 | "Specialized Events" | |
190 | ] |
|
122 | ] | |
191 | }, |
|
123 | }, | |
192 | { |
|
124 | { | |
193 | "cell_type": "heading", |
|
125 | "cell_type": "heading", | |
194 | "level": 2, |
|
126 | "level": 2, | |
195 | "metadata": {}, |
|
127 | "metadata": {}, | |
196 | "source": [ |
|
128 | "source": [ | |
197 | "Button On Click Event" |
|
129 | "Button On Click Event" | |
198 | ] |
|
130 | ] | |
199 | }, |
|
131 | }, | |
200 | { |
|
132 | { | |
201 | "cell_type": "markdown", |
|
133 | "cell_type": "markdown", | |
202 | "metadata": {}, |
|
134 | "metadata": {}, | |
203 | "source": [ |
|
135 | "source": [ | |
204 | "The `ButtonWidget` is a special widget, like the `ContainerWidget` and `MulticontainerWidget`, that isn't used to represent a data type. Instead the button widget is used to handle mouse clicks. The `on_click` method of the `ButtonWidget` can be used to register a click even handler. The doc string of the `on_click` can be seen below." |
|
136 | "The `ButtonWidget` is a special widget, like the `ContainerWidget` and `MulticontainerWidget`, that isn't used to represent a data type. Instead the button widget is used to handle mouse clicks. The `on_click` method of the `ButtonWidget` can be used to register a click even handler. The doc string of the `on_click` can be seen below." | |
205 | ] |
|
137 | ] | |
206 | }, |
|
138 | }, | |
207 | { |
|
139 | { | |
208 | "cell_type": "code", |
|
140 | "cell_type": "code", | |
209 | "collapsed": false, |
|
141 | "collapsed": false, | |
210 | "input": [ |
|
142 | "input": [ | |
211 | "print(widgets.ButtonWidget.on_click.__doc__)" |
|
143 | "print(widgets.ButtonWidget.on_click.__doc__)" | |
212 | ], |
|
144 | ], | |
213 | "language": "python", |
|
145 | "language": "python", | |
214 | "metadata": {}, |
|
146 | "metadata": {}, | |
215 | "outputs": [ |
|
147 | "outputs": [ | |
216 | { |
|
148 | { | |
217 | "output_type": "stream", |
|
149 | "output_type": "stream", | |
218 | "stream": "stdout", |
|
150 | "stream": "stdout", | |
219 | "text": [ |
|
151 | "text": [ | |
220 | "Register a callback to execute when the button is clicked. The\n", |
|
152 | "Register a callback to execute when the button is clicked. The\n", | |
221 | " callback can either accept no parameters or one sender parameter:\n", |
|
153 | " callback can either accept no parameters or one sender parameter:\n", | |
222 | " - callback()\n", |
|
154 | " - callback()\n", | |
223 | " - callback(sender)\n", |
|
155 | " - callback(sender)\n", | |
224 | " If the callback has a sender parameter, the ButtonWidget instance that\n", |
|
156 | " If the callback has a sender parameter, the ButtonWidget instance that\n", | |
225 | " called the callback will be passed into the method as the sender.\n", |
|
157 | " called the callback will be passed into the method as the sender.\n", | |
226 | "\n", |
|
158 | "\n", | |
227 | " Parameters\n", |
|
159 | " Parameters\n", | |
228 | " ----------\n", |
|
160 | " ----------\n", | |
229 | " remove : bool (optional)\n", |
|
161 | " remove : bool (optional)\n", | |
230 | " Set to true to remove the callback from the list of callbacks.\n" |
|
162 | " Set to true to remove the callback from the list of callbacks.\n" | |
231 | ] |
|
163 | ] | |
232 | } |
|
164 | } | |
233 | ], |
|
165 | ], | |
234 | "prompt_number": 4 |
|
166 | "prompt_number": 4 | |
235 | }, |
|
167 | }, | |
236 | { |
|
168 | { | |
237 | "cell_type": "markdown", |
|
169 | "cell_type": "markdown", | |
238 | "metadata": {}, |
|
170 | "metadata": {}, | |
239 | "source": [ |
|
171 | "source": [ | |
240 | "Button clicks are tracked by the `clicks` property of the button widget. By using the `on_click` method and the `clicks` property, a button that outputs how many times it has been clicked is shown below." |
|
172 | "Button clicks are tracked by the `clicks` property of the button widget. By using the `on_click` method and the `clicks` property, a button that outputs how many times it has been clicked is shown below." | |
241 | ] |
|
173 | ] | |
242 | }, |
|
174 | }, | |
243 | { |
|
175 | { | |
244 | "cell_type": "code", |
|
176 | "cell_type": "code", | |
245 | "collapsed": false, |
|
177 | "collapsed": false, | |
246 | "input": [ |
|
178 | "input": [ | |
247 | "button = widgets.ButtonWidget(description=\"Click Me!\")\n", |
|
179 | "button = widgets.ButtonWidget(description=\"Click Me!\")\n", | |
248 | "display(button)\n", |
|
180 | "display(button)\n", | |
249 | "\n", |
|
181 | "\n", | |
250 | "def on_button_clicked(sender):\n", |
|
182 | "def on_button_clicked(sender):\n", | |
251 | " print(\"Button clicked %d times.\" % sender.clicks)\n", |
|
183 | " print(\"Button clicked %d times.\" % sender.clicks)\n", | |
252 | "\n", |
|
184 | "\n", | |
253 | "button.on_click(on_button_clicked)" |
|
185 | "button.on_click(on_button_clicked)" | |
254 | ], |
|
186 | ], | |
255 | "language": "python", |
|
187 | "language": "python", | |
256 | "metadata": {}, |
|
188 | "metadata": {}, | |
257 | "outputs": [ |
|
189 | "outputs": [ | |
258 | { |
|
190 | { | |
259 | "output_type": "stream", |
|
191 | "output_type": "stream", | |
260 | "stream": "stdout", |
|
192 | "stream": "stdout", | |
261 | "text": [ |
|
193 | "text": [ | |
262 | "Button clicked 1 times.\n" |
|
194 | "Button clicked 1 times.\n" | |
263 | ] |
|
195 | ] | |
264 | }, |
|
196 | }, | |
265 | { |
|
197 | { | |
266 | "output_type": "stream", |
|
198 | "output_type": "stream", | |
267 | "stream": "stdout", |
|
199 | "stream": "stdout", | |
268 | "text": [ |
|
200 | "text": [ | |
269 | "Button clicked 2 times.\n" |
|
201 | "Button clicked 2 times.\n" | |
270 | ] |
|
202 | ] | |
271 | }, |
|
203 | }, | |
272 | { |
|
204 | { | |
273 | "output_type": "stream", |
|
205 | "output_type": "stream", | |
274 | "stream": "stdout", |
|
206 | "stream": "stdout", | |
275 | "text": [ |
|
207 | "text": [ | |
276 | "Button clicked 3 times.\n" |
|
208 | "Button clicked 3 times.\n" | |
277 | ] |
|
209 | ] | |
278 | } |
|
210 | } | |
279 | ], |
|
211 | ], | |
280 | "prompt_number": 5 |
|
212 | "prompt_number": 5 | |
281 | }, |
|
213 | }, | |
282 | { |
|
214 | { | |
283 | "cell_type": "markdown", |
|
215 | "cell_type": "markdown", | |
284 | "metadata": {}, |
|
216 | "metadata": {}, | |
285 | "source": [ |
|
217 | "source": [ | |
286 | "Event handlers can also be used to create widgets. In the example below, clicking a button spawns another button with a description equal to how many times the parent button had been clicked at the time." |
|
218 | "Event handlers can also be used to create widgets. In the example below, clicking a button spawns another button with a description equal to how many times the parent button had been clicked at the time." | |
287 | ] |
|
219 | ] | |
288 | }, |
|
220 | }, | |
289 | { |
|
221 | { | |
290 | "cell_type": "code", |
|
222 | "cell_type": "code", | |
291 | "collapsed": false, |
|
223 | "collapsed": false, | |
292 | "input": [ |
|
224 | "input": [ | |
293 | "def show_button(sender=None):\n", |
|
225 | "def show_button(sender=None):\n", | |
294 | " button = widgets.ButtonWidget()\n", |
|
226 | " button = widgets.ButtonWidget()\n", | |
295 | " button.description = \"%d\" % (sender.clicks if sender is not None else 0)\n", |
|
227 | " button.description = \"%d\" % (sender.clicks if sender is not None else 0)\n", | |
296 | " display(button)\n", |
|
228 | " display(button)\n", | |
297 | " button.on_click(show_button)\n", |
|
229 | " button.on_click(show_button)\n", | |
298 | "show_button()\n", |
|
230 | "show_button()\n", | |
299 | " " |
|
231 | " " | |
300 | ], |
|
232 | ], | |
301 | "language": "python", |
|
233 | "language": "python", | |
302 | "metadata": {}, |
|
234 | "metadata": {}, | |
303 | "outputs": [], |
|
235 | "outputs": [], | |
304 | "prompt_number": 6 |
|
236 | "prompt_number": 6 | |
305 | } |
|
237 | } | |
306 | ], |
|
238 | ], | |
307 | "metadata": {} |
|
239 | "metadata": {} | |
308 | } |
|
240 | } | |
309 | ] |
|
241 | ] | |
310 | } No newline at end of file |
|
242 | } |
@@ -1,326 +1,258 b'' | |||||
1 | { |
|
1 | { | |
2 | "metadata": { |
|
2 | "metadata": { | |
|
3 | "cell_tags": [ | |||
|
4 | [ | |||
|
5 | "<None>", | |||
|
6 | null | |||
|
7 | ] | |||
|
8 | ], | |||
3 | "name": "" |
|
9 | "name": "" | |
4 | }, |
|
10 | }, | |
5 | "nbformat": 3, |
|
11 | "nbformat": 3, | |
6 | "nbformat_minor": 0, |
|
12 | "nbformat_minor": 0, | |
7 | "worksheets": [ |
|
13 | "worksheets": [ | |
8 | { |
|
14 | { | |
9 | "cells": [ |
|
15 | "cells": [ | |
10 | { |
|
16 | { | |
11 | "cell_type": "code", |
|
17 | "cell_type": "code", | |
12 | "collapsed": false, |
|
18 | "collapsed": false, | |
13 | "input": [ |
|
19 | "input": [ | |
14 | "from IPython.html import widgets # Widget definitions\n", |
|
20 | "from IPython.html import widgets # Widget definitions\n", | |
15 |
"from IPython.display import display # Used to display widgets in the notebook |
|
21 | "from IPython.display import display # Used to display widgets in the notebook" | |
16 | "\n", |
|
|||
17 | "# Enable widgets in this notebook\n", |
|
|||
18 | "widgets.init_widget_js()" |
|
|||
19 | ], |
|
22 | ], | |
20 | "language": "python", |
|
23 | "language": "python", | |
21 | "metadata": {}, |
|
24 | "metadata": {}, | |
22 | "outputs": [ |
|
25 | "outputs": [], | |
23 | { |
|
|||
24 | "javascript": [ |
|
|||
25 | "$.getScript(\"/static/notebook/js/widgets/bool.js\");" |
|
|||
26 | ], |
|
|||
27 | "metadata": {}, |
|
|||
28 | "output_type": "display_data" |
|
|||
29 | }, |
|
|||
30 | { |
|
|||
31 | "javascript": [ |
|
|||
32 | "$.getScript(\"/static/notebook/js/widgets/int_range.js\");" |
|
|||
33 | ], |
|
|||
34 | "metadata": {}, |
|
|||
35 | "output_type": "display_data" |
|
|||
36 | }, |
|
|||
37 | { |
|
|||
38 | "javascript": [ |
|
|||
39 | "$.getScript(\"/static/notebook/js/widgets/int.js\");" |
|
|||
40 | ], |
|
|||
41 | "metadata": {}, |
|
|||
42 | "output_type": "display_data" |
|
|||
43 | }, |
|
|||
44 | { |
|
|||
45 | "javascript": [ |
|
|||
46 | "$.getScript(\"/static/notebook/js/widgets/selection.js\");" |
|
|||
47 | ], |
|
|||
48 | "metadata": {}, |
|
|||
49 | "output_type": "display_data" |
|
|||
50 | }, |
|
|||
51 | { |
|
|||
52 | "javascript": [ |
|
|||
53 | "$.getScript(\"/static/notebook/js/widgets/string.js\");" |
|
|||
54 | ], |
|
|||
55 | "metadata": {}, |
|
|||
56 | "output_type": "display_data" |
|
|||
57 | }, |
|
|||
58 | { |
|
|||
59 | "javascript": [ |
|
|||
60 | "$.getScript(\"/static/notebook/js/widgets/float.js\");" |
|
|||
61 | ], |
|
|||
62 | "metadata": {}, |
|
|||
63 | "output_type": "display_data" |
|
|||
64 | }, |
|
|||
65 | { |
|
|||
66 | "javascript": [ |
|
|||
67 | "$.getScript(\"/static/notebook/js/widgets/container.js\");" |
|
|||
68 | ], |
|
|||
69 | "metadata": {}, |
|
|||
70 | "output_type": "display_data" |
|
|||
71 | }, |
|
|||
72 | { |
|
|||
73 | "javascript": [ |
|
|||
74 | "$.getScript(\"/static/notebook/js/widgets/multicontainer.js\");" |
|
|||
75 | ], |
|
|||
76 | "metadata": {}, |
|
|||
77 | "output_type": "display_data" |
|
|||
78 | }, |
|
|||
79 | { |
|
|||
80 | "javascript": [ |
|
|||
81 | "$.getScript(\"/static/notebook/js/widgets/button.js\");" |
|
|||
82 | ], |
|
|||
83 | "metadata": {}, |
|
|||
84 | "output_type": "display_data" |
|
|||
85 | }, |
|
|||
86 | { |
|
|||
87 | "javascript": [ |
|
|||
88 | "$.getScript(\"/static/notebook/js/widgets/float_range.js\");" |
|
|||
89 | ], |
|
|||
90 | "metadata": {}, |
|
|||
91 | "output_type": "display_data" |
|
|||
92 | } |
|
|||
93 | ], |
|
|||
94 | "prompt_number": 1 |
|
26 | "prompt_number": 1 | |
95 | }, |
|
27 | }, | |
96 | { |
|
28 | { | |
97 | "cell_type": "heading", |
|
29 | "cell_type": "heading", | |
98 | "level": 1, |
|
30 | "level": 1, | |
99 | "metadata": {}, |
|
31 | "metadata": {}, | |
100 | "source": [ |
|
32 | "source": [ | |
101 | "Parent/Child Relationships" |
|
33 | "Parent/Child Relationships" | |
102 | ] |
|
34 | ] | |
103 | }, |
|
35 | }, | |
104 | { |
|
36 | { | |
105 | "cell_type": "markdown", |
|
37 | "cell_type": "markdown", | |
106 | "metadata": {}, |
|
38 | "metadata": {}, | |
107 | "source": [ |
|
39 | "source": [ | |
108 | "To display widget A inside widget B, widget A must be a child of widget B. With IPython widgets, the widgets are instances that live in the back-end (usally Python). There can be multiple views displayed in the front-end that represent one widget in the backend. Each view can be displayed at a different time, or even displayed two or more times in the same output. Because of this, the parent of a widget can only be set before the widget has been displayed.\n", |
|
40 | "To display widget A inside widget B, widget A must be a child of widget B. With IPython widgets, the widgets are instances that live in the back-end (usally Python). There can be multiple views displayed in the front-end that represent one widget in the backend. Each view can be displayed at a different time, or even displayed two or more times in the same output. Because of this, the parent of a widget can only be set before the widget has been displayed.\n", | |
109 | "\n", |
|
41 | "\n", | |
110 | "Every widget has a `parent` property. This property can be set via a kwarg in the widget's constructor or after construction, but before display. Calling display on an object with children automatically displays those children too (as seen below)." |
|
42 | "Every widget has a `parent` property. This property can be set via a kwarg in the widget's constructor or after construction, but before display. Calling display on an object with children automatically displays those children too (as seen below)." | |
111 | ] |
|
43 | ] | |
112 | }, |
|
44 | }, | |
113 | { |
|
45 | { | |
114 | "cell_type": "code", |
|
46 | "cell_type": "code", | |
115 | "collapsed": false, |
|
47 | "collapsed": false, | |
116 | "input": [ |
|
48 | "input": [ | |
117 | "container = widgets.MulticontainerWidget()\n", |
|
49 | "container = widgets.MulticontainerWidget()\n", | |
118 | "\n", |
|
50 | "\n", | |
119 | "floatrange = widgets.FloatRangeWidget(parent=container) # You can set the parent in the constructor,\n", |
|
51 | "floatrange = widgets.FloatRangeWidget(parent=container) # You can set the parent in the constructor,\n", | |
120 | "\n", |
|
52 | "\n", | |
121 | "string = widgets.StringWidget()\n", |
|
53 | "string = widgets.StringWidget()\n", | |
122 | "string.parent = container # or after the widget has been created.\n", |
|
54 | "string.parent = container # or after the widget has been created.\n", | |
123 | "\n", |
|
55 | "\n", | |
124 | "display(container) # Displays the `container` and all of it's children." |
|
56 | "display(container) # Displays the `container` and all of it's children." | |
125 | ], |
|
57 | ], | |
126 | "language": "python", |
|
58 | "language": "python", | |
127 | "metadata": {}, |
|
59 | "metadata": {}, | |
128 | "outputs": [], |
|
60 | "outputs": [], | |
129 | "prompt_number": 2 |
|
61 | "prompt_number": 2 | |
130 | }, |
|
62 | }, | |
131 | { |
|
63 | { | |
132 | "cell_type": "markdown", |
|
64 | "cell_type": "markdown", | |
133 | "metadata": {}, |
|
65 | "metadata": {}, | |
134 | "source": [ |
|
66 | "source": [ | |
135 | "Children can also be added to parents after the parent has been displayed. If the children are added after the parent has already been displayed, the children must be displayed themselves.\n", |
|
67 | "Children can also be added to parents after the parent has been displayed. If the children are added after the parent has already been displayed, the children must be displayed themselves.\n", | |
136 | "\n", |
|
68 | "\n", | |
137 | "In the example below, the IntRangeWidget is never rendered since display was called on the parent before the parent/child relationship was established." |
|
69 | "In the example below, the IntRangeWidget is never rendered since display was called on the parent before the parent/child relationship was established." | |
138 | ] |
|
70 | ] | |
139 | }, |
|
71 | }, | |
140 | { |
|
72 | { | |
141 | "cell_type": "code", |
|
73 | "cell_type": "code", | |
142 | "collapsed": false, |
|
74 | "collapsed": false, | |
143 | "input": [ |
|
75 | "input": [ | |
144 | "container = widgets.MulticontainerWidget()\n", |
|
76 | "container = widgets.MulticontainerWidget()\n", | |
145 | "display(container)\n", |
|
77 | "display(container)\n", | |
146 | "\n", |
|
78 | "\n", | |
147 | "intrange = widgets.IntRangeWidget(parent=container) # Never gets displayed." |
|
79 | "intrange = widgets.IntRangeWidget(parent=container) # Never gets displayed." | |
148 | ], |
|
80 | ], | |
149 | "language": "python", |
|
81 | "language": "python", | |
150 | "metadata": {}, |
|
82 | "metadata": {}, | |
151 | "outputs": [], |
|
83 | "outputs": [], | |
152 | "prompt_number": 3 |
|
84 | "prompt_number": 3 | |
153 | }, |
|
85 | }, | |
154 | { |
|
86 | { | |
155 | "cell_type": "markdown", |
|
87 | "cell_type": "markdown", | |
156 | "metadata": {}, |
|
88 | "metadata": {}, | |
157 | "source": [ |
|
89 | "source": [ | |
158 | "Calling display on the child fixes the problem." |
|
90 | "Calling display on the child fixes the problem." | |
159 | ] |
|
91 | ] | |
160 | }, |
|
92 | }, | |
161 | { |
|
93 | { | |
162 | "cell_type": "code", |
|
94 | "cell_type": "code", | |
163 | "collapsed": false, |
|
95 | "collapsed": false, | |
164 | "input": [ |
|
96 | "input": [ | |
165 | "container = widgets.MulticontainerWidget()\n", |
|
97 | "container = widgets.MulticontainerWidget()\n", | |
166 | "display(container)\n", |
|
98 | "display(container)\n", | |
167 | "\n", |
|
99 | "\n", | |
168 | "intrange = widgets.IntRangeWidget(parent=container)\n", |
|
100 | "intrange = widgets.IntRangeWidget(parent=container)\n", | |
169 | "display(intrange) # This line is needed since the `container` has already been displayed." |
|
101 | "display(intrange) # This line is needed since the `container` has already been displayed." | |
170 | ], |
|
102 | ], | |
171 | "language": "python", |
|
103 | "language": "python", | |
172 | "metadata": {}, |
|
104 | "metadata": {}, | |
173 | "outputs": [], |
|
105 | "outputs": [], | |
174 | "prompt_number": 4 |
|
106 | "prompt_number": 4 | |
175 | }, |
|
107 | }, | |
176 | { |
|
108 | { | |
177 | "cell_type": "heading", |
|
109 | "cell_type": "heading", | |
178 | "level": 1, |
|
110 | "level": 1, | |
179 | "metadata": {}, |
|
111 | "metadata": {}, | |
180 | "source": [ |
|
112 | "source": [ | |
181 | "Changing Child Views" |
|
113 | "Changing Child Views" | |
182 | ] |
|
114 | ] | |
183 | }, |
|
115 | }, | |
184 | { |
|
116 | { | |
185 | "cell_type": "markdown", |
|
117 | "cell_type": "markdown", | |
186 | "metadata": {}, |
|
118 | "metadata": {}, | |
187 | "source": [ |
|
119 | "source": [ | |
188 | "The view used to display a widget must defined by the time the widget is displayed. If children widgets are to be displayed along with the parent in one call, their `view_name`s can't be set since all of the widgets are sharing the same display call. Instead, their `default_view_name`s must be set (as seen below)." |
|
120 | "The view used to display a widget must defined by the time the widget is displayed. If children widgets are to be displayed along with the parent in one call, their `view_name`s can't be set since all of the widgets are sharing the same display call. Instead, their `default_view_name`s must be set (as seen below)." | |
189 | ] |
|
121 | ] | |
190 | }, |
|
122 | }, | |
191 | { |
|
123 | { | |
192 | "cell_type": "code", |
|
124 | "cell_type": "code", | |
193 | "collapsed": false, |
|
125 | "collapsed": false, | |
194 | "input": [ |
|
126 | "input": [ | |
195 | "container = widgets.MulticontainerWidget()\n", |
|
127 | "container = widgets.MulticontainerWidget()\n", | |
196 | "\n", |
|
128 | "\n", | |
197 | "floatrange = widgets.FloatRangeWidget(parent=container)\n", |
|
129 | "floatrange = widgets.FloatRangeWidget(parent=container)\n", | |
198 | "floatrange.default_view_name = \"FloatTextView\" # It can be set as a property.\n", |
|
130 | "floatrange.default_view_name = \"FloatTextView\" # It can be set as a property.\n", | |
199 | "\n", |
|
131 | "\n", | |
200 | "string = widgets.StringWidget(default_view_name = \"TextAreaView\") # It can also be set in the constructor.\n", |
|
132 | "string = widgets.StringWidget(default_view_name = \"TextAreaView\") # It can also be set in the constructor.\n", | |
201 | "string.parent = container\n", |
|
133 | "string.parent = container\n", | |
202 | "\n", |
|
134 | "\n", | |
203 | "display(container)" |
|
135 | "display(container)" | |
204 | ], |
|
136 | ], | |
205 | "language": "python", |
|
137 | "language": "python", | |
206 | "metadata": {}, |
|
138 | "metadata": {}, | |
207 | "outputs": [], |
|
139 | "outputs": [], | |
208 | "prompt_number": 5 |
|
140 | "prompt_number": 5 | |
209 | }, |
|
141 | }, | |
210 | { |
|
142 | { | |
211 | "cell_type": "markdown", |
|
143 | "cell_type": "markdown", | |
212 | "metadata": {}, |
|
144 | "metadata": {}, | |
213 | "source": [ |
|
145 | "source": [ | |
214 | "However, if the children are displayed after the parent, their `view_name` can also be set like normal. Both methods will work. The code below produces the same output as the code above." |
|
146 | "However, if the children are displayed after the parent, their `view_name` can also be set like normal. Both methods will work. The code below produces the same output as the code above." | |
215 | ] |
|
147 | ] | |
216 | }, |
|
148 | }, | |
217 | { |
|
149 | { | |
218 | "cell_type": "code", |
|
150 | "cell_type": "code", | |
219 | "collapsed": false, |
|
151 | "collapsed": false, | |
220 | "input": [ |
|
152 | "input": [ | |
221 | "container = widgets.MulticontainerWidget()\n", |
|
153 | "container = widgets.MulticontainerWidget()\n", | |
222 | "display(container)\n", |
|
154 | "display(container)\n", | |
223 | "\n", |
|
155 | "\n", | |
224 | "floatrange = widgets.FloatRangeWidget()\n", |
|
156 | "floatrange = widgets.FloatRangeWidget()\n", | |
225 | "floatrange.parent=container\n", |
|
157 | "floatrange.parent=container\n", | |
226 | "display(floatrange, view_name = \"FloatTextView\") # view_name can be set during display.\n", |
|
158 | "display(floatrange, view_name = \"FloatTextView\") # view_name can be set during display.\n", | |
227 | "\n", |
|
159 | "\n", | |
228 | "string = widgets.StringWidget()\n", |
|
160 | "string = widgets.StringWidget()\n", | |
229 | "string.parent = container\n", |
|
161 | "string.parent = container\n", | |
230 | "string.default_view_name = \"TextAreaView\" # Setting default_view_name still works.\n", |
|
162 | "string.default_view_name = \"TextAreaView\" # Setting default_view_name still works.\n", | |
231 | "display(string)\n" |
|
163 | "display(string)\n" | |
232 | ], |
|
164 | ], | |
233 | "language": "python", |
|
165 | "language": "python", | |
234 | "metadata": {}, |
|
166 | "metadata": {}, | |
235 | "outputs": [], |
|
167 | "outputs": [], | |
236 | "prompt_number": 6 |
|
168 | "prompt_number": 6 | |
237 | }, |
|
169 | }, | |
238 | { |
|
170 | { | |
239 | "cell_type": "heading", |
|
171 | "cell_type": "heading", | |
240 | "level": 1, |
|
172 | "level": 1, | |
241 | "metadata": {}, |
|
173 | "metadata": {}, | |
242 | "source": [ |
|
174 | "source": [ | |
243 | "Visibility" |
|
175 | "Visibility" | |
244 | ] |
|
176 | ] | |
245 | }, |
|
177 | }, | |
246 | { |
|
178 | { | |
247 | "cell_type": "markdown", |
|
179 | "cell_type": "markdown", | |
248 | "metadata": {}, |
|
180 | "metadata": {}, | |
249 | "source": [ |
|
181 | "source": [ | |
250 | "Sometimes it's necessary to hide/show widget views in place, without ruining the order that they have been displayed on the page. Using the `display` method, the views are always added to the end of their respective containers. Instead the `visibility` property of widgets can be used to hide/show widgets that have already been displayed (as seen below)." |
|
182 | "Sometimes it's necessary to hide/show widget views in place, without ruining the order that they have been displayed on the page. Using the `display` method, the views are always added to the end of their respective containers. Instead the `visibility` property of widgets can be used to hide/show widgets that have already been displayed (as seen below)." | |
251 | ] |
|
183 | ] | |
252 | }, |
|
184 | }, | |
253 | { |
|
185 | { | |
254 | "cell_type": "code", |
|
186 | "cell_type": "code", | |
255 | "collapsed": false, |
|
187 | "collapsed": false, | |
256 | "input": [ |
|
188 | "input": [ | |
257 | "string = widgets.StringWidget(value=\"Hello World!\")\n", |
|
189 | "string = widgets.StringWidget(value=\"Hello World!\")\n", | |
258 | "display(string, view_name=\"LabelView\") " |
|
190 | "display(string, view_name=\"LabelView\") " | |
259 | ], |
|
191 | ], | |
260 | "language": "python", |
|
192 | "language": "python", | |
261 | "metadata": {}, |
|
193 | "metadata": {}, | |
262 | "outputs": [], |
|
194 | "outputs": [], | |
263 | "prompt_number": 7 |
|
195 | "prompt_number": 7 | |
264 | }, |
|
196 | }, | |
265 | { |
|
197 | { | |
266 | "cell_type": "code", |
|
198 | "cell_type": "code", | |
267 | "collapsed": false, |
|
199 | "collapsed": false, | |
268 | "input": [ |
|
200 | "input": [ | |
269 | "string.visible=False" |
|
201 | "string.visible=False" | |
270 | ], |
|
202 | ], | |
271 | "language": "python", |
|
203 | "language": "python", | |
272 | "metadata": {}, |
|
204 | "metadata": {}, | |
273 | "outputs": [], |
|
205 | "outputs": [], | |
274 | "prompt_number": 8 |
|
206 | "prompt_number": 8 | |
275 | }, |
|
207 | }, | |
276 | { |
|
208 | { | |
277 | "cell_type": "code", |
|
209 | "cell_type": "code", | |
278 | "collapsed": false, |
|
210 | "collapsed": false, | |
279 | "input": [ |
|
211 | "input": [ | |
280 | "string.visible=True" |
|
212 | "string.visible=True" | |
281 | ], |
|
213 | ], | |
282 | "language": "python", |
|
214 | "language": "python", | |
283 | "metadata": {}, |
|
215 | "metadata": {}, | |
284 | "outputs": [], |
|
216 | "outputs": [], | |
285 | "prompt_number": 9 |
|
217 | "prompt_number": 9 | |
286 | }, |
|
218 | }, | |
287 | { |
|
219 | { | |
288 | "cell_type": "markdown", |
|
220 | "cell_type": "markdown", | |
289 | "metadata": {}, |
|
221 | "metadata": {}, | |
290 | "source": [ |
|
222 | "source": [ | |
291 | "In the example below, a form is rendered which conditionally displays widgets depending on the state of other widgets. Try toggling the student checkbox." |
|
223 | "In the example below, a form is rendered which conditionally displays widgets depending on the state of other widgets. Try toggling the student checkbox." | |
292 | ] |
|
224 | ] | |
293 | }, |
|
225 | }, | |
294 | { |
|
226 | { | |
295 | "cell_type": "code", |
|
227 | "cell_type": "code", | |
296 | "collapsed": false, |
|
228 | "collapsed": false, | |
297 | "input": [ |
|
229 | "input": [ | |
298 | "form = widgets.ContainerWidget()\n", |
|
230 | "form = widgets.ContainerWidget()\n", | |
299 | "first = widgets.StringWidget(description=\"First Name:\", parent=form)\n", |
|
231 | "first = widgets.StringWidget(description=\"First Name:\", parent=form)\n", | |
300 | "last = widgets.StringWidget(description=\"Last Name:\", parent=form)\n", |
|
232 | "last = widgets.StringWidget(description=\"Last Name:\", parent=form)\n", | |
301 | "\n", |
|
233 | "\n", | |
302 | "student = widgets.BoolWidget(description=\"Student:\", value=False, parent=form)\n", |
|
234 | "student = widgets.BoolWidget(description=\"Student:\", value=False, parent=form)\n", | |
303 | "school_info = widgets.ContainerWidget(visible=False, parent=form)\n", |
|
235 | "school_info = widgets.ContainerWidget(visible=False, parent=form)\n", | |
304 | "school = widgets.StringWidget(description=\"School:\", parent=school_info)\n", |
|
236 | "school = widgets.StringWidget(description=\"School:\", parent=school_info)\n", | |
305 | "grade = widgets.IntRangeWidget(description=\"Grade:\", min=0, max=12, default_view_name='IntTextView', parent=school_info)\n", |
|
237 | "grade = widgets.IntRangeWidget(description=\"Grade:\", min=0, max=12, default_view_name='IntTextView', parent=school_info)\n", | |
306 | "\n", |
|
238 | "\n", | |
307 | "pet = widgets.StringWidget(description=\"Pet's Name:\", parent=form)\n", |
|
239 | "pet = widgets.StringWidget(description=\"Pet's Name:\", parent=form)\n", | |
308 | "display(form)\n", |
|
240 | "display(form)\n", | |
309 | "\n", |
|
241 | "\n", | |
310 | "def on_student_toggle(name, value):\n", |
|
242 | "def on_student_toggle(name, value):\n", | |
311 | " if value:\n", |
|
243 | " if value:\n", | |
312 | " school_info.visible = True\n", |
|
244 | " school_info.visible = True\n", | |
313 | " else:\n", |
|
245 | " else:\n", | |
314 | " school_info.visible = False\n", |
|
246 | " school_info.visible = False\n", | |
315 | "student.on_trait_change(on_student_toggle, 'value')\n" |
|
247 | "student.on_trait_change(on_student_toggle, 'value')\n" | |
316 | ], |
|
248 | ], | |
317 | "language": "python", |
|
249 | "language": "python", | |
318 | "metadata": {}, |
|
250 | "metadata": {}, | |
319 | "outputs": [], |
|
251 | "outputs": [], | |
320 | "prompt_number": 10 |
|
252 | "prompt_number": 10 | |
321 | } |
|
253 | } | |
322 | ], |
|
254 | ], | |
323 | "metadata": {} |
|
255 | "metadata": {} | |
324 | } |
|
256 | } | |
325 | ] |
|
257 | ] | |
326 | } No newline at end of file |
|
258 | } |
@@ -1,405 +1,337 b'' | |||||
1 | { |
|
1 | { | |
2 | "metadata": { |
|
2 | "metadata": { | |
|
3 | "cell_tags": [ | |||
|
4 | [ | |||
|
5 | "<None>", | |||
|
6 | null | |||
|
7 | ] | |||
|
8 | ], | |||
3 | "name": "" |
|
9 | "name": "" | |
4 | }, |
|
10 | }, | |
5 | "nbformat": 3, |
|
11 | "nbformat": 3, | |
6 | "nbformat_minor": 0, |
|
12 | "nbformat_minor": 0, | |
7 | "worksheets": [ |
|
13 | "worksheets": [ | |
8 | { |
|
14 | { | |
9 | "cells": [ |
|
15 | "cells": [ | |
10 | { |
|
16 | { | |
11 | "cell_type": "code", |
|
17 | "cell_type": "code", | |
12 | "collapsed": false, |
|
18 | "collapsed": false, | |
13 | "input": [ |
|
19 | "input": [ | |
14 | "from IPython.html import widgets # Widget definitions\n", |
|
20 | "from IPython.html import widgets # Widget definitions\n", | |
15 |
"from IPython.display import display # Used to display widgets in the notebook |
|
21 | "from IPython.display import display # Used to display widgets in the notebook" | |
16 | "\n", |
|
|||
17 | "# Enable widgets in this notebook\n", |
|
|||
18 | "widgets.init_widget_js()" |
|
|||
19 | ], |
|
22 | ], | |
20 | "language": "python", |
|
23 | "language": "python", | |
21 | "metadata": {}, |
|
24 | "metadata": {}, | |
22 | "outputs": [ |
|
25 | "outputs": [], | |
23 | { |
|
|||
24 | "javascript": [ |
|
|||
25 | "$.getScript(\"../static/notebook/js/widgets/bool.js\");" |
|
|||
26 | ], |
|
|||
27 | "metadata": {}, |
|
|||
28 | "output_type": "display_data" |
|
|||
29 | }, |
|
|||
30 | { |
|
|||
31 | "javascript": [ |
|
|||
32 | "$.getScript(\"../static/notebook/js/widgets/int_range.js\");" |
|
|||
33 | ], |
|
|||
34 | "metadata": {}, |
|
|||
35 | "output_type": "display_data" |
|
|||
36 | }, |
|
|||
37 | { |
|
|||
38 | "javascript": [ |
|
|||
39 | "$.getScript(\"../static/notebook/js/widgets/int.js\");" |
|
|||
40 | ], |
|
|||
41 | "metadata": {}, |
|
|||
42 | "output_type": "display_data" |
|
|||
43 | }, |
|
|||
44 | { |
|
|||
45 | "javascript": [ |
|
|||
46 | "$.getScript(\"../static/notebook/js/widgets/selection.js\");" |
|
|||
47 | ], |
|
|||
48 | "metadata": {}, |
|
|||
49 | "output_type": "display_data" |
|
|||
50 | }, |
|
|||
51 | { |
|
|||
52 | "javascript": [ |
|
|||
53 | "$.getScript(\"../static/notebook/js/widgets/string.js\");" |
|
|||
54 | ], |
|
|||
55 | "metadata": {}, |
|
|||
56 | "output_type": "display_data" |
|
|||
57 | }, |
|
|||
58 | { |
|
|||
59 | "javascript": [ |
|
|||
60 | "$.getScript(\"../static/notebook/js/widgets/float.js\");" |
|
|||
61 | ], |
|
|||
62 | "metadata": {}, |
|
|||
63 | "output_type": "display_data" |
|
|||
64 | }, |
|
|||
65 | { |
|
|||
66 | "javascript": [ |
|
|||
67 | "$.getScript(\"../static/notebook/js/widgets/container.js\");" |
|
|||
68 | ], |
|
|||
69 | "metadata": {}, |
|
|||
70 | "output_type": "display_data" |
|
|||
71 | }, |
|
|||
72 | { |
|
|||
73 | "javascript": [ |
|
|||
74 | "$.getScript(\"../static/notebook/js/widgets/multicontainer.js\");" |
|
|||
75 | ], |
|
|||
76 | "metadata": {}, |
|
|||
77 | "output_type": "display_data" |
|
|||
78 | }, |
|
|||
79 | { |
|
|||
80 | "javascript": [ |
|
|||
81 | "$.getScript(\"../static/notebook/js/widgets/button.js\");" |
|
|||
82 | ], |
|
|||
83 | "metadata": {}, |
|
|||
84 | "output_type": "display_data" |
|
|||
85 | }, |
|
|||
86 | { |
|
|||
87 | "javascript": [ |
|
|||
88 | "$.getScript(\"../static/notebook/js/widgets/float_range.js\");" |
|
|||
89 | ], |
|
|||
90 | "metadata": {}, |
|
|||
91 | "output_type": "display_data" |
|
|||
92 | } |
|
|||
93 | ], |
|
|||
94 | "prompt_number": 1 |
|
26 | "prompt_number": 1 | |
95 | }, |
|
27 | }, | |
96 | { |
|
28 | { | |
97 | "cell_type": "heading", |
|
29 | "cell_type": "heading", | |
98 | "level": 1, |
|
30 | "level": 1, | |
99 | "metadata": {}, |
|
31 | "metadata": {}, | |
100 | "source": [ |
|
32 | "source": [ | |
101 | "CSS" |
|
33 | "CSS" | |
102 | ] |
|
34 | ] | |
103 | }, |
|
35 | }, | |
104 | { |
|
36 | { | |
105 | "cell_type": "markdown", |
|
37 | "cell_type": "markdown", | |
106 | "metadata": {}, |
|
38 | "metadata": {}, | |
107 | "source": [ |
|
39 | "source": [ | |
108 | "When trying to design an attractive widget GUI, styling becomes important. Widget views are DOM (document object model) elements that can be controlled with CSS. There are two helper methods defined on widget that allow the manipulation of the widget's CSS. The first is the `set_css` method, whos doc string is displayed below. This method allows one or more CSS attributes to be set at once. " |
|
40 | "When trying to design an attractive widget GUI, styling becomes important. Widget views are DOM (document object model) elements that can be controlled with CSS. There are two helper methods defined on widget that allow the manipulation of the widget's CSS. The first is the `set_css` method, whos doc string is displayed below. This method allows one or more CSS attributes to be set at once. " | |
109 | ] |
|
41 | ] | |
110 | }, |
|
42 | }, | |
111 | { |
|
43 | { | |
112 | "cell_type": "code", |
|
44 | "cell_type": "code", | |
113 | "collapsed": false, |
|
45 | "collapsed": false, | |
114 | "input": [ |
|
46 | "input": [ | |
115 | "print(widgets.Widget.set_css.__doc__)" |
|
47 | "print(widgets.Widget.set_css.__doc__)" | |
116 | ], |
|
48 | ], | |
117 | "language": "python", |
|
49 | "language": "python", | |
118 | "metadata": {}, |
|
50 | "metadata": {}, | |
119 | "outputs": [ |
|
51 | "outputs": [ | |
120 | { |
|
52 | { | |
121 | "output_type": "stream", |
|
53 | "output_type": "stream", | |
122 | "stream": "stdout", |
|
54 | "stream": "stdout", | |
123 | "text": [ |
|
55 | "text": [ | |
124 | "Set one or more CSS properties of the widget (shared among all of the \n", |
|
56 | "Set one or more CSS properties of the widget (shared among all of the \n", | |
125 | " views). This function has two signatures:\n", |
|
57 | " views). This function has two signatures:\n", | |
126 | " - set_css(css_dict, [selector=''])\n", |
|
58 | " - set_css(css_dict, [selector=''])\n", | |
127 | " - set_css(key, value, [selector=''])\n", |
|
59 | " - set_css(key, value, [selector=''])\n", | |
128 | "\n", |
|
60 | "\n", | |
129 | " Parameters\n", |
|
61 | " Parameters\n", | |
130 | " ----------\n", |
|
62 | " ----------\n", | |
131 | " css_dict : dict\n", |
|
63 | " css_dict : dict\n", | |
132 | " CSS key/value pairs to apply\n", |
|
64 | " CSS key/value pairs to apply\n", | |
133 | " key: unicode\n", |
|
65 | " key: unicode\n", | |
134 | " CSS key\n", |
|
66 | " CSS key\n", | |
135 | " value\n", |
|
67 | " value\n", | |
136 | " CSS value\n", |
|
68 | " CSS value\n", | |
137 | " selector: unicode (optional)\n", |
|
69 | " selector: unicode (optional)\n", | |
138 | " JQuery selector to use to apply the CSS key/value.\n", |
|
70 | " JQuery selector to use to apply the CSS key/value.\n", | |
139 | " \n" |
|
71 | " \n" | |
140 | ] |
|
72 | ] | |
141 | } |
|
73 | } | |
142 | ], |
|
74 | ], | |
143 | "prompt_number": 2 |
|
75 | "prompt_number": 2 | |
144 | }, |
|
76 | }, | |
145 | { |
|
77 | { | |
146 | "cell_type": "markdown", |
|
78 | "cell_type": "markdown", | |
147 | "metadata": {}, |
|
79 | "metadata": {}, | |
148 | "source": [ |
|
80 | "source": [ | |
149 | "The second is `get_css` which allows CSS attributes that have been set to be read. Note that this method will only read CSS attributes that have been set using the `set_css` method. `get_css`'s doc string is displayed below." |
|
81 | "The second is `get_css` which allows CSS attributes that have been set to be read. Note that this method will only read CSS attributes that have been set using the `set_css` method. `get_css`'s doc string is displayed below." | |
150 | ] |
|
82 | ] | |
151 | }, |
|
83 | }, | |
152 | { |
|
84 | { | |
153 | "cell_type": "code", |
|
85 | "cell_type": "code", | |
154 | "collapsed": false, |
|
86 | "collapsed": false, | |
155 | "input": [ |
|
87 | "input": [ | |
156 | "print(widgets.Widget.get_css.__doc__)" |
|
88 | "print(widgets.Widget.get_css.__doc__)" | |
157 | ], |
|
89 | ], | |
158 | "language": "python", |
|
90 | "language": "python", | |
159 | "metadata": {}, |
|
91 | "metadata": {}, | |
160 | "outputs": [ |
|
92 | "outputs": [ | |
161 | { |
|
93 | { | |
162 | "output_type": "stream", |
|
94 | "output_type": "stream", | |
163 | "stream": "stdout", |
|
95 | "stream": "stdout", | |
164 | "text": [ |
|
96 | "text": [ | |
165 | "Get a CSS property of the widget. Note, this function does not \n", |
|
97 | "Get a CSS property of the widget. Note, this function does not \n", | |
166 | " actually request the CSS from the front-end; Only properties that have \n", |
|
98 | " actually request the CSS from the front-end; Only properties that have \n", | |
167 | " been set with set_css can be read.\n", |
|
99 | " been set with set_css can be read.\n", | |
168 | "\n", |
|
100 | "\n", | |
169 | " Parameters\n", |
|
101 | " Parameters\n", | |
170 | " ----------\n", |
|
102 | " ----------\n", | |
171 | " key: unicode\n", |
|
103 | " key: unicode\n", | |
172 | " CSS key\n", |
|
104 | " CSS key\n", | |
173 | " selector: unicode (optional)\n", |
|
105 | " selector: unicode (optional)\n", | |
174 | " JQuery selector used when the CSS key/value was set.\n", |
|
106 | " JQuery selector used when the CSS key/value was set.\n", | |
175 | " \n" |
|
107 | " \n" | |
176 | ] |
|
108 | ] | |
177 | } |
|
109 | } | |
178 | ], |
|
110 | ], | |
179 | "prompt_number": 3 |
|
111 | "prompt_number": 3 | |
180 | }, |
|
112 | }, | |
181 | { |
|
113 | { | |
182 | "cell_type": "markdown", |
|
114 | "cell_type": "markdown", | |
183 | "metadata": {}, |
|
115 | "metadata": {}, | |
184 | "source": [ |
|
116 | "source": [ | |
185 | "Below is an example that applies CSS attributes to a container to emphasize text." |
|
117 | "Below is an example that applies CSS attributes to a container to emphasize text." | |
186 | ] |
|
118 | ] | |
187 | }, |
|
119 | }, | |
188 | { |
|
120 | { | |
189 | "cell_type": "code", |
|
121 | "cell_type": "code", | |
190 | "collapsed": false, |
|
122 | "collapsed": false, | |
191 | "input": [ |
|
123 | "input": [ | |
192 | "container = widgets.ContainerWidget()\n", |
|
124 | "container = widgets.ContainerWidget()\n", | |
193 | "\n", |
|
125 | "\n", | |
194 | "# set_css used to set a single CSS attribute.\n", |
|
126 | "# set_css used to set a single CSS attribute.\n", | |
195 | "container.set_css('border', '3px solid black') # Border the container\n", |
|
127 | "container.set_css('border', '3px solid black') # Border the container\n", | |
196 | "\n", |
|
128 | "\n", | |
197 | "# set_css used to set multiple CSS attributes.\n", |
|
129 | "# set_css used to set multiple CSS attributes.\n", | |
198 | "container.set_css({'padding': '6px', # Add padding to the container\n", |
|
130 | "container.set_css({'padding': '6px', # Add padding to the container\n", | |
199 | " 'background': 'yellow'}) # Fill the container yellow\n", |
|
131 | " 'background': 'yellow'}) # Fill the container yellow\n", | |
200 | "\n", |
|
132 | "\n", | |
201 | "label = widgets.StringWidget(default_view_name=\"LabelView\", parent=container)\n", |
|
133 | "label = widgets.StringWidget(default_view_name=\"LabelView\", parent=container)\n", | |
202 | "label.value = \"<strong>ALERT: </strong> Hello World!\"\n", |
|
134 | "label.value = \"<strong>ALERT: </strong> Hello World!\"\n", | |
203 | "\n", |
|
135 | "\n", | |
204 | "display(container)" |
|
136 | "display(container)" | |
205 | ], |
|
137 | ], | |
206 | "language": "python", |
|
138 | "language": "python", | |
207 | "metadata": {}, |
|
139 | "metadata": {}, | |
208 | "outputs": [], |
|
140 | "outputs": [], | |
209 | "prompt_number": 4 |
|
141 | "prompt_number": 4 | |
210 | }, |
|
142 | }, | |
211 | { |
|
143 | { | |
212 | "cell_type": "heading", |
|
144 | "cell_type": "heading", | |
213 | "level": 1, |
|
145 | "level": 1, | |
214 | "metadata": {}, |
|
146 | "metadata": {}, | |
215 | "source": [ |
|
147 | "source": [ | |
216 | "DOM Classes" |
|
148 | "DOM Classes" | |
217 | ] |
|
149 | ] | |
218 | }, |
|
150 | }, | |
219 | { |
|
151 | { | |
220 | "cell_type": "markdown", |
|
152 | "cell_type": "markdown", | |
221 | "metadata": {}, |
|
153 | "metadata": {}, | |
222 | "source": [ |
|
154 | "source": [ | |
223 | "In some cases it's necessary to apply DOM classes to your widgets. DOM classes allow DOM elements to be indentified by Javascript and CSS. The notebook defines its own set of classes to stylize its elements. The `add_class` widget method allows you to add DOM classes to your widget's definition. The `add_class` method's doc string can be seen below." |
|
155 | "In some cases it's necessary to apply DOM classes to your widgets. DOM classes allow DOM elements to be indentified by Javascript and CSS. The notebook defines its own set of classes to stylize its elements. The `add_class` widget method allows you to add DOM classes to your widget's definition. The `add_class` method's doc string can be seen below." | |
224 | ] |
|
156 | ] | |
225 | }, |
|
157 | }, | |
226 | { |
|
158 | { | |
227 | "cell_type": "code", |
|
159 | "cell_type": "code", | |
228 | "collapsed": false, |
|
160 | "collapsed": false, | |
229 | "input": [ |
|
161 | "input": [ | |
230 | "print(widgets.Widget.add_class.__doc__)" |
|
162 | "print(widgets.Widget.add_class.__doc__)" | |
231 | ], |
|
163 | ], | |
232 | "language": "python", |
|
164 | "language": "python", | |
233 | "metadata": {}, |
|
165 | "metadata": {}, | |
234 | "outputs": [ |
|
166 | "outputs": [ | |
235 | { |
|
167 | { | |
236 | "output_type": "stream", |
|
168 | "output_type": "stream", | |
237 | "stream": "stdout", |
|
169 | "stream": "stdout", | |
238 | "text": [ |
|
170 | "text": [ | |
239 | "Add class[es] to a DOM element\n", |
|
171 | "Add class[es] to a DOM element\n", | |
240 | "\n", |
|
172 | "\n", | |
241 | " Parameters\n", |
|
173 | " Parameters\n", | |
242 | " ----------\n", |
|
174 | " ----------\n", | |
243 | " class_name: unicode\n", |
|
175 | " class_name: unicode\n", | |
244 | " Class name(s) to add to the DOM element(s). Multiple class names \n", |
|
176 | " Class name(s) to add to the DOM element(s). Multiple class names \n", | |
245 | " must be space separated.\n", |
|
177 | " must be space separated.\n", | |
246 | " selector: unicode (optional)\n", |
|
178 | " selector: unicode (optional)\n", | |
247 | " JQuery selector to select the DOM element(s) that the class(es) will \n", |
|
179 | " JQuery selector to select the DOM element(s) that the class(es) will \n", | |
248 | " be added to.\n", |
|
180 | " be added to.\n", | |
249 | " \n" |
|
181 | " \n" | |
250 | ] |
|
182 | ] | |
251 | } |
|
183 | } | |
252 | ], |
|
184 | ], | |
253 | "prompt_number": 5 |
|
185 | "prompt_number": 5 | |
254 | }, |
|
186 | }, | |
255 | { |
|
187 | { | |
256 | "cell_type": "markdown", |
|
188 | "cell_type": "markdown", | |
257 | "metadata": {}, |
|
189 | "metadata": {}, | |
258 | "source": [ |
|
190 | "source": [ | |
259 | "Since `add_class` if a DOM operation, it will only affect widgets that have been displayed. `add_class` must be called after the widget has been displayed. Extending the example above, the corners of the container can be rounded by adding the `corner-all` notebook class to the container (as seen below). " |
|
191 | "Since `add_class` if a DOM operation, it will only affect widgets that have been displayed. `add_class` must be called after the widget has been displayed. Extending the example above, the corners of the container can be rounded by adding the `corner-all` notebook class to the container (as seen below). " | |
260 | ] |
|
192 | ] | |
261 | }, |
|
193 | }, | |
262 | { |
|
194 | { | |
263 | "cell_type": "code", |
|
195 | "cell_type": "code", | |
264 | "collapsed": false, |
|
196 | "collapsed": false, | |
265 | "input": [ |
|
197 | "input": [ | |
266 | "container = widgets.ContainerWidget()\n", |
|
198 | "container = widgets.ContainerWidget()\n", | |
267 | "container.set_css({'border': '3px solid black',\n", |
|
199 | "container.set_css({'border': '3px solid black',\n", | |
268 | " 'padding': '6px',\n", |
|
200 | " 'padding': '6px',\n", | |
269 | " 'background': 'yellow'}) \n", |
|
201 | " 'background': 'yellow'}) \n", | |
270 | "\n", |
|
202 | "\n", | |
271 | "label = widgets.StringWidget(default_view_name=\"LabelView\", parent=container) \n", |
|
203 | "label = widgets.StringWidget(default_view_name=\"LabelView\", parent=container) \n", | |
272 | "label.value = \"<strong>ALERT: </strong> Hello World!\"\n", |
|
204 | "label.value = \"<strong>ALERT: </strong> Hello World!\"\n", | |
273 | "\n", |
|
205 | "\n", | |
274 | "display(container)\n", |
|
206 | "display(container)\n", | |
275 | "container.add_class('corner-all') # Must be called AFTER display" |
|
207 | "container.add_class('corner-all') # Must be called AFTER display" | |
276 | ], |
|
208 | ], | |
277 | "language": "python", |
|
209 | "language": "python", | |
278 | "metadata": {}, |
|
210 | "metadata": {}, | |
279 | "outputs": [], |
|
211 | "outputs": [], | |
280 | "prompt_number": 6 |
|
212 | "prompt_number": 6 | |
281 | }, |
|
213 | }, | |
282 | { |
|
214 | { | |
283 | "cell_type": "markdown", |
|
215 | "cell_type": "markdown", | |
284 | "metadata": {}, |
|
216 | "metadata": {}, | |
285 | "source": [ |
|
217 | "source": [ | |
286 | "The IPython notebook uses bootstrap for styling. The example above can be simplified by using a bootstrap class (as seen below). Bootstrap documentation can be found at http://getbootstrap.com/\u200e ." |
|
218 | "The IPython notebook uses bootstrap for styling. The example above can be simplified by using a bootstrap class (as seen below). Bootstrap documentation can be found at http://getbootstrap.com/\u200e ." | |
287 | ] |
|
219 | ] | |
288 | }, |
|
220 | }, | |
289 | { |
|
221 | { | |
290 | "cell_type": "code", |
|
222 | "cell_type": "code", | |
291 | "collapsed": false, |
|
223 | "collapsed": false, | |
292 | "input": [ |
|
224 | "input": [ | |
293 | "label = widgets.StringWidget(value = \"<strong>ALERT: </strong> Hello World!\")\n", |
|
225 | "label = widgets.StringWidget(value = \"<strong>ALERT: </strong> Hello World!\")\n", | |
294 | "display(label, view_name=\"LabelView\")\n", |
|
226 | "display(label, view_name=\"LabelView\")\n", | |
295 | "\n", |
|
227 | "\n", | |
296 | "# Apply twitter bootstrap alert class to the label.\n", |
|
228 | "# Apply twitter bootstrap alert class to the label.\n", | |
297 | "label.add_class(\"alert\")" |
|
229 | "label.add_class(\"alert\")" | |
298 | ], |
|
230 | ], | |
299 | "language": "python", |
|
231 | "language": "python", | |
300 | "metadata": {}, |
|
232 | "metadata": {}, | |
301 | "outputs": [], |
|
233 | "outputs": [], | |
302 | "prompt_number": 7 |
|
234 | "prompt_number": 7 | |
303 | }, |
|
235 | }, | |
304 | { |
|
236 | { | |
305 | "cell_type": "markdown", |
|
237 | "cell_type": "markdown", | |
306 | "metadata": {}, |
|
238 | "metadata": {}, | |
307 | "source": [ |
|
239 | "source": [ | |
308 | "The example below shows how bootstrap classes can be used to change button apearance." |
|
240 | "The example below shows how bootstrap classes can be used to change button apearance." | |
309 | ] |
|
241 | ] | |
310 | }, |
|
242 | }, | |
311 | { |
|
243 | { | |
312 | "cell_type": "code", |
|
244 | "cell_type": "code", | |
313 | "collapsed": false, |
|
245 | "collapsed": false, | |
314 | "input": [ |
|
246 | "input": [ | |
315 | "# List of the bootstrap button styles\n", |
|
247 | "# List of the bootstrap button styles\n", | |
316 | "button_classes = ['Default', 'btn-primary', 'btn-info', 'btn-success', \n", |
|
248 | "button_classes = ['Default', 'btn-primary', 'btn-info', 'btn-success', \n", | |
317 | " 'btn-warning', 'btn-danger', 'btn-inverse', 'btn-link']\n", |
|
249 | " 'btn-warning', 'btn-danger', 'btn-inverse', 'btn-link']\n", | |
318 | "\n", |
|
250 | "\n", | |
319 | "# Create each button and apply the style. Also add margin to the buttons so they space\n", |
|
251 | "# Create each button and apply the style. Also add margin to the buttons so they space\n", | |
320 | "# themselves nicely.\n", |
|
252 | "# themselves nicely.\n", | |
321 | "for i in range(8):\n", |
|
253 | "for i in range(8):\n", | |
322 | " button = widgets.ButtonWidget(description=button_classes[i])\n", |
|
254 | " button = widgets.ButtonWidget(description=button_classes[i])\n", | |
323 | " button.set_css(\"margin\", \"5px\")\n", |
|
255 | " button.set_css(\"margin\", \"5px\")\n", | |
324 | " display(button)\n", |
|
256 | " display(button)\n", | |
325 | " if i > 0: # Don't add a class the first button.\n", |
|
257 | " if i > 0: # Don't add a class the first button.\n", | |
326 | " button.add_class(button_classes[i])\n", |
|
258 | " button.add_class(button_classes[i])\n", | |
327 | " " |
|
259 | " " | |
328 | ], |
|
260 | ], | |
329 | "language": "python", |
|
261 | "language": "python", | |
330 | "metadata": {}, |
|
262 | "metadata": {}, | |
331 | "outputs": [], |
|
263 | "outputs": [], | |
332 | "prompt_number": 8 |
|
264 | "prompt_number": 8 | |
333 | }, |
|
265 | }, | |
334 | { |
|
266 | { | |
335 | "cell_type": "markdown", |
|
267 | "cell_type": "markdown", | |
336 | "metadata": {}, |
|
268 | "metadata": {}, | |
337 | "source": [ |
|
269 | "source": [ | |
338 | "It's also useful to be able to remove DOM classes from widgets. The `remove_class` widget method allows you to remove classes from widgets that have been displayed. Like `add_widget`, it must be called after the widget has been displayed. The doc string of `remove_class` can be seen below." |
|
270 | "It's also useful to be able to remove DOM classes from widgets. The `remove_class` widget method allows you to remove classes from widgets that have been displayed. Like `add_widget`, it must be called after the widget has been displayed. The doc string of `remove_class` can be seen below." | |
339 | ] |
|
271 | ] | |
340 | }, |
|
272 | }, | |
341 | { |
|
273 | { | |
342 | "cell_type": "code", |
|
274 | "cell_type": "code", | |
343 | "collapsed": false, |
|
275 | "collapsed": false, | |
344 | "input": [ |
|
276 | "input": [ | |
345 | "print(widgets.Widget.remove_class.__doc__)" |
|
277 | "print(widgets.Widget.remove_class.__doc__)" | |
346 | ], |
|
278 | ], | |
347 | "language": "python", |
|
279 | "language": "python", | |
348 | "metadata": {}, |
|
280 | "metadata": {}, | |
349 | "outputs": [ |
|
281 | "outputs": [ | |
350 | { |
|
282 | { | |
351 | "output_type": "stream", |
|
283 | "output_type": "stream", | |
352 | "stream": "stdout", |
|
284 | "stream": "stdout", | |
353 | "text": [ |
|
285 | "text": [ | |
354 | "Remove class[es] from a DOM element\n", |
|
286 | "Remove class[es] from a DOM element\n", | |
355 | "\n", |
|
287 | "\n", | |
356 | " Parameters\n", |
|
288 | " Parameters\n", | |
357 | " ----------\n", |
|
289 | " ----------\n", | |
358 | " class_name: unicode\n", |
|
290 | " class_name: unicode\n", | |
359 | " Class name(s) to remove from the DOM element(s). Multiple class \n", |
|
291 | " Class name(s) to remove from the DOM element(s). Multiple class \n", | |
360 | " names must be space separated.\n", |
|
292 | " names must be space separated.\n", | |
361 | " selector: unicode (optional)\n", |
|
293 | " selector: unicode (optional)\n", | |
362 | " JQuery selector to select the DOM element(s) that the class(es) will \n", |
|
294 | " JQuery selector to select the DOM element(s) that the class(es) will \n", | |
363 | " be removed from.\n", |
|
295 | " be removed from.\n", | |
364 | " \n" |
|
296 | " \n" | |
365 | ] |
|
297 | ] | |
366 | } |
|
298 | } | |
367 | ], |
|
299 | ], | |
368 | "prompt_number": 9 |
|
300 | "prompt_number": 9 | |
369 | }, |
|
301 | }, | |
370 | { |
|
302 | { | |
371 | "cell_type": "markdown", |
|
303 | "cell_type": "markdown", | |
372 | "metadata": {}, |
|
304 | "metadata": {}, | |
373 | "source": [ |
|
305 | "source": [ | |
374 | "The example below animates an alert using different bootstrap styles." |
|
306 | "The example below animates an alert using different bootstrap styles." | |
375 | ] |
|
307 | ] | |
376 | }, |
|
308 | }, | |
377 | { |
|
309 | { | |
378 | "cell_type": "code", |
|
310 | "cell_type": "code", | |
379 | "collapsed": false, |
|
311 | "collapsed": false, | |
380 | "input": [ |
|
312 | "input": [ | |
381 | "import time\n", |
|
313 | "import time\n", | |
382 | "label = widgets.StringWidget(value = \"<strong>ALERT: </strong> Hello World!\")\n", |
|
314 | "label = widgets.StringWidget(value = \"<strong>ALERT: </strong> Hello World!\")\n", | |
383 | "display(label, view_name=\"LabelView\")\n", |
|
315 | "display(label, view_name=\"LabelView\")\n", | |
384 | "\n", |
|
316 | "\n", | |
385 | "# Apply twitter bootstrap alert class to the label.\n", |
|
317 | "# Apply twitter bootstrap alert class to the label.\n", | |
386 | "label.add_class(\"alert\")\n", |
|
318 | "label.add_class(\"alert\")\n", | |
387 | "\n", |
|
319 | "\n", | |
388 | "# Animate through additional bootstrap label styles 3 times\n", |
|
320 | "# Animate through additional bootstrap label styles 3 times\n", | |
389 | "additional_alert_styles = ['alert-error', 'alert-info', 'alert-success']\n", |
|
321 | "additional_alert_styles = ['alert-error', 'alert-info', 'alert-success']\n", | |
390 | "for i in range(3 * len(additional_alert_styles)):\n", |
|
322 | "for i in range(3 * len(additional_alert_styles)):\n", | |
391 | " label.add_class(additional_alert_styles[i % 3])\n", |
|
323 | " label.add_class(additional_alert_styles[i % 3])\n", | |
392 | " label.remove_class(additional_alert_styles[(i-1) % 3])\n", |
|
324 | " label.remove_class(additional_alert_styles[(i-1) % 3])\n", | |
393 | " time.sleep(1)\n", |
|
325 | " time.sleep(1)\n", | |
394 | " " |
|
326 | " " | |
395 | ], |
|
327 | ], | |
396 | "language": "python", |
|
328 | "language": "python", | |
397 | "metadata": {}, |
|
329 | "metadata": {}, | |
398 | "outputs": [], |
|
330 | "outputs": [], | |
399 | "prompt_number": 10 |
|
331 | "prompt_number": 10 | |
400 | } |
|
332 | } | |
401 | ], |
|
333 | ], | |
402 | "metadata": {} |
|
334 | "metadata": {} | |
403 | } |
|
335 | } | |
404 | ] |
|
336 | ] | |
405 | } No newline at end of file |
|
337 | } |
@@ -1,378 +1,304 b'' | |||||
1 | { |
|
1 | { | |
2 | "metadata": { |
|
2 | "metadata": { | |
3 | "cell_tags": [ |
|
3 | "cell_tags": [ | |
4 | [ |
|
4 | [ | |
5 | "<None>", |
|
5 | "<None>", | |
6 | null |
|
6 | null | |
7 | ] |
|
7 | ] | |
8 | ], |
|
8 | ], | |
9 | "name": "" |
|
9 | "name": "" | |
10 | }, |
|
10 | }, | |
11 | "nbformat": 3, |
|
11 | "nbformat": 3, | |
12 | "nbformat_minor": 0, |
|
12 | "nbformat_minor": 0, | |
13 | "worksheets": [ |
|
13 | "worksheets": [ | |
14 | { |
|
14 | { | |
15 | "cells": [ |
|
15 | "cells": [ | |
16 | { |
|
16 | { | |
17 | "cell_type": "code", |
|
17 | "cell_type": "code", | |
18 | "collapsed": false, |
|
18 | "collapsed": false, | |
19 | "input": [ |
|
19 | "input": [ | |
20 | "from IPython.html import widgets # Widget definitions\n", |
|
20 | "from IPython.html import widgets # Widget definitions\n", | |
21 |
"from IPython.display import display # Used to display widgets in the notebook |
|
21 | "from IPython.display import display # Used to display widgets in the notebook" | |
22 | "\n", |
|
|||
23 | "# Enable widgets in this notebook\n", |
|
|||
24 | "widgets.init_widget_js()" |
|
|||
25 | ], |
|
22 | ], | |
26 | "language": "python", |
|
23 | "language": "python", | |
27 | "metadata": {}, |
|
24 | "metadata": {}, | |
28 | "outputs": [ |
|
25 | "outputs": [], | |
29 | { |
|
|||
30 | "javascript": [ |
|
|||
31 | "$.getScript($(\"body\").data(\"baseProjectUrl\") + \"static/notebook/js/widgets/button.js\");" |
|
|||
32 | ], |
|
|||
33 | "metadata": {}, |
|
|||
34 | "output_type": "display_data" |
|
|||
35 | }, |
|
|||
36 | { |
|
|||
37 | "javascript": [ |
|
|||
38 | "$.getScript($(\"body\").data(\"baseProjectUrl\") + \"static/notebook/js/widgets/int_range.js\");" |
|
|||
39 | ], |
|
|||
40 | "metadata": {}, |
|
|||
41 | "output_type": "display_data" |
|
|||
42 | }, |
|
|||
43 | { |
|
|||
44 | "javascript": [ |
|
|||
45 | "$.getScript($(\"body\").data(\"baseProjectUrl\") + \"static/notebook/js/widgets/string.js\");" |
|
|||
46 | ], |
|
|||
47 | "metadata": {}, |
|
|||
48 | "output_type": "display_data" |
|
|||
49 | }, |
|
|||
50 | { |
|
|||
51 | "javascript": [ |
|
|||
52 | "$.getScript($(\"body\").data(\"baseProjectUrl\") + \"static/notebook/js/widgets/multicontainer.js\");" |
|
|||
53 | ], |
|
|||
54 | "metadata": {}, |
|
|||
55 | "output_type": "display_data" |
|
|||
56 | }, |
|
|||
57 | { |
|
|||
58 | "javascript": [ |
|
|||
59 | "$.getScript($(\"body\").data(\"baseProjectUrl\") + \"static/notebook/js/widgets/bool.js\");" |
|
|||
60 | ], |
|
|||
61 | "metadata": {}, |
|
|||
62 | "output_type": "display_data" |
|
|||
63 | }, |
|
|||
64 | { |
|
|||
65 | "javascript": [ |
|
|||
66 | "$.getScript($(\"body\").data(\"baseProjectUrl\") + \"static/notebook/js/widgets/int.js\");" |
|
|||
67 | ], |
|
|||
68 | "metadata": {}, |
|
|||
69 | "output_type": "display_data" |
|
|||
70 | }, |
|
|||
71 | { |
|
|||
72 | "javascript": [ |
|
|||
73 | "$.getScript($(\"body\").data(\"baseProjectUrl\") + \"static/notebook/js/widgets/selection.js\");" |
|
|||
74 | ], |
|
|||
75 | "metadata": {}, |
|
|||
76 | "output_type": "display_data" |
|
|||
77 | }, |
|
|||
78 | { |
|
|||
79 | "javascript": [ |
|
|||
80 | "$.getScript($(\"body\").data(\"baseProjectUrl\") + \"static/notebook/js/widgets/float.js\");" |
|
|||
81 | ], |
|
|||
82 | "metadata": {}, |
|
|||
83 | "output_type": "display_data" |
|
|||
84 | }, |
|
|||
85 | { |
|
|||
86 | "javascript": [ |
|
|||
87 | "$.getScript($(\"body\").data(\"baseProjectUrl\") + \"static/notebook/js/widgets/float_range.js\");" |
|
|||
88 | ], |
|
|||
89 | "metadata": {}, |
|
|||
90 | "output_type": "display_data" |
|
|||
91 | }, |
|
|||
92 | { |
|
|||
93 | "javascript": [ |
|
|||
94 | "$.getScript($(\"body\").data(\"baseProjectUrl\") + \"static/notebook/js/widgets/container.js\");" |
|
|||
95 | ], |
|
|||
96 | "metadata": {}, |
|
|||
97 | "output_type": "display_data" |
|
|||
98 | } |
|
|||
99 | ], |
|
|||
100 | "prompt_number": 1 |
|
26 | "prompt_number": 1 | |
101 | }, |
|
27 | }, | |
102 | { |
|
28 | { | |
103 | "cell_type": "heading", |
|
29 | "cell_type": "heading", | |
104 | "level": 1, |
|
30 | "level": 1, | |
105 | "metadata": {}, |
|
31 | "metadata": {}, | |
106 | "source": [ |
|
32 | "source": [ | |
107 | "Alignment" |
|
33 | "Alignment" | |
108 | ] |
|
34 | ] | |
109 | }, |
|
35 | }, | |
110 | { |
|
36 | { | |
111 | "cell_type": "markdown", |
|
37 | "cell_type": "markdown", | |
112 | "metadata": {}, |
|
38 | "metadata": {}, | |
113 | "source": [ |
|
39 | "source": [ | |
114 | "Most widgets have a `description` property which allows a label for the widget to be defined. The label of the widget has a fixed minimum width. The text of the label is always right aligned and the widget is left aligned (as seen below) " |
|
40 | "Most widgets have a `description` property which allows a label for the widget to be defined. The label of the widget has a fixed minimum width. The text of the label is always right aligned and the widget is left aligned (as seen below) " | |
115 | ] |
|
41 | ] | |
116 | }, |
|
42 | }, | |
117 | { |
|
43 | { | |
118 | "cell_type": "code", |
|
44 | "cell_type": "code", | |
119 | "collapsed": false, |
|
45 | "collapsed": false, | |
120 | "input": [ |
|
46 | "input": [ | |
121 | "display(widgets.StringWidget(description=\"a:\"))\n", |
|
47 | "display(widgets.StringWidget(description=\"a:\"))\n", | |
122 | "display(widgets.StringWidget(description=\"aa:\"))\n", |
|
48 | "display(widgets.StringWidget(description=\"aa:\"))\n", | |
123 | "display(widgets.StringWidget(description=\"aaa:\"))" |
|
49 | "display(widgets.StringWidget(description=\"aaa:\"))" | |
124 | ], |
|
50 | ], | |
125 | "language": "python", |
|
51 | "language": "python", | |
126 | "metadata": {}, |
|
52 | "metadata": {}, | |
127 | "outputs": [], |
|
53 | "outputs": [], | |
128 | "prompt_number": 2 |
|
54 | "prompt_number": 2 | |
129 | }, |
|
55 | }, | |
130 | { |
|
56 | { | |
131 | "cell_type": "markdown", |
|
57 | "cell_type": "markdown", | |
132 | "metadata": {}, |
|
58 | "metadata": {}, | |
133 | "source": [ |
|
59 | "source": [ | |
134 | "If a label is longer than the minimum width, the widget is shifted to the right (as seen below)." |
|
60 | "If a label is longer than the minimum width, the widget is shifted to the right (as seen below)." | |
135 | ] |
|
61 | ] | |
136 | }, |
|
62 | }, | |
137 | { |
|
63 | { | |
138 | "cell_type": "code", |
|
64 | "cell_type": "code", | |
139 | "collapsed": false, |
|
65 | "collapsed": false, | |
140 | "input": [ |
|
66 | "input": [ | |
141 | "display(widgets.StringWidget(description=\"a:\"))\n", |
|
67 | "display(widgets.StringWidget(description=\"a:\"))\n", | |
142 | "display(widgets.StringWidget(description=\"aa:\"))\n", |
|
68 | "display(widgets.StringWidget(description=\"aa:\"))\n", | |
143 | "display(widgets.StringWidget(description=\"aaa:\"))\n", |
|
69 | "display(widgets.StringWidget(description=\"aaa:\"))\n", | |
144 | "display(widgets.StringWidget(description=\"aaaaaaaaaaaaaaaaaa:\"))" |
|
70 | "display(widgets.StringWidget(description=\"aaaaaaaaaaaaaaaaaa:\"))" | |
145 | ], |
|
71 | ], | |
146 | "language": "python", |
|
72 | "language": "python", | |
147 | "metadata": {}, |
|
73 | "metadata": {}, | |
148 | "outputs": [], |
|
74 | "outputs": [], | |
149 | "prompt_number": 3 |
|
75 | "prompt_number": 3 | |
150 | }, |
|
76 | }, | |
151 | { |
|
77 | { | |
152 | "cell_type": "markdown", |
|
78 | "cell_type": "markdown", | |
153 | "metadata": {}, |
|
79 | "metadata": {}, | |
154 | "source": [ |
|
80 | "source": [ | |
155 | "If a `description` is not set for the widget, the label is not displayed (as seen below)." |
|
81 | "If a `description` is not set for the widget, the label is not displayed (as seen below)." | |
156 | ] |
|
82 | ] | |
157 | }, |
|
83 | }, | |
158 | { |
|
84 | { | |
159 | "cell_type": "code", |
|
85 | "cell_type": "code", | |
160 | "collapsed": false, |
|
86 | "collapsed": false, | |
161 | "input": [ |
|
87 | "input": [ | |
162 | "display(widgets.StringWidget(description=\"a:\"))\n", |
|
88 | "display(widgets.StringWidget(description=\"a:\"))\n", | |
163 | "display(widgets.StringWidget(description=\"aa:\"))\n", |
|
89 | "display(widgets.StringWidget(description=\"aa:\"))\n", | |
164 | "display(widgets.StringWidget(description=\"aaa:\"))\n", |
|
90 | "display(widgets.StringWidget(description=\"aaa:\"))\n", | |
165 | "display(widgets.StringWidget())" |
|
91 | "display(widgets.StringWidget())" | |
166 | ], |
|
92 | ], | |
167 | "language": "python", |
|
93 | "language": "python", | |
168 | "metadata": {}, |
|
94 | "metadata": {}, | |
169 | "outputs": [], |
|
95 | "outputs": [], | |
170 | "prompt_number": 4 |
|
96 | "prompt_number": 4 | |
171 | }, |
|
97 | }, | |
172 | { |
|
98 | { | |
173 | "cell_type": "heading", |
|
99 | "cell_type": "heading", | |
174 | "level": 1, |
|
100 | "level": 1, | |
175 | "metadata": {}, |
|
101 | "metadata": {}, | |
176 | "source": [ |
|
102 | "source": [ | |
177 | "Custom Alignment" |
|
103 | "Custom Alignment" | |
178 | ] |
|
104 | ] | |
179 | }, |
|
105 | }, | |
180 | { |
|
106 | { | |
181 | "cell_type": "markdown", |
|
107 | "cell_type": "markdown", | |
182 | "metadata": {}, |
|
108 | "metadata": {}, | |
183 | "source": [ |
|
109 | "source": [ | |
184 | "`ContainerWidget`s allow for custom alignment of widgets. The `hbox` and `vbox` methods (parameterless) cause the `ContainerWidget` to both horizontally and vertically align its children. The following example compares `vbox` to `hbox`." |
|
110 | "`ContainerWidget`s allow for custom alignment of widgets. The `hbox` and `vbox` methods (parameterless) cause the `ContainerWidget` to both horizontally and vertically align its children. The following example compares `vbox` to `hbox`." | |
185 | ] |
|
111 | ] | |
186 | }, |
|
112 | }, | |
187 | { |
|
113 | { | |
188 | "cell_type": "code", |
|
114 | "cell_type": "code", | |
189 | "collapsed": false, |
|
115 | "collapsed": false, | |
190 | "input": [ |
|
116 | "input": [ | |
191 | "child_style = {\n", |
|
117 | "child_style = {\n", | |
192 | " 'background': '#77CC77',\n", |
|
118 | " 'background': '#77CC77',\n", | |
193 | " 'padding': '25px',\n", |
|
119 | " 'padding': '25px',\n", | |
194 | " 'margin': '5px',\n", |
|
120 | " 'margin': '5px',\n", | |
195 | " 'font-size': 'xx-large',\n", |
|
121 | " 'font-size': 'xx-large',\n", | |
196 | " 'color': 'white',\n", |
|
122 | " 'color': 'white',\n", | |
197 | "}\n", |
|
123 | "}\n", | |
198 | "\n", |
|
124 | "\n", | |
199 | "def make_container(title):\n", |
|
125 | "def make_container(title):\n", | |
200 | " display(widgets.StringWidget(default_view_name='LabelView', value='<h2><br>' + title + '</h2>'))\n", |
|
126 | " display(widgets.StringWidget(default_view_name='LabelView', value='<h2><br>' + title + '</h2>'))\n", | |
201 | " container = widgets.ContainerWidget()\n", |
|
127 | " container = widgets.ContainerWidget()\n", | |
202 | " container.set_css('background', '#999999')\n", |
|
128 | " container.set_css('background', '#999999')\n", | |
203 | " display(container)\n", |
|
129 | " display(container)\n", | |
204 | " return container\n", |
|
130 | " return container\n", | |
205 | "\n", |
|
131 | "\n", | |
206 | "def fill_container(container):\n", |
|
132 | "def fill_container(container):\n", | |
207 | " components = []\n", |
|
133 | " components = []\n", | |
208 | " for i in range(3):\n", |
|
134 | " for i in range(3):\n", | |
209 | " components.append(widgets.StringWidget(parent=container, default_view_name='LabelView', value=\"ABC\"[i]))\n", |
|
135 | " components.append(widgets.StringWidget(parent=container, default_view_name='LabelView', value=\"ABC\"[i]))\n", | |
210 | " components[i].set_css(child_style)\n", |
|
136 | " components[i].set_css(child_style)\n", | |
211 | " display(components[i])\n", |
|
137 | " display(components[i])\n", | |
212 | " \n", |
|
138 | " \n", | |
213 | "container = make_container('VBox')\n", |
|
139 | "container = make_container('VBox')\n", | |
214 | "container.vbox()\n", |
|
140 | "container.vbox()\n", | |
215 | "fill_container(container)\n", |
|
141 | "fill_container(container)\n", | |
216 | "\n", |
|
142 | "\n", | |
217 | "container = make_container('HBox')\n", |
|
143 | "container = make_container('HBox')\n", | |
218 | "container.hbox()\n", |
|
144 | "container.hbox()\n", | |
219 | "fill_container(container)\n" |
|
145 | "fill_container(container)\n" | |
220 | ], |
|
146 | ], | |
221 | "language": "python", |
|
147 | "language": "python", | |
222 | "metadata": {}, |
|
148 | "metadata": {}, | |
223 | "outputs": [], |
|
149 | "outputs": [], | |
224 | "prompt_number": 5 |
|
150 | "prompt_number": 5 | |
225 | }, |
|
151 | }, | |
226 | { |
|
152 | { | |
227 | "cell_type": "markdown", |
|
153 | "cell_type": "markdown", | |
228 | "metadata": {}, |
|
154 | "metadata": {}, | |
229 | "source": [ |
|
155 | "source": [ | |
230 | "The `ContainerWidget` `pack_start`, `pack_center`, and `pack_end` methods (parameterless) adjust the alignment of the widgets on the axis that they are being rendered on. Below is an example of the different alignments." |
|
156 | "The `ContainerWidget` `pack_start`, `pack_center`, and `pack_end` methods (parameterless) adjust the alignment of the widgets on the axis that they are being rendered on. Below is an example of the different alignments." | |
231 | ] |
|
157 | ] | |
232 | }, |
|
158 | }, | |
233 | { |
|
159 | { | |
234 | "cell_type": "code", |
|
160 | "cell_type": "code", | |
235 | "collapsed": false, |
|
161 | "collapsed": false, | |
236 | "input": [ |
|
162 | "input": [ | |
237 | "container = make_container('HBox Pack Start')\n", |
|
163 | "container = make_container('HBox Pack Start')\n", | |
238 | "container.hbox()\n", |
|
164 | "container.hbox()\n", | |
239 | "container.pack_start()\n", |
|
165 | "container.pack_start()\n", | |
240 | "fill_container(container)\n", |
|
166 | "fill_container(container)\n", | |
241 | " \n", |
|
167 | " \n", | |
242 | "container = make_container('HBox Pack Center')\n", |
|
168 | "container = make_container('HBox Pack Center')\n", | |
243 | "container.hbox()\n", |
|
169 | "container.hbox()\n", | |
244 | "container.pack_center()\n", |
|
170 | "container.pack_center()\n", | |
245 | "fill_container(container)\n", |
|
171 | "fill_container(container)\n", | |
246 | " \n", |
|
172 | " \n", | |
247 | "container = make_container('HBox Pack End')\n", |
|
173 | "container = make_container('HBox Pack End')\n", | |
248 | "container.hbox()\n", |
|
174 | "container.hbox()\n", | |
249 | "container.pack_end()\n", |
|
175 | "container.pack_end()\n", | |
250 | "fill_container(container)" |
|
176 | "fill_container(container)" | |
251 | ], |
|
177 | ], | |
252 | "language": "python", |
|
178 | "language": "python", | |
253 | "metadata": {}, |
|
179 | "metadata": {}, | |
254 | "outputs": [], |
|
180 | "outputs": [], | |
255 | "prompt_number": 6 |
|
181 | "prompt_number": 6 | |
256 | }, |
|
182 | }, | |
257 | { |
|
183 | { | |
258 | "cell_type": "markdown", |
|
184 | "cell_type": "markdown", | |
259 | "metadata": {}, |
|
185 | "metadata": {}, | |
260 | "source": [ |
|
186 | "source": [ | |
261 | "The `ContainerWidget` `flex0`, `flex1`, and `flex2` methods (parameterless) modify the containers flexibility. Changing a container flexibility affects how and if the container will occupy the remaining space. Setting `flex0` has the same result as setting no flex. Below is an example of different flex configurations. The number on the boxes correspond to the applied flex." |
|
187 | "The `ContainerWidget` `flex0`, `flex1`, and `flex2` methods (parameterless) modify the containers flexibility. Changing a container flexibility affects how and if the container will occupy the remaining space. Setting `flex0` has the same result as setting no flex. Below is an example of different flex configurations. The number on the boxes correspond to the applied flex." | |
262 | ] |
|
188 | ] | |
263 | }, |
|
189 | }, | |
264 | { |
|
190 | { | |
265 | "cell_type": "code", |
|
191 | "cell_type": "code", | |
266 | "collapsed": false, |
|
192 | "collapsed": false, | |
267 | "input": [ |
|
193 | "input": [ | |
268 | "def fill_container(container, flexes):\n", |
|
194 | "def fill_container(container, flexes):\n", | |
269 | " components = []\n", |
|
195 | " components = []\n", | |
270 | " for i in range(len(flexes)):\n", |
|
196 | " for i in range(len(flexes)):\n", | |
271 | " components.append(widgets.ContainerWidget(parent=container))\n", |
|
197 | " components.append(widgets.ContainerWidget(parent=container))\n", | |
272 | " components[i].set_css(child_style)\n", |
|
198 | " components[i].set_css(child_style)\n", | |
273 | " \n", |
|
199 | " \n", | |
274 | " label = widgets.StringWidget(parent=components[i], default_view_name='LabelView', value=str(flexes[i]))\n", |
|
200 | " label = widgets.StringWidget(parent=components[i], default_view_name='LabelView', value=str(flexes[i]))\n", | |
275 | " \n", |
|
201 | " \n", | |
276 | " if flexes[i] == 0:\n", |
|
202 | " if flexes[i] == 0:\n", | |
277 | " components[i].flex0()\n", |
|
203 | " components[i].flex0()\n", | |
278 | " elif flexes[i] == 1:\n", |
|
204 | " elif flexes[i] == 1:\n", | |
279 | " components[i].flex1()\n", |
|
205 | " components[i].flex1()\n", | |
280 | " elif flexes[i] == 2:\n", |
|
206 | " elif flexes[i] == 2:\n", | |
281 | " components[i].flex2()\n", |
|
207 | " components[i].flex2()\n", | |
282 | " display(components[i])\n", |
|
208 | " display(components[i])\n", | |
283 | " \n", |
|
209 | " \n", | |
284 | "container = make_container('Different Flex Configurations')\n", |
|
210 | "container = make_container('Different Flex Configurations')\n", | |
285 | "container.hbox()\n", |
|
211 | "container.hbox()\n", | |
286 | "fill_container(container, [0, 0, 0])\n", |
|
212 | "fill_container(container, [0, 0, 0])\n", | |
287 | " \n", |
|
213 | " \n", | |
288 | "container = make_container('')\n", |
|
214 | "container = make_container('')\n", | |
289 | "container.hbox()\n", |
|
215 | "container.hbox()\n", | |
290 | "fill_container(container, [0, 0, 1])\n", |
|
216 | "fill_container(container, [0, 0, 1])\n", | |
291 | " \n", |
|
217 | " \n", | |
292 | "container = make_container('')\n", |
|
218 | "container = make_container('')\n", | |
293 | "container.hbox()\n", |
|
219 | "container.hbox()\n", | |
294 | "fill_container(container, [0, 1, 1])\n", |
|
220 | "fill_container(container, [0, 1, 1])\n", | |
295 | " \n", |
|
221 | " \n", | |
296 | "container = make_container('')\n", |
|
222 | "container = make_container('')\n", | |
297 | "container.hbox()\n", |
|
223 | "container.hbox()\n", | |
298 | "fill_container(container, [0, 2, 2])\n", |
|
224 | "fill_container(container, [0, 2, 2])\n", | |
299 | " \n", |
|
225 | " \n", | |
300 | "container = make_container('')\n", |
|
226 | "container = make_container('')\n", | |
301 | "container.hbox()\n", |
|
227 | "container.hbox()\n", | |
302 | "fill_container(container, [0, 1, 2])\n", |
|
228 | "fill_container(container, [0, 1, 2])\n", | |
303 | " \n", |
|
229 | " \n", | |
304 | "container = make_container('')\n", |
|
230 | "container = make_container('')\n", | |
305 | "container.hbox()\n", |
|
231 | "container.hbox()\n", | |
306 | "fill_container(container, [1, 1, 2])" |
|
232 | "fill_container(container, [1, 1, 2])" | |
307 | ], |
|
233 | ], | |
308 | "language": "python", |
|
234 | "language": "python", | |
309 | "metadata": {}, |
|
235 | "metadata": {}, | |
310 | "outputs": [], |
|
236 | "outputs": [], | |
311 | "prompt_number": 7 |
|
237 | "prompt_number": 7 | |
312 | }, |
|
238 | }, | |
313 | { |
|
239 | { | |
314 | "cell_type": "markdown", |
|
240 | "cell_type": "markdown", | |
315 | "metadata": {}, |
|
241 | "metadata": {}, | |
316 | "source": [ |
|
242 | "source": [ | |
317 | "The `ContainerWidget` `align_start`, `align_center`, and `align_end` methods (parameterless) adjust the alignment of the widgets on the axis perpindicular to the one that they are being rendered on. Below is an example of the different alignments." |
|
243 | "The `ContainerWidget` `align_start`, `align_center`, and `align_end` methods (parameterless) adjust the alignment of the widgets on the axis perpindicular to the one that they are being rendered on. Below is an example of the different alignments." | |
318 | ] |
|
244 | ] | |
319 | }, |
|
245 | }, | |
320 | { |
|
246 | { | |
321 | "cell_type": "code", |
|
247 | "cell_type": "code", | |
322 | "collapsed": false, |
|
248 | "collapsed": false, | |
323 | "input": [ |
|
249 | "input": [ | |
324 | "def fill_container(container):\n", |
|
250 | "def fill_container(container):\n", | |
325 | " components = []\n", |
|
251 | " components = []\n", | |
326 | " for i in range(3):\n", |
|
252 | " for i in range(3):\n", | |
327 | " components.append(widgets.StringWidget(parent=container, default_view_name='LabelView', value=\"ABC\"[i]))\n", |
|
253 | " components.append(widgets.StringWidget(parent=container, default_view_name='LabelView', value=\"ABC\"[i]))\n", | |
328 | " components[i].set_css(child_style)\n", |
|
254 | " components[i].set_css(child_style)\n", | |
329 | " components[i].set_css('height', str((i+1) * 50) + 'px')\n", |
|
255 | " components[i].set_css('height', str((i+1) * 50) + 'px')\n", | |
330 | " display(components[i])\n", |
|
256 | " display(components[i])\n", | |
331 | "\n", |
|
257 | "\n", | |
332 | "container = make_container('HBox Align Start')\n", |
|
258 | "container = make_container('HBox Align Start')\n", | |
333 | "container.hbox()\n", |
|
259 | "container.hbox()\n", | |
334 | "container.align_start()\n", |
|
260 | "container.align_start()\n", | |
335 | "fill_container(container)\n", |
|
261 | "fill_container(container)\n", | |
336 | " \n", |
|
262 | " \n", | |
337 | "container = make_container('HBox Align Center')\n", |
|
263 | "container = make_container('HBox Align Center')\n", | |
338 | "container.hbox()\n", |
|
264 | "container.hbox()\n", | |
339 | "container.align_center()\n", |
|
265 | "container.align_center()\n", | |
340 | "fill_container(container)\n", |
|
266 | "fill_container(container)\n", | |
341 | " \n", |
|
267 | " \n", | |
342 | "container = make_container('HBox Align End')\n", |
|
268 | "container = make_container('HBox Align End')\n", | |
343 | "container.hbox()\n", |
|
269 | "container.hbox()\n", | |
344 | "container.align_end()\n", |
|
270 | "container.align_end()\n", | |
345 | "fill_container(container)" |
|
271 | "fill_container(container)" | |
346 | ], |
|
272 | ], | |
347 | "language": "python", |
|
273 | "language": "python", | |
348 | "metadata": {}, |
|
274 | "metadata": {}, | |
349 | "outputs": [], |
|
275 | "outputs": [], | |
350 | "prompt_number": 8 |
|
276 | "prompt_number": 8 | |
351 | }, |
|
277 | }, | |
352 | { |
|
278 | { | |
353 | "cell_type": "markdown", |
|
279 | "cell_type": "markdown", | |
354 | "metadata": {}, |
|
280 | "metadata": {}, | |
355 | "source": [ |
|
281 | "source": [ | |
356 | "By default the widget area is a `vbox`; however, there are many uses for a `hbox`. The example below uses a `hbox` to display a set of vertical sliders, like an equalizer." |
|
282 | "By default the widget area is a `vbox`; however, there are many uses for a `hbox`. The example below uses a `hbox` to display a set of vertical sliders, like an equalizer." | |
357 | ] |
|
283 | ] | |
358 | }, |
|
284 | }, | |
359 | { |
|
285 | { | |
360 | "cell_type": "code", |
|
286 | "cell_type": "code", | |
361 | "collapsed": false, |
|
287 | "collapsed": false, | |
362 | "input": [ |
|
288 | "input": [ | |
363 | "container = widgets.ContainerWidget()\n", |
|
289 | "container = widgets.ContainerWidget()\n", | |
364 | "container.hbox()\n", |
|
290 | "container.hbox()\n", | |
365 | "for i in range(15):\n", |
|
291 | "for i in range(15):\n", | |
366 | " widgets.FloatRangeWidget(orientation='vertical', parent=container, description=str(i+1), value=50.0)\n", |
|
292 | " widgets.FloatRangeWidget(orientation='vertical', parent=container, description=str(i+1), value=50.0)\n", | |
367 | "display(container)" |
|
293 | "display(container)" | |
368 | ], |
|
294 | ], | |
369 | "language": "python", |
|
295 | "language": "python", | |
370 | "metadata": {}, |
|
296 | "metadata": {}, | |
371 | "outputs": [], |
|
297 | "outputs": [], | |
372 | "prompt_number": 9 |
|
298 | "prompt_number": 9 | |
373 | } |
|
299 | } | |
374 | ], |
|
300 | ], | |
375 | "metadata": {} |
|
301 | "metadata": {} | |
376 | } |
|
302 | } | |
377 | ] |
|
303 | ] | |
378 | } No newline at end of file |
|
304 | } |
@@ -1,1278 +1,1203 b'' | |||||
1 | { |
|
1 | { | |
2 | "metadata": { |
|
2 | "metadata": { | |
3 | "cell_tags": [ |
|
3 | "cell_tags": [ | |
4 | [ |
|
4 | [ | |
5 | "<None>", |
|
5 | "<None>", | |
6 | null |
|
6 | null | |
7 | ] |
|
7 | ] | |
8 | ], |
|
8 | ], | |
9 | "name": "" |
|
9 | "name": "" | |
10 | }, |
|
10 | }, | |
11 | "nbformat": 3, |
|
11 | "nbformat": 3, | |
12 | "nbformat_minor": 0, |
|
12 | "nbformat_minor": 0, | |
13 | "worksheets": [ |
|
13 | "worksheets": [ | |
14 | { |
|
14 | { | |
15 | "cells": [ |
|
15 | "cells": [ | |
16 | { |
|
16 | { | |
17 | "cell_type": "markdown", |
|
17 | "cell_type": "markdown", | |
18 | "metadata": {}, |
|
18 | "metadata": {}, | |
19 | "source": [ |
|
19 | "source": [ | |
20 | "Before reading, the author recommends the reader to review\n", |
|
20 | "Before reading, the author recommends the reader to review\n", | |
21 | "\n", |
|
21 | "\n", | |
22 | "- [MVC prgramming](http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller)\n", |
|
22 | "- [MVC prgramming](http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller)\n", | |
23 | "- [Backbone.js](https://www.codeschool.com/courses/anatomy-of-backbonejs)\n", |
|
23 | "- [Backbone.js](https://www.codeschool.com/courses/anatomy-of-backbonejs)\n", | |
24 | "- [The widget IPEP](https://github.com/ipython/ipython/wiki/IPEP-23%3A-Backbone.js-Widgets)\n", |
|
24 | "- [The widget IPEP](https://github.com/ipython/ipython/wiki/IPEP-23%3A-Backbone.js-Widgets)\n", | |
25 | "- [The original widget PR discussion](https://github.com/ipython/ipython/pull/4374)" |
|
25 | "- [The original widget PR discussion](https://github.com/ipython/ipython/pull/4374)" | |
26 | ] |
|
26 | ] | |
27 | }, |
|
27 | }, | |
28 | { |
|
28 | { | |
29 | "cell_type": "code", |
|
29 | "cell_type": "code", | |
30 | "collapsed": false, |
|
30 | "collapsed": false, | |
31 | "input": [ |
|
31 | "input": [ | |
32 | "from IPython.html import widgets # Widget definitions\n", |
|
32 | "from IPython.html import widgets # Widget definitions\n", | |
33 |
"from IPython.display import display # Used to display widgets in the notebook |
|
33 | "from IPython.display import display # Used to display widgets in the notebook" | |
34 | "\n", |
|
|||
35 | "# Enable widgets in this notebook\n", |
|
|||
36 | "widgets.init_widget_js()" |
|
|||
37 | ], |
|
34 | ], | |
38 | "language": "python", |
|
35 | "language": "python", | |
39 | "metadata": {}, |
|
36 | "metadata": {}, | |
40 | "outputs": [ |
|
37 | "outputs": [], | |
41 | { |
|
|||
42 | "javascript": [ |
|
|||
43 | "$.getScript($(\"body\").data(\"baseProjectUrl\") + \"static/notebook/js/widgets/button.js\");" |
|
|||
44 | ], |
|
|||
45 | "metadata": {}, |
|
|||
46 | "output_type": "display_data" |
|
|||
47 | }, |
|
|||
48 | { |
|
|||
49 | "javascript": [ |
|
|||
50 | "$.getScript($(\"body\").data(\"baseProjectUrl\") + \"static/notebook/js/widgets/int_range.js\");" |
|
|||
51 | ], |
|
|||
52 | "metadata": {}, |
|
|||
53 | "output_type": "display_data" |
|
|||
54 | }, |
|
|||
55 | { |
|
|||
56 | "javascript": [ |
|
|||
57 | "$.getScript($(\"body\").data(\"baseProjectUrl\") + \"static/notebook/js/widgets/string.js\");" |
|
|||
58 | ], |
|
|||
59 | "metadata": {}, |
|
|||
60 | "output_type": "display_data" |
|
|||
61 | }, |
|
|||
62 | { |
|
|||
63 | "javascript": [ |
|
|||
64 | "$.getScript($(\"body\").data(\"baseProjectUrl\") + \"static/notebook/js/widgets/multicontainer.js\");" |
|
|||
65 | ], |
|
|||
66 | "metadata": {}, |
|
|||
67 | "output_type": "display_data" |
|
|||
68 | }, |
|
|||
69 | { |
|
|||
70 | "javascript": [ |
|
|||
71 | "$.getScript($(\"body\").data(\"baseProjectUrl\") + \"static/notebook/js/widgets/bool.js\");" |
|
|||
72 | ], |
|
|||
73 | "metadata": {}, |
|
|||
74 | "output_type": "display_data" |
|
|||
75 | }, |
|
|||
76 | { |
|
|||
77 | "javascript": [ |
|
|||
78 | "$.getScript($(\"body\").data(\"baseProjectUrl\") + \"static/notebook/js/widgets/int.js\");" |
|
|||
79 | ], |
|
|||
80 | "metadata": {}, |
|
|||
81 | "output_type": "display_data" |
|
|||
82 | }, |
|
|||
83 | { |
|
|||
84 | "javascript": [ |
|
|||
85 | "$.getScript($(\"body\").data(\"baseProjectUrl\") + \"static/notebook/js/widgets/selection.js\");" |
|
|||
86 | ], |
|
|||
87 | "metadata": {}, |
|
|||
88 | "output_type": "display_data" |
|
|||
89 | }, |
|
|||
90 | { |
|
|||
91 | "javascript": [ |
|
|||
92 | "$.getScript($(\"body\").data(\"baseProjectUrl\") + \"static/notebook/js/widgets/float.js\");" |
|
|||
93 | ], |
|
|||
94 | "metadata": {}, |
|
|||
95 | "output_type": "display_data" |
|
|||
96 | }, |
|
|||
97 | { |
|
|||
98 | "javascript": [ |
|
|||
99 | "$.getScript($(\"body\").data(\"baseProjectUrl\") + \"static/notebook/js/widgets/float_range.js\");" |
|
|||
100 | ], |
|
|||
101 | "metadata": {}, |
|
|||
102 | "output_type": "display_data" |
|
|||
103 | }, |
|
|||
104 | { |
|
|||
105 | "javascript": [ |
|
|||
106 | "$.getScript($(\"body\").data(\"baseProjectUrl\") + \"static/notebook/js/widgets/container.js\");" |
|
|||
107 | ], |
|
|||
108 | "metadata": {}, |
|
|||
109 | "output_type": "display_data" |
|
|||
110 | } |
|
|||
111 | ], |
|
|||
112 | "prompt_number": 1 |
|
38 | "prompt_number": 1 | |
113 | }, |
|
39 | }, | |
114 | { |
|
40 | { | |
115 | "cell_type": "heading", |
|
41 | "cell_type": "heading", | |
116 | "level": 1, |
|
42 | "level": 1, | |
117 | "metadata": {}, |
|
43 | "metadata": {}, | |
118 | "source": [ |
|
44 | "source": [ | |
119 | "Abstract" |
|
45 | "Abstract" | |
120 | ] |
|
46 | ] | |
121 | }, |
|
47 | }, | |
122 | { |
|
48 | { | |
123 | "cell_type": "markdown", |
|
49 | "cell_type": "markdown", | |
124 | "metadata": {}, |
|
50 | "metadata": {}, | |
125 | "source": [ |
|
51 | "source": [ | |
126 | "This notebook implements a custom date picker widget. The purpose of this notebook is to demonstrate the widget creation process. To create a custom widget, custom Python and JavaScript is required." |
|
52 | "This notebook implements a custom date picker widget. The purpose of this notebook is to demonstrate the widget creation process. To create a custom widget, custom Python and JavaScript is required." | |
127 | ] |
|
53 | ] | |
128 | }, |
|
54 | }, | |
129 | { |
|
55 | { | |
130 | "cell_type": "heading", |
|
56 | "cell_type": "heading", | |
131 | "level": 1, |
|
57 | "level": 1, | |
132 | "metadata": {}, |
|
58 | "metadata": {}, | |
133 | "source": [ |
|
59 | "source": [ | |
134 | "Section 1 - Basics" |
|
60 | "Section 1 - Basics" | |
135 | ] |
|
61 | ] | |
136 | }, |
|
62 | }, | |
137 | { |
|
63 | { | |
138 | "cell_type": "heading", |
|
64 | "cell_type": "heading", | |
139 | "level": 2, |
|
65 | "level": 2, | |
140 | "metadata": {}, |
|
66 | "metadata": {}, | |
141 | "source": [ |
|
67 | "source": [ | |
142 | "Python" |
|
68 | "Python" | |
143 | ] |
|
69 | ] | |
144 | }, |
|
70 | }, | |
145 | { |
|
71 | { | |
146 | "cell_type": "markdown", |
|
72 | "cell_type": "markdown", | |
147 | "metadata": {}, |
|
73 | "metadata": {}, | |
148 | "source": [ |
|
74 | "source": [ | |
149 | "When starting a project like this, it is often easiest to make an overly simplified base to verify that the underlying framework is working as expected. To start we will create an empty widget and make sure that it can be rendered. The first step is to create the widget in Python." |
|
75 | "When starting a project like this, it is often easiest to make an overly simplified base to verify that the underlying framework is working as expected. To start we will create an empty widget and make sure that it can be rendered. The first step is to create the widget in Python." | |
150 | ] |
|
76 | ] | |
151 | }, |
|
77 | }, | |
152 | { |
|
78 | { | |
153 | "cell_type": "code", |
|
79 | "cell_type": "code", | |
154 | "collapsed": false, |
|
80 | "collapsed": false, | |
155 | "input": [ |
|
81 | "input": [ | |
156 | "# Import the base Widget class and the traitlets Unicode class.\n", |
|
82 | "# Import the base Widget class and the traitlets Unicode class.\n", | |
157 | "from IPython.html.widgets import Widget\n", |
|
83 | "from IPython.html.widgets import Widget\n", | |
158 | "from IPython.utils.traitlets import Unicode\n", |
|
84 | "from IPython.utils.traitlets import Unicode\n", | |
159 | "\n", |
|
85 | "\n", | |
160 | "# Define our DateWidget and its target model and default view.\n", |
|
86 | "# Define our DateWidget and its target model and default view.\n", | |
161 | "class DateWidget(Widget):\n", |
|
87 | "class DateWidget(Widget):\n", | |
162 | " target_name = Unicode('DateWidgetModel')\n", |
|
88 | " target_name = Unicode('DateWidgetModel')\n", | |
163 | " default_view_name = Unicode('DatePickerView')" |
|
89 | " default_view_name = Unicode('DatePickerView')" | |
164 | ], |
|
90 | ], | |
165 | "language": "python", |
|
91 | "language": "python", | |
166 | "metadata": {}, |
|
92 | "metadata": {}, | |
167 | "outputs": [], |
|
93 | "outputs": [], | |
168 | "prompt_number": 2 |
|
94 | "prompt_number": 2 | |
169 | }, |
|
95 | }, | |
170 | { |
|
96 | { | |
171 | "cell_type": "markdown", |
|
97 | "cell_type": "markdown", | |
172 | "metadata": {}, |
|
98 | "metadata": {}, | |
173 | "source": [ |
|
99 | "source": [ | |
174 | "- **target_name** is a special `Widget` property that tells the widget framework which Backbone model in the front-end corresponds to this widget.\n", |
|
100 | "- **target_name** is a special `Widget` property that tells the widget framework which Backbone model in the front-end corresponds to this widget.\n", | |
175 | "- **default_view_name** is the default Backbone view to display when the user calls `display` to display an instance of this widget.\n" |
|
101 | "- **default_view_name** is the default Backbone view to display when the user calls `display` to display an instance of this widget.\n" | |
176 | ] |
|
102 | ] | |
177 | }, |
|
103 | }, | |
178 | { |
|
104 | { | |
179 | "cell_type": "heading", |
|
105 | "cell_type": "heading", | |
180 | "level": 2, |
|
106 | "level": 2, | |
181 | "metadata": {}, |
|
107 | "metadata": {}, | |
182 | "source": [ |
|
108 | "source": [ | |
183 | "JavaScript" |
|
109 | "JavaScript" | |
184 | ] |
|
110 | ] | |
185 | }, |
|
111 | }, | |
186 | { |
|
112 | { | |
187 | "cell_type": "markdown", |
|
113 | "cell_type": "markdown", | |
188 | "metadata": {}, |
|
114 | "metadata": {}, | |
189 | "source": [ |
|
115 | "source": [ | |
190 | "In the IPython notebook [require.js](http://requirejs.org/) is used to load JavaScript dependencies. All IPython widget code depends on `notebook/js/widget.js`. In it the base widget model, base view, and widget manager are defined. We need to use require.js to include this file:" |
|
116 | "In the IPython notebook [require.js](http://requirejs.org/) is used to load JavaScript dependencies. All IPython widget code depends on `notebook/js/widget.js`. In it the base widget model, base view, and widget manager are defined. We need to use require.js to include this file:" | |
191 | ] |
|
117 | ] | |
192 | }, |
|
118 | }, | |
193 | { |
|
119 | { | |
194 | "cell_type": "code", |
|
120 | "cell_type": "code", | |
195 | "collapsed": false, |
|
121 | "collapsed": false, | |
196 | "input": [ |
|
122 | "input": [ | |
197 | "%%javascript\n", |
|
123 | "%%javascript\n", | |
198 | "\n", |
|
124 | "\n", | |
199 | "require([\"notebook/js/widget\"], function(){\n", |
|
125 | "require([\"notebook/js/widget\"], function(){\n", | |
200 | "\n", |
|
126 | "\n", | |
201 | "});" |
|
127 | "});" | |
202 | ], |
|
128 | ], | |
203 | "language": "python", |
|
129 | "language": "python", | |
204 | "metadata": {}, |
|
130 | "metadata": {}, | |
205 | "outputs": [ |
|
131 | "outputs": [ | |
206 | { |
|
132 | { | |
207 | "javascript": [ |
|
133 | "javascript": [ | |
208 | "\n", |
|
134 | "\n", | |
209 | "require([\"notebook/js/widget\"], function(){\n", |
|
135 | "require([\"notebook/js/widget\"], function(){\n", | |
210 | "\n", |
|
136 | "\n", | |
211 | "});" |
|
137 | "});" | |
212 | ], |
|
138 | ], | |
213 | "metadata": {}, |
|
139 | "metadata": {}, | |
214 | "output_type": "display_data", |
|
140 | "output_type": "display_data", | |
215 | "text": [ |
|
141 | "text": [ | |
216 |
"<IPython.core.display.Javascript at 0x |
|
142 | "<IPython.core.display.Javascript at 0x21f8f10>" | |
217 | ] |
|
143 | ] | |
218 | } |
|
144 | } | |
219 | ], |
|
145 | ], | |
220 | "prompt_number": 3 |
|
146 | "prompt_number": 3 | |
221 | }, |
|
147 | }, | |
222 | { |
|
148 | { | |
223 | "cell_type": "markdown", |
|
149 | "cell_type": "markdown", | |
224 | "metadata": {}, |
|
150 | "metadata": {}, | |
225 | "source": [ |
|
151 | "source": [ | |
226 | "The next step is to add a definition for the widget's model. It's important to extend the `IPython.WidgetModel` which extends the Backbone.js base model instead of trying to extend the Backbone.js base model directly. After defining the model, it needs to be registed with the widget manager using the `target_name` used in the Python code." |
|
152 | "The next step is to add a definition for the widget's model. It's important to extend the `IPython.WidgetModel` which extends the Backbone.js base model instead of trying to extend the Backbone.js base model directly. After defining the model, it needs to be registed with the widget manager using the `target_name` used in the Python code." | |
227 | ] |
|
153 | ] | |
228 | }, |
|
154 | }, | |
229 | { |
|
155 | { | |
230 | "cell_type": "code", |
|
156 | "cell_type": "code", | |
231 | "collapsed": false, |
|
157 | "collapsed": false, | |
232 | "input": [ |
|
158 | "input": [ | |
233 | "%%javascript\n", |
|
159 | "%%javascript\n", | |
234 | "\n", |
|
160 | "\n", | |
235 | "require([\"notebook/js/widget\"], function(){\n", |
|
161 | "require([\"notebook/js/widget\"], function(){\n", | |
236 | " \n", |
|
162 | " \n", | |
237 | " // Define the DateModel and register it with the widget manager.\n", |
|
163 | " // Define the DateModel and register it with the widget manager.\n", | |
238 | " var DateModel = IPython.WidgetModel.extend({});\n", |
|
164 | " var DateModel = IPython.WidgetModel.extend({});\n", | |
239 |
" IPython. |
|
165 | " IPython.widget_manager.register_widget_model('DateWidgetModel', DateModel);\n", | |
240 | "});" |
|
166 | "});" | |
241 | ], |
|
167 | ], | |
242 | "language": "python", |
|
168 | "language": "python", | |
243 | "metadata": {}, |
|
169 | "metadata": {}, | |
244 | "outputs": [ |
|
170 | "outputs": [ | |
245 | { |
|
171 | { | |
246 | "javascript": [ |
|
172 | "javascript": [ | |
247 | "\n", |
|
173 | "\n", | |
248 | "require([\"notebook/js/widget\"], function(){\n", |
|
174 | "require([\"notebook/js/widget\"], function(){\n", | |
249 | " \n", |
|
175 | " \n", | |
250 | " // Define the DateModel and register it with the widget manager.\n", |
|
176 | " // Define the DateModel and register it with the widget manager.\n", | |
251 | " var DateModel = IPython.WidgetModel.extend({});\n", |
|
177 | " var DateModel = IPython.WidgetModel.extend({});\n", | |
252 |
" IPython. |
|
178 | " IPython.widget_manager.register_widget_model('DateWidgetModel', DateModel);\n", | |
253 | "});" |
|
179 | "});" | |
254 | ], |
|
180 | ], | |
255 | "metadata": {}, |
|
181 | "metadata": {}, | |
256 | "output_type": "display_data", |
|
182 | "output_type": "display_data", | |
257 | "text": [ |
|
183 | "text": [ | |
258 |
"<IPython.core.display.Javascript at 0x |
|
184 | "<IPython.core.display.Javascript at 0x21f8ed0>" | |
259 | ] |
|
185 | ] | |
260 | } |
|
186 | } | |
261 | ], |
|
187 | ], | |
262 | "prompt_number": 4 |
|
188 | "prompt_number": 4 | |
263 | }, |
|
189 | }, | |
264 | { |
|
190 | { | |
265 | "cell_type": "markdown", |
|
191 | "cell_type": "markdown", | |
266 | "metadata": {}, |
|
192 | "metadata": {}, | |
267 | "source": [ |
|
193 | "source": [ | |
268 | "Now that the model is defined, we need to define a view that can be used to represent the model. To do this, the `IPython.WidgetView` is extended. A render function must be defined. The render function is used to render a widget view instance to the DOM. For now the render function renders a div that contains the text *Hello World!* Lastly, the view needs to be registered with the widget manager like the model was.\n", |
|
194 | "Now that the model is defined, we need to define a view that can be used to represent the model. To do this, the `IPython.WidgetView` is extended. A render function must be defined. The render function is used to render a widget view instance to the DOM. For now the render function renders a div that contains the text *Hello World!* Lastly, the view needs to be registered with the widget manager like the model was.\n", | |
269 | "\n", |
|
195 | "\n", | |
270 | "**Final JavaScript code below:**" |
|
196 | "**Final JavaScript code below:**" | |
271 | ] |
|
197 | ] | |
272 | }, |
|
198 | }, | |
273 | { |
|
199 | { | |
274 | "cell_type": "code", |
|
200 | "cell_type": "code", | |
275 | "collapsed": false, |
|
201 | "collapsed": false, | |
276 | "input": [ |
|
202 | "input": [ | |
277 | "%%javascript\n", |
|
203 | "%%javascript\n", | |
278 | "\n", |
|
204 | "\n", | |
279 | "require([\"notebook/js/widget\"], function(){\n", |
|
205 | "require([\"notebook/js/widget\"], function(){\n", | |
280 | " \n", |
|
206 | " \n", | |
281 | " // Define the DateModel and register it with the widget manager.\n", |
|
207 | " // Define the DateModel and register it with the widget manager.\n", | |
282 | " var DateModel = IPython.WidgetModel.extend({});\n", |
|
208 | " var DateModel = IPython.WidgetModel.extend({});\n", | |
283 |
" IPython. |
|
209 | " IPython.widget_manager.register_widget_model('DateWidgetModel', DateModel);\n", | |
284 | " \n", |
|
210 | " \n", | |
285 | " // Define the DatePickerView\n", |
|
211 | " // Define the DatePickerView\n", | |
286 | " var DatePickerView = IPython.WidgetView.extend({\n", |
|
212 | " var DatePickerView = IPython.WidgetView.extend({\n", | |
287 | " \n", |
|
213 | " \n", | |
288 | " render: function(){\n", |
|
214 | " render: function(){\n", | |
289 | " this.$el = $('<div />')\n", |
|
215 | " this.$el = $('<div />')\n", | |
290 | " .html('Hello World!');\n", |
|
216 | " .html('Hello World!');\n", | |
291 | " },\n", |
|
217 | " },\n", | |
292 | " });\n", |
|
218 | " });\n", | |
293 | " \n", |
|
219 | " \n", | |
294 | " // Register the DatePickerView with the widget manager.\n", |
|
220 | " // Register the DatePickerView with the widget manager.\n", | |
295 |
" IPython. |
|
221 | " IPython.widget_manager.register_widget_view('DatePickerView', DatePickerView);\n", | |
296 | "});" |
|
222 | "});" | |
297 | ], |
|
223 | ], | |
298 | "language": "python", |
|
224 | "language": "python", | |
299 | "metadata": {}, |
|
225 | "metadata": {}, | |
300 | "outputs": [ |
|
226 | "outputs": [ | |
301 | { |
|
227 | { | |
302 | "javascript": [ |
|
228 | "javascript": [ | |
303 | "\n", |
|
229 | "\n", | |
304 | "require([\"notebook/js/widget\"], function(){\n", |
|
230 | "require([\"notebook/js/widget\"], function(){\n", | |
305 | " \n", |
|
231 | " \n", | |
306 | " // Define the DateModel and register it with the widget manager.\n", |
|
232 | " // Define the DateModel and register it with the widget manager.\n", | |
307 | " var DateModel = IPython.WidgetModel.extend({});\n", |
|
233 | " var DateModel = IPython.WidgetModel.extend({});\n", | |
308 |
" IPython. |
|
234 | " IPython.widget_manager.register_widget_model('DateWidgetModel', DateModel);\n", | |
309 | " \n", |
|
235 | " \n", | |
310 | " // Define the DatePickerView\n", |
|
236 | " // Define the DatePickerView\n", | |
311 | " var DatePickerView = IPython.WidgetView.extend({\n", |
|
237 | " var DatePickerView = IPython.WidgetView.extend({\n", | |
312 | " \n", |
|
238 | " \n", | |
313 | " render: function(){\n", |
|
239 | " render: function(){\n", | |
314 | " this.$el = $('<div />')\n", |
|
240 | " this.$el = $('<div />')\n", | |
315 | " .html('Hello World!');\n", |
|
241 | " .html('Hello World!');\n", | |
316 | " },\n", |
|
242 | " },\n", | |
317 | " });\n", |
|
243 | " });\n", | |
318 | " \n", |
|
244 | " \n", | |
319 | " // Register the DatePickerView with the widget manager.\n", |
|
245 | " // Register the DatePickerView with the widget manager.\n", | |
320 |
" IPython. |
|
246 | " IPython.widget_manager.register_widget_view('DatePickerView', DatePickerView);\n", | |
321 | "});" |
|
247 | "});" | |
322 | ], |
|
248 | ], | |
323 | "metadata": {}, |
|
249 | "metadata": {}, | |
324 | "output_type": "display_data", |
|
250 | "output_type": "display_data", | |
325 | "text": [ |
|
251 | "text": [ | |
326 |
"<IPython.core.display.Javascript at 0x |
|
252 | "<IPython.core.display.Javascript at 0x21f8cd0>" | |
327 | ] |
|
253 | ] | |
328 | } |
|
254 | } | |
329 | ], |
|
255 | ], | |
330 | "prompt_number": 5 |
|
256 | "prompt_number": 5 | |
331 | }, |
|
257 | }, | |
332 | { |
|
258 | { | |
333 | "cell_type": "heading", |
|
259 | "cell_type": "heading", | |
334 | "level": 2, |
|
260 | "level": 2, | |
335 | "metadata": {}, |
|
261 | "metadata": {}, | |
336 | "source": [ |
|
262 | "source": [ | |
337 | "Test" |
|
263 | "Test" | |
338 | ] |
|
264 | ] | |
339 | }, |
|
265 | }, | |
340 | { |
|
266 | { | |
341 | "cell_type": "markdown", |
|
267 | "cell_type": "markdown", | |
342 | "metadata": {}, |
|
268 | "metadata": {}, | |
343 | "source": [ |
|
269 | "source": [ | |
344 | "To test, create the widget the same way that the other widgets are created." |
|
270 | "To test, create the widget the same way that the other widgets are created." | |
345 | ] |
|
271 | ] | |
346 | }, |
|
272 | }, | |
347 | { |
|
273 | { | |
348 | "cell_type": "code", |
|
274 | "cell_type": "code", | |
349 | "collapsed": false, |
|
275 | "collapsed": false, | |
350 | "input": [ |
|
276 | "input": [ | |
351 | "my_widget = DateWidget()\n", |
|
277 | "my_widget = DateWidget()\n", | |
352 | "display(my_widget)" |
|
278 | "display(my_widget)" | |
353 | ], |
|
279 | ], | |
354 | "language": "python", |
|
280 | "language": "python", | |
355 | "metadata": {}, |
|
281 | "metadata": {}, | |
356 | "outputs": [], |
|
282 | "outputs": [], | |
357 | "prompt_number": 6 |
|
283 | "prompt_number": 6 | |
358 | }, |
|
284 | }, | |
359 | { |
|
285 | { | |
360 | "cell_type": "heading", |
|
286 | "cell_type": "heading", | |
361 | "level": 1, |
|
287 | "level": 1, | |
362 | "metadata": {}, |
|
288 | "metadata": {}, | |
363 | "source": [ |
|
289 | "source": [ | |
364 | "Section 2 - Something useful" |
|
290 | "Section 2 - Something useful" | |
365 | ] |
|
291 | ] | |
366 | }, |
|
292 | }, | |
367 | { |
|
293 | { | |
368 | "cell_type": "heading", |
|
294 | "cell_type": "heading", | |
369 | "level": 2, |
|
295 | "level": 2, | |
370 | "metadata": {}, |
|
296 | "metadata": {}, | |
371 | "source": [ |
|
297 | "source": [ | |
372 | "Python" |
|
298 | "Python" | |
373 | ] |
|
299 | ] | |
374 | }, |
|
300 | }, | |
375 | { |
|
301 | { | |
376 | "cell_type": "markdown", |
|
302 | "cell_type": "markdown", | |
377 | "metadata": {}, |
|
303 | "metadata": {}, | |
378 | "source": [ |
|
304 | "source": [ | |
379 | "In the last section we created a simple widget that displayed *Hello World!* There was no custom state information associated with the widget. To make an actual date widget, we need to add a property that will be synced between the Python model and the JavaScript model. The new property must be a traitlet property so the widget machinery can automatically handle it. The property needs to be added to the the `_keys` list. The `_keys` list tells the widget machinery what traitlets should be synced with the front-end. Adding this to the code from the last section:" |
|
305 | "In the last section we created a simple widget that displayed *Hello World!* There was no custom state information associated with the widget. To make an actual date widget, we need to add a property that will be synced between the Python model and the JavaScript model. The new property must be a traitlet property so the widget machinery can automatically handle it. The property needs to be added to the the `_keys` list. The `_keys` list tells the widget machinery what traitlets should be synced with the front-end. Adding this to the code from the last section:" | |
380 | ] |
|
306 | ] | |
381 | }, |
|
307 | }, | |
382 | { |
|
308 | { | |
383 | "cell_type": "code", |
|
309 | "cell_type": "code", | |
384 | "collapsed": false, |
|
310 | "collapsed": false, | |
385 | "input": [ |
|
311 | "input": [ | |
386 | "# Import the base Widget class and the traitlets Unicode class.\n", |
|
312 | "# Import the base Widget class and the traitlets Unicode class.\n", | |
387 | "from IPython.html.widgets import Widget\n", |
|
313 | "from IPython.html.widgets import Widget\n", | |
388 | "from IPython.utils.traitlets import Unicode\n", |
|
314 | "from IPython.utils.traitlets import Unicode\n", | |
389 | "\n", |
|
315 | "\n", | |
390 | "# Define our DateWidget and its target model and default view.\n", |
|
316 | "# Define our DateWidget and its target model and default view.\n", | |
391 | "class DateWidget(Widget):\n", |
|
317 | "class DateWidget(Widget):\n", | |
392 | " target_name = Unicode('DateWidgetModel')\n", |
|
318 | " target_name = Unicode('DateWidgetModel')\n", | |
393 | " default_view_name = Unicode('DatePickerView')\n", |
|
319 | " default_view_name = Unicode('DatePickerView')\n", | |
394 | " \n", |
|
320 | " \n", | |
395 | " # Define the custom state properties to sync with the front-end\n", |
|
321 | " # Define the custom state properties to sync with the front-end\n", | |
396 | " _keys = ['value']\n", |
|
322 | " _keys = ['value']\n", | |
397 | " value = Unicode()" |
|
323 | " value = Unicode()" | |
398 | ], |
|
324 | ], | |
399 | "language": "python", |
|
325 | "language": "python", | |
400 | "metadata": {}, |
|
326 | "metadata": {}, | |
401 | "outputs": [], |
|
327 | "outputs": [], | |
402 | "prompt_number": 7 |
|
328 | "prompt_number": 7 | |
403 | }, |
|
329 | }, | |
404 | { |
|
330 | { | |
405 | "cell_type": "heading", |
|
331 | "cell_type": "heading", | |
406 | "level": 2, |
|
332 | "level": 2, | |
407 | "metadata": {}, |
|
333 | "metadata": {}, | |
408 | "source": [ |
|
334 | "source": [ | |
409 | "JavaScript" |
|
335 | "JavaScript" | |
410 | ] |
|
336 | ] | |
411 | }, |
|
337 | }, | |
412 | { |
|
338 | { | |
413 | "cell_type": "markdown", |
|
339 | "cell_type": "markdown", | |
414 | "metadata": {}, |
|
340 | "metadata": {}, | |
415 | "source": [ |
|
341 | "source": [ | |
416 | "In the JavaScript there is no need to define the same properties in the JavaScript model. When the JavaScript model is created for the first time, it copies all of the attributes from the Python model. We need to replace *Hello World!* with an actual HTML date picker widget." |
|
342 | "In the JavaScript there is no need to define the same properties in the JavaScript model. When the JavaScript model is created for the first time, it copies all of the attributes from the Python model. We need to replace *Hello World!* with an actual HTML date picker widget." | |
417 | ] |
|
343 | ] | |
418 | }, |
|
344 | }, | |
419 | { |
|
345 | { | |
420 | "cell_type": "code", |
|
346 | "cell_type": "code", | |
421 | "collapsed": false, |
|
347 | "collapsed": false, | |
422 | "input": [ |
|
348 | "input": [ | |
423 | "%%javascript\n", |
|
349 | "%%javascript\n", | |
424 | "\n", |
|
350 | "\n", | |
425 | "require([\"notebook/js/widget\"], function(){\n", |
|
351 | "require([\"notebook/js/widget\"], function(){\n", | |
426 | " \n", |
|
352 | " \n", | |
427 | " // Define the DateModel and register it with the widget manager.\n", |
|
353 | " // Define the DateModel and register it with the widget manager.\n", | |
428 | " var DateModel = IPython.WidgetModel.extend({});\n", |
|
354 | " var DateModel = IPython.WidgetModel.extend({});\n", | |
429 |
" IPython. |
|
355 | " IPython.widget_manager.register_widget_model('DateWidgetModel', DateModel);\n", | |
430 | " \n", |
|
356 | " \n", | |
431 | " // Define the DatePickerView\n", |
|
357 | " // Define the DatePickerView\n", | |
432 | " var DatePickerView = IPython.WidgetView.extend({\n", |
|
358 | " var DatePickerView = IPython.WidgetView.extend({\n", | |
433 | " \n", |
|
359 | " \n", | |
434 | " render: function(){\n", |
|
360 | " render: function(){\n", | |
435 | " \n", |
|
361 | " \n", | |
436 | " // Create a div to hold our widget.\n", |
|
362 | " // Create a div to hold our widget.\n", | |
437 | " this.$el = $('<div />');\n", |
|
363 | " this.$el = $('<div />');\n", | |
438 | " \n", |
|
364 | " \n", | |
439 | " // Create the date picker control.\n", |
|
365 | " // Create the date picker control.\n", | |
440 | " this.$date = $('<input />')\n", |
|
366 | " this.$date = $('<input />')\n", | |
441 | " .attr('type', 'date');\n", |
|
367 | " .attr('type', 'date');\n", | |
442 | " },\n", |
|
368 | " },\n", | |
443 | " });\n", |
|
369 | " });\n", | |
444 | " \n", |
|
370 | " \n", | |
445 | " // Register the DatePickerView with the widget manager.\n", |
|
371 | " // Register the DatePickerView with the widget manager.\n", | |
446 |
" IPython. |
|
372 | " IPython.widget_manager.register_widget_view('DatePickerView', DatePickerView);\n", | |
447 | "});" |
|
373 | "});" | |
448 | ], |
|
374 | ], | |
449 | "language": "python", |
|
375 | "language": "python", | |
450 | "metadata": {}, |
|
376 | "metadata": {}, | |
451 | "outputs": [ |
|
377 | "outputs": [ | |
452 | { |
|
378 | { | |
453 | "javascript": [ |
|
379 | "javascript": [ | |
454 | "\n", |
|
380 | "\n", | |
455 | "require([\"notebook/js/widget\"], function(){\n", |
|
381 | "require([\"notebook/js/widget\"], function(){\n", | |
456 | " \n", |
|
382 | " \n", | |
457 | " // Define the DateModel and register it with the widget manager.\n", |
|
383 | " // Define the DateModel and register it with the widget manager.\n", | |
458 | " var DateModel = IPython.WidgetModel.extend({});\n", |
|
384 | " var DateModel = IPython.WidgetModel.extend({});\n", | |
459 |
" IPython. |
|
385 | " IPython.widget_manager.register_widget_model('DateWidgetModel', DateModel);\n", | |
460 | " \n", |
|
386 | " \n", | |
461 | " // Define the DatePickerView\n", |
|
387 | " // Define the DatePickerView\n", | |
462 | " var DatePickerView = IPython.WidgetView.extend({\n", |
|
388 | " var DatePickerView = IPython.WidgetView.extend({\n", | |
463 | " \n", |
|
389 | " \n", | |
464 | " render: function(){\n", |
|
390 | " render: function(){\n", | |
465 | " \n", |
|
391 | " \n", | |
466 | " // Create a div to hold our widget.\n", |
|
392 | " // Create a div to hold our widget.\n", | |
467 | " this.$el = $('<div />');\n", |
|
393 | " this.$el = $('<div />');\n", | |
468 | " \n", |
|
394 | " \n", | |
469 | " // Create the date picker control.\n", |
|
395 | " // Create the date picker control.\n", | |
470 | " this.$date = $('<input />')\n", |
|
396 | " this.$date = $('<input />')\n", | |
471 | " .attr('type', 'date');\n", |
|
397 | " .attr('type', 'date');\n", | |
472 | " },\n", |
|
398 | " },\n", | |
473 | " });\n", |
|
399 | " });\n", | |
474 | " \n", |
|
400 | " \n", | |
475 | " // Register the DatePickerView with the widget manager.\n", |
|
401 | " // Register the DatePickerView with the widget manager.\n", | |
476 |
" IPython. |
|
402 | " IPython.widget_manager.register_widget_view('DatePickerView', DatePickerView);\n", | |
477 | "});" |
|
403 | "});" | |
478 | ], |
|
404 | ], | |
479 | "metadata": {}, |
|
405 | "metadata": {}, | |
480 | "output_type": "display_data", |
|
406 | "output_type": "display_data", | |
481 | "text": [ |
|
407 | "text": [ | |
482 |
"<IPython.core.display.Javascript at 0x |
|
408 | "<IPython.core.display.Javascript at 0x21fc310>" | |
483 | ] |
|
409 | ] | |
484 | } |
|
410 | } | |
485 | ], |
|
411 | ], | |
486 | "prompt_number": 8 |
|
412 | "prompt_number": 8 | |
487 | }, |
|
413 | }, | |
488 | { |
|
414 | { | |
489 | "cell_type": "markdown", |
|
415 | "cell_type": "markdown", | |
490 | "metadata": {}, |
|
416 | "metadata": {}, | |
491 | "source": [ |
|
417 | "source": [ | |
492 | "In order to get the HTML date picker to update itself with the value set in the back-end, we need to implement an `update()` method." |
|
418 | "In order to get the HTML date picker to update itself with the value set in the back-end, we need to implement an `update()` method." | |
493 | ] |
|
419 | ] | |
494 | }, |
|
420 | }, | |
495 | { |
|
421 | { | |
496 | "cell_type": "code", |
|
422 | "cell_type": "code", | |
497 | "collapsed": false, |
|
423 | "collapsed": false, | |
498 | "input": [ |
|
424 | "input": [ | |
499 | "%%javascript\n", |
|
425 | "%%javascript\n", | |
500 | "\n", |
|
426 | "\n", | |
501 | "require([\"notebook/js/widget\"], function(){\n", |
|
427 | "require([\"notebook/js/widget\"], function(){\n", | |
502 | " \n", |
|
428 | " \n", | |
503 | " // Define the DateModel and register it with the widget manager.\n", |
|
429 | " // Define the DateModel and register it with the widget manager.\n", | |
504 | " var DateModel = IPython.WidgetModel.extend({});\n", |
|
430 | " var DateModel = IPython.WidgetModel.extend({});\n", | |
505 |
" IPython. |
|
431 | " IPython.widget_manager.register_widget_model('DateWidgetModel', DateModel);\n", | |
506 | " \n", |
|
432 | " \n", | |
507 | " // Define the DatePickerView\n", |
|
433 | " // Define the DatePickerView\n", | |
508 | " var DatePickerView = IPython.WidgetView.extend({\n", |
|
434 | " var DatePickerView = IPython.WidgetView.extend({\n", | |
509 | " \n", |
|
435 | " \n", | |
510 | " render: function(){\n", |
|
436 | " render: function(){\n", | |
511 | " \n", |
|
437 | " \n", | |
512 | " // Create a div to hold our widget.\n", |
|
438 | " // Create a div to hold our widget.\n", | |
513 | " this.$el = $('<div />');\n", |
|
439 | " this.$el = $('<div />');\n", | |
514 | " \n", |
|
440 | " \n", | |
515 | " // Create the date picker control.\n", |
|
441 | " // Create the date picker control.\n", | |
516 | " this.$date = $('<input />')\n", |
|
442 | " this.$date = $('<input />')\n", | |
517 | " .attr('type', 'date');\n", |
|
443 | " .attr('type', 'date');\n", | |
518 | " },\n", |
|
444 | " },\n", | |
519 | " \n", |
|
445 | " \n", | |
520 | " update: function() {\n", |
|
446 | " update: function() {\n", | |
521 | " \n", |
|
447 | " \n", | |
522 | " // Set the value of the date control and then call base.\n", |
|
448 | " // Set the value of the date control and then call base.\n", | |
523 | " this.$date.val(this.model.get('value')); // ISO format \"YYYY-MM-DDTHH:mm:ss.sssZ\" is required\n", |
|
449 | " this.$date.val(this.model.get('value')); // ISO format \"YYYY-MM-DDTHH:mm:ss.sssZ\" is required\n", | |
524 | " return IPython.WidgetView.prototype.update.call(this);\n", |
|
450 | " return IPython.WidgetView.prototype.update.call(this);\n", | |
525 | " },\n", |
|
451 | " },\n", | |
526 | " });\n", |
|
452 | " });\n", | |
527 | " \n", |
|
453 | " \n", | |
528 | " // Register the DatePickerView with the widget manager.\n", |
|
454 | " // Register the DatePickerView with the widget manager.\n", | |
529 |
" IPython. |
|
455 | " IPython.widget_manager.register_widget_view('DatePickerView', DatePickerView);\n", | |
530 | "});" |
|
456 | "});" | |
531 | ], |
|
457 | ], | |
532 | "language": "python", |
|
458 | "language": "python", | |
533 | "metadata": {}, |
|
459 | "metadata": {}, | |
534 | "outputs": [ |
|
460 | "outputs": [ | |
535 | { |
|
461 | { | |
536 | "javascript": [ |
|
462 | "javascript": [ | |
537 | "\n", |
|
463 | "\n", | |
538 | "require([\"notebook/js/widget\"], function(){\n", |
|
464 | "require([\"notebook/js/widget\"], function(){\n", | |
539 | " \n", |
|
465 | " \n", | |
540 | " // Define the DateModel and register it with the widget manager.\n", |
|
466 | " // Define the DateModel and register it with the widget manager.\n", | |
541 | " var DateModel = IPython.WidgetModel.extend({});\n", |
|
467 | " var DateModel = IPython.WidgetModel.extend({});\n", | |
542 |
" IPython. |
|
468 | " IPython.widget_manager.register_widget_model('DateWidgetModel', DateModel);\n", | |
543 | " \n", |
|
469 | " \n", | |
544 | " // Define the DatePickerView\n", |
|
470 | " // Define the DatePickerView\n", | |
545 | " var DatePickerView = IPython.WidgetView.extend({\n", |
|
471 | " var DatePickerView = IPython.WidgetView.extend({\n", | |
546 | " \n", |
|
472 | " \n", | |
547 | " render: function(){\n", |
|
473 | " render: function(){\n", | |
548 | " \n", |
|
474 | " \n", | |
549 | " // Create a div to hold our widget.\n", |
|
475 | " // Create a div to hold our widget.\n", | |
550 | " this.$el = $('<div />');\n", |
|
476 | " this.$el = $('<div />');\n", | |
551 | " \n", |
|
477 | " \n", | |
552 | " // Create the date picker control.\n", |
|
478 | " // Create the date picker control.\n", | |
553 | " this.$date = $('<input />')\n", |
|
479 | " this.$date = $('<input />')\n", | |
554 | " .attr('type', 'date');\n", |
|
480 | " .attr('type', 'date');\n", | |
555 | " },\n", |
|
481 | " },\n", | |
556 | " \n", |
|
482 | " \n", | |
557 | " update: function() {\n", |
|
483 | " update: function() {\n", | |
558 | " \n", |
|
484 | " \n", | |
559 | " // Set the value of the date control and then call base.\n", |
|
485 | " // Set the value of the date control and then call base.\n", | |
560 | " this.$date.val(this.model.get('value')); // ISO format \"YYYY-MM-DDTHH:mm:ss.sssZ\" is required\n", |
|
486 | " this.$date.val(this.model.get('value')); // ISO format \"YYYY-MM-DDTHH:mm:ss.sssZ\" is required\n", | |
561 | " return IPython.WidgetView.prototype.update.call(this);\n", |
|
487 | " return IPython.WidgetView.prototype.update.call(this);\n", | |
562 | " },\n", |
|
488 | " },\n", | |
563 | " });\n", |
|
489 | " });\n", | |
564 | " \n", |
|
490 | " \n", | |
565 | " // Register the DatePickerView with the widget manager.\n", |
|
491 | " // Register the DatePickerView with the widget manager.\n", | |
566 |
" IPython. |
|
492 | " IPython.widget_manager.register_widget_view('DatePickerView', DatePickerView);\n", | |
567 | "});" |
|
493 | "});" | |
568 | ], |
|
494 | ], | |
569 | "metadata": {}, |
|
495 | "metadata": {}, | |
570 | "output_type": "display_data", |
|
496 | "output_type": "display_data", | |
571 | "text": [ |
|
497 | "text": [ | |
572 |
"<IPython.core.display.Javascript at 0x |
|
498 | "<IPython.core.display.Javascript at 0x21fc290>" | |
573 | ] |
|
499 | ] | |
574 | } |
|
500 | } | |
575 | ], |
|
501 | ], | |
576 | "prompt_number": 9 |
|
502 | "prompt_number": 9 | |
577 | }, |
|
503 | }, | |
578 | { |
|
504 | { | |
579 | "cell_type": "markdown", |
|
505 | "cell_type": "markdown", | |
580 | "metadata": {}, |
|
506 | "metadata": {}, | |
581 | "source": [ |
|
507 | "source": [ | |
582 | "To get the changed value from the front-end to publish itself to the back-end, we need to listen to the change event triggered by the HTM date control and set the value in the model. By setting the `this.$el` property of the view, we break the Backbone powered event handling. To fix this, a call to `this.delegateEvents()` must be added after `this.$el` is set. \n", |
|
508 | "To get the changed value from the front-end to publish itself to the back-end, we need to listen to the change event triggered by the HTM date control and set the value in the model. By setting the `this.$el` property of the view, we break the Backbone powered event handling. To fix this, a call to `this.delegateEvents()` must be added after `this.$el` is set. \n", | |
583 | "\n", |
|
509 | "\n", | |
584 | "After the date change event fires and the new value is set in the model, it's very important that we call `update_other_views(this)` to make the other views on the page update and to let the widget machinery know which view changed the model. This is important because the widget machinery needs to know which cell to route the message callbacks to.\n", |
|
510 | "After the date change event fires and the new value is set in the model, it's very important that we call `update_other_views(this)` to make the other views on the page update and to let the widget machinery know which view changed the model. This is important because the widget machinery needs to know which cell to route the message callbacks to.\n", | |
585 | "\n", |
|
511 | "\n", | |
586 | "**Final JavaScript code below:**" |
|
512 | "**Final JavaScript code below:**" | |
587 | ] |
|
513 | ] | |
588 | }, |
|
514 | }, | |
589 | { |
|
515 | { | |
590 | "cell_type": "code", |
|
516 | "cell_type": "code", | |
591 | "collapsed": false, |
|
517 | "collapsed": false, | |
592 | "input": [ |
|
518 | "input": [ | |
593 | "%%javascript\n", |
|
519 | "%%javascript\n", | |
594 | "\n", |
|
520 | "\n", | |
595 | "require([\"notebook/js/widget\"], function(){\n", |
|
521 | "require([\"notebook/js/widget\"], function(){\n", | |
596 | " \n", |
|
522 | " \n", | |
597 | " // Define the DateModel and register it with the widget manager.\n", |
|
523 | " // Define the DateModel and register it with the widget manager.\n", | |
598 | " var DateModel = IPython.WidgetModel.extend({});\n", |
|
524 | " var DateModel = IPython.WidgetModel.extend({});\n", | |
599 |
" IPython. |
|
525 | " IPython.widget_manager.register_widget_model('DateWidgetModel', DateModel);\n", | |
600 | " \n", |
|
526 | " \n", | |
601 | " // Define the DatePickerView\n", |
|
527 | " // Define the DatePickerView\n", | |
602 | " var DatePickerView = IPython.WidgetView.extend({\n", |
|
528 | " var DatePickerView = IPython.WidgetView.extend({\n", | |
603 | " \n", |
|
529 | " \n", | |
604 | " render: function(){\n", |
|
530 | " render: function(){\n", | |
605 | " \n", |
|
531 | " \n", | |
606 | " // Create a div to hold our widget.\n", |
|
532 | " // Create a div to hold our widget.\n", | |
607 | " this.$el = $('<div />');\n", |
|
533 | " this.$el = $('<div />');\n", | |
608 | " this.delegateEvents();\n", |
|
534 | " this.delegateEvents();\n", | |
609 | " \n", |
|
535 | " \n", | |
610 | " // Create the date picker control.\n", |
|
536 | " // Create the date picker control.\n", | |
611 | " this.$date = $('<input />')\n", |
|
537 | " this.$date = $('<input />')\n", | |
612 | " .attr('type', 'date')\n", |
|
538 | " .attr('type', 'date')\n", | |
613 | " .appendTo(this.$el);\n", |
|
539 | " .appendTo(this.$el);\n", | |
614 | " },\n", |
|
540 | " },\n", | |
615 | " \n", |
|
541 | " \n", | |
616 | " update: function() {\n", |
|
542 | " update: function() {\n", | |
617 | " \n", |
|
543 | " \n", | |
618 | " // Set the value of the date control and then call base.\n", |
|
544 | " // Set the value of the date control and then call base.\n", | |
619 | " this.$date.val(this.model.get('value')); // ISO format \"YYYY-MM-DDTHH:mm:ss.sssZ\" is required\n", |
|
545 | " this.$date.val(this.model.get('value')); // ISO format \"YYYY-MM-DDTHH:mm:ss.sssZ\" is required\n", | |
620 | " return IPython.WidgetView.prototype.update.call(this);\n", |
|
546 | " return IPython.WidgetView.prototype.update.call(this);\n", | |
621 | " },\n", |
|
547 | " },\n", | |
622 | " \n", |
|
548 | " \n", | |
623 | " // Tell Backbone to listen to the change event of input controls (which the HTML date picker is)\n", |
|
549 | " // Tell Backbone to listen to the change event of input controls (which the HTML date picker is)\n", | |
624 | " events: {\"change\": \"handle_date_change\"},\n", |
|
550 | " events: {\"change\": \"handle_date_change\"},\n", | |
625 | " \n", |
|
551 | " \n", | |
626 | " // Callback for when the date is changed.\n", |
|
552 | " // Callback for when the date is changed.\n", | |
627 | " handle_date_change: function(event) {\n", |
|
553 | " handle_date_change: function(event) {\n", | |
628 | " this.model.set('value', this.$date.val());\n", |
|
554 | " this.model.set('value', this.$date.val());\n", | |
629 | " this.model.update_other_views(this);\n", |
|
555 | " this.model.update_other_views(this);\n", | |
630 | " },\n", |
|
556 | " },\n", | |
631 | " \n", |
|
557 | " \n", | |
632 | " });\n", |
|
558 | " });\n", | |
633 | " \n", |
|
559 | " \n", | |
634 | " // Register the DatePickerView with the widget manager.\n", |
|
560 | " // Register the DatePickerView with the widget manager.\n", | |
635 |
" IPython. |
|
561 | " IPython.widget_manager.register_widget_view('DatePickerView', DatePickerView);\n", | |
636 | "});" |
|
562 | "});" | |
637 | ], |
|
563 | ], | |
638 | "language": "python", |
|
564 | "language": "python", | |
639 | "metadata": {}, |
|
565 | "metadata": {}, | |
640 | "outputs": [ |
|
566 | "outputs": [ | |
641 | { |
|
567 | { | |
642 | "javascript": [ |
|
568 | "javascript": [ | |
643 | "\n", |
|
569 | "\n", | |
644 | "require([\"notebook/js/widget\"], function(){\n", |
|
570 | "require([\"notebook/js/widget\"], function(){\n", | |
645 | " \n", |
|
571 | " \n", | |
646 | " // Define the DateModel and register it with the widget manager.\n", |
|
572 | " // Define the DateModel and register it with the widget manager.\n", | |
647 | " var DateModel = IPython.WidgetModel.extend({});\n", |
|
573 | " var DateModel = IPython.WidgetModel.extend({});\n", | |
648 |
" IPython. |
|
574 | " IPython.widget_manager.register_widget_model('DateWidgetModel', DateModel);\n", | |
649 | " \n", |
|
575 | " \n", | |
650 | " // Define the DatePickerView\n", |
|
576 | " // Define the DatePickerView\n", | |
651 | " var DatePickerView = IPython.WidgetView.extend({\n", |
|
577 | " var DatePickerView = IPython.WidgetView.extend({\n", | |
652 | " \n", |
|
578 | " \n", | |
653 | " render: function(){\n", |
|
579 | " render: function(){\n", | |
654 | " \n", |
|
580 | " \n", | |
655 | " // Create a div to hold our widget.\n", |
|
581 | " // Create a div to hold our widget.\n", | |
656 | " this.$el = $('<div />');\n", |
|
582 | " this.$el = $('<div />');\n", | |
657 | " this.delegateEvents();\n", |
|
583 | " this.delegateEvents();\n", | |
658 | " \n", |
|
584 | " \n", | |
659 | " // Create the date picker control.\n", |
|
585 | " // Create the date picker control.\n", | |
660 | " this.$date = $('<input />')\n", |
|
586 | " this.$date = $('<input />')\n", | |
661 | " .attr('type', 'date')\n", |
|
587 | " .attr('type', 'date')\n", | |
662 | " .appendTo(this.$el);\n", |
|
588 | " .appendTo(this.$el);\n", | |
663 | " },\n", |
|
589 | " },\n", | |
664 | " \n", |
|
590 | " \n", | |
665 | " update: function() {\n", |
|
591 | " update: function() {\n", | |
666 | " \n", |
|
592 | " \n", | |
667 | " // Set the value of the date control and then call base.\n", |
|
593 | " // Set the value of the date control and then call base.\n", | |
668 | " this.$date.val(this.model.get('value')); // ISO format \"YYYY-MM-DDTHH:mm:ss.sssZ\" is required\n", |
|
594 | " this.$date.val(this.model.get('value')); // ISO format \"YYYY-MM-DDTHH:mm:ss.sssZ\" is required\n", | |
669 | " return IPython.WidgetView.prototype.update.call(this);\n", |
|
595 | " return IPython.WidgetView.prototype.update.call(this);\n", | |
670 | " },\n", |
|
596 | " },\n", | |
671 | " \n", |
|
597 | " \n", | |
672 | " // Tell Backbone to listen to the change event of input controls (which the HTML date picker is)\n", |
|
598 | " // Tell Backbone to listen to the change event of input controls (which the HTML date picker is)\n", | |
673 | " events: {\"change\": \"handle_date_change\"},\n", |
|
599 | " events: {\"change\": \"handle_date_change\"},\n", | |
674 | " \n", |
|
600 | " \n", | |
675 | " // Callback for when the date is changed.\n", |
|
601 | " // Callback for when the date is changed.\n", | |
676 | " handle_date_change: function(event) {\n", |
|
602 | " handle_date_change: function(event) {\n", | |
677 | " this.model.set('value', this.$date.val());\n", |
|
603 | " this.model.set('value', this.$date.val());\n", | |
678 | " this.model.update_other_views(this);\n", |
|
604 | " this.model.update_other_views(this);\n", | |
679 | " },\n", |
|
605 | " },\n", | |
680 | " \n", |
|
606 | " \n", | |
681 | " });\n", |
|
607 | " });\n", | |
682 | " \n", |
|
608 | " \n", | |
683 | " // Register the DatePickerView with the widget manager.\n", |
|
609 | " // Register the DatePickerView with the widget manager.\n", | |
684 |
" IPython. |
|
610 | " IPython.widget_manager.register_widget_view('DatePickerView', DatePickerView);\n", | |
685 | "});" |
|
611 | "});" | |
686 | ], |
|
612 | ], | |
687 | "metadata": {}, |
|
613 | "metadata": {}, | |
688 | "output_type": "display_data", |
|
614 | "output_type": "display_data", | |
689 | "text": [ |
|
615 | "text": [ | |
690 |
"<IPython.core.display.Javascript at 0x |
|
616 | "<IPython.core.display.Javascript at 0x21fc3d0>" | |
691 | ] |
|
617 | ] | |
692 | } |
|
618 | } | |
693 | ], |
|
619 | ], | |
694 | "prompt_number": 10 |
|
620 | "prompt_number": 10 | |
695 | }, |
|
621 | }, | |
696 | { |
|
622 | { | |
697 | "cell_type": "heading", |
|
623 | "cell_type": "heading", | |
698 | "level": 2, |
|
624 | "level": 2, | |
699 | "metadata": {}, |
|
625 | "metadata": {}, | |
700 | "source": [ |
|
626 | "source": [ | |
701 | "Test" |
|
627 | "Test" | |
702 | ] |
|
628 | ] | |
703 | }, |
|
629 | }, | |
704 | { |
|
630 | { | |
705 | "cell_type": "markdown", |
|
631 | "cell_type": "markdown", | |
706 | "metadata": {}, |
|
632 | "metadata": {}, | |
707 | "source": [ |
|
633 | "source": [ | |
708 | "To test, create the widget the same way that the other widgets are created." |
|
634 | "To test, create the widget the same way that the other widgets are created." | |
709 | ] |
|
635 | ] | |
710 | }, |
|
636 | }, | |
711 | { |
|
637 | { | |
712 | "cell_type": "code", |
|
638 | "cell_type": "code", | |
713 | "collapsed": false, |
|
639 | "collapsed": false, | |
714 | "input": [ |
|
640 | "input": [ | |
715 | "my_widget = DateWidget()\n", |
|
641 | "my_widget = DateWidget()\n", | |
716 | "display(my_widget)" |
|
642 | "display(my_widget)" | |
717 | ], |
|
643 | ], | |
718 | "language": "python", |
|
644 | "language": "python", | |
719 | "metadata": {}, |
|
645 | "metadata": {}, | |
720 | "outputs": [], |
|
646 | "outputs": [], | |
721 | "prompt_number": 11 |
|
647 | "prompt_number": 11 | |
722 | }, |
|
648 | }, | |
723 | { |
|
649 | { | |
724 | "cell_type": "markdown", |
|
650 | "cell_type": "markdown", | |
725 | "metadata": {}, |
|
651 | "metadata": {}, | |
726 | "source": [ |
|
652 | "source": [ | |
727 | "Display the widget again to make sure that both views remain in sync." |
|
653 | "Display the widget again to make sure that both views remain in sync." | |
728 | ] |
|
654 | ] | |
729 | }, |
|
655 | }, | |
730 | { |
|
656 | { | |
731 | "cell_type": "code", |
|
657 | "cell_type": "code", | |
732 | "collapsed": false, |
|
658 | "collapsed": false, | |
733 | "input": [ |
|
659 | "input": [ | |
734 | "display(my_widget)" |
|
660 | "display(my_widget)" | |
735 | ], |
|
661 | ], | |
736 | "language": "python", |
|
662 | "language": "python", | |
737 | "metadata": {}, |
|
663 | "metadata": {}, | |
738 | "outputs": [], |
|
664 | "outputs": [], | |
739 | "prompt_number": 12 |
|
665 | "prompt_number": 12 | |
740 | }, |
|
666 | }, | |
741 | { |
|
667 | { | |
742 | "cell_type": "markdown", |
|
668 | "cell_type": "markdown", | |
743 | "metadata": {}, |
|
669 | "metadata": {}, | |
744 | "source": [ |
|
670 | "source": [ | |
745 | "Read the date from Python" |
|
671 | "Read the date from Python" | |
746 | ] |
|
672 | ] | |
747 | }, |
|
673 | }, | |
748 | { |
|
674 | { | |
749 | "cell_type": "code", |
|
675 | "cell_type": "code", | |
750 | "collapsed": false, |
|
676 | "collapsed": false, | |
751 | "input": [ |
|
677 | "input": [ | |
752 | "my_widget.value" |
|
678 | "my_widget.value" | |
753 | ], |
|
679 | ], | |
754 | "language": "python", |
|
680 | "language": "python", | |
755 | "metadata": {}, |
|
681 | "metadata": {}, | |
756 | "outputs": [ |
|
682 | "outputs": [ | |
757 | { |
|
683 | { | |
758 | "metadata": {}, |
|
684 | "metadata": {}, | |
759 | "output_type": "pyout", |
|
685 | "output_type": "pyout", | |
760 | "prompt_number": 13, |
|
686 | "prompt_number": 13, | |
761 | "text": [ |
|
687 | "text": [ | |
762 | "u''" |
|
688 | "u'2013-11-14'" | |
763 | ] |
|
689 | ] | |
764 | } |
|
690 | } | |
765 | ], |
|
691 | ], | |
766 | "prompt_number": 13 |
|
692 | "prompt_number": 13 | |
767 | }, |
|
693 | }, | |
768 | { |
|
694 | { | |
769 | "cell_type": "markdown", |
|
695 | "cell_type": "markdown", | |
770 | "metadata": {}, |
|
696 | "metadata": {}, | |
771 | "source": [ |
|
697 | "source": [ | |
772 | "Set the date from Python" |
|
698 | "Set the date from Python" | |
773 | ] |
|
699 | ] | |
774 | }, |
|
700 | }, | |
775 | { |
|
701 | { | |
776 | "cell_type": "code", |
|
702 | "cell_type": "code", | |
777 | "collapsed": false, |
|
703 | "collapsed": false, | |
778 | "input": [ |
|
704 | "input": [ | |
779 | "my_widget.value = \"1999-12-01\" # December 1st, 1999" |
|
705 | "my_widget.value = \"1999-12-01\" # December 1st, 1999" | |
780 | ], |
|
706 | ], | |
781 | "language": "python", |
|
707 | "language": "python", | |
782 | "metadata": {}, |
|
708 | "metadata": {}, | |
783 | "outputs": [], |
|
709 | "outputs": [], | |
784 | "prompt_number": 14 |
|
710 | "prompt_number": 14 | |
785 | }, |
|
711 | }, | |
786 | { |
|
712 | { | |
787 | "cell_type": "heading", |
|
713 | "cell_type": "heading", | |
788 | "level": 1, |
|
714 | "level": 1, | |
789 | "metadata": {}, |
|
715 | "metadata": {}, | |
790 | "source": [ |
|
716 | "source": [ | |
791 | "Section 3 - Extra credit" |
|
717 | "Section 3 - Extra credit" | |
792 | ] |
|
718 | ] | |
793 | }, |
|
719 | }, | |
794 | { |
|
720 | { | |
795 | "cell_type": "markdown", |
|
721 | "cell_type": "markdown", | |
796 | "metadata": {}, |
|
722 | "metadata": {}, | |
797 | "source": [ |
|
723 | "source": [ | |
798 | "In the last section we created a fully working date picker widget. Now we will add custom validation and support for labels. Currently only the ISO date format \"YYYY-MM-DD\" is supported. We will add support for all of the date formats recognized by the 3rd party Python dateutil library." |
|
724 | "In the last section we created a fully working date picker widget. Now we will add custom validation and support for labels. Currently only the ISO date format \"YYYY-MM-DD\" is supported. We will add support for all of the date formats recognized by the 3rd party Python dateutil library." | |
799 | ] |
|
725 | ] | |
800 | }, |
|
726 | }, | |
801 | { |
|
727 | { | |
802 | "cell_type": "heading", |
|
728 | "cell_type": "heading", | |
803 | "level": 2, |
|
729 | "level": 2, | |
804 | "metadata": {}, |
|
730 | "metadata": {}, | |
805 | "source": [ |
|
731 | "source": [ | |
806 | "Python" |
|
732 | "Python" | |
807 | ] |
|
733 | ] | |
808 | }, |
|
734 | }, | |
809 | { |
|
735 | { | |
810 | "cell_type": "markdown", |
|
736 | "cell_type": "markdown", | |
811 | "metadata": {}, |
|
737 | "metadata": {}, | |
812 | "source": [ |
|
738 | "source": [ | |
813 | "The traitlet machinery searches the class that the trait is defined in for methods with \"`_changed`\" suffixed onto their names. Any method with the format \"`X_changed`\" will be called when \"`X`\" is modified. We can take advantage of this to perform validation and parsing of different date string formats. Below a method that listens to value has been added to the DateWidget." |
|
739 | "The traitlet machinery searches the class that the trait is defined in for methods with \"`_changed`\" suffixed onto their names. Any method with the format \"`X_changed`\" will be called when \"`X`\" is modified. We can take advantage of this to perform validation and parsing of different date string formats. Below a method that listens to value has been added to the DateWidget." | |
814 | ] |
|
740 | ] | |
815 | }, |
|
741 | }, | |
816 | { |
|
742 | { | |
817 | "cell_type": "code", |
|
743 | "cell_type": "code", | |
818 | "collapsed": false, |
|
744 | "collapsed": false, | |
819 | "input": [ |
|
745 | "input": [ | |
820 | "# Import the base Widget class and the traitlets Unicode class.\n", |
|
746 | "# Import the base Widget class and the traitlets Unicode class.\n", | |
821 | "from IPython.html.widgets import Widget\n", |
|
747 | "from IPython.html.widgets import Widget\n", | |
822 | "from IPython.utils.traitlets import Unicode\n", |
|
748 | "from IPython.utils.traitlets import Unicode\n", | |
823 | "\n", |
|
749 | "\n", | |
824 | "# Define our DateWidget and its target model and default view.\n", |
|
750 | "# Define our DateWidget and its target model and default view.\n", | |
825 | "class DateWidget(Widget):\n", |
|
751 | "class DateWidget(Widget):\n", | |
826 | " target_name = Unicode('DateWidgetModel')\n", |
|
752 | " target_name = Unicode('DateWidgetModel')\n", | |
827 | " default_view_name = Unicode('DatePickerView')\n", |
|
753 | " default_view_name = Unicode('DatePickerView')\n", | |
828 | " \n", |
|
754 | " \n", | |
829 | " # Define the custom state properties to sync with the front-end\n", |
|
755 | " # Define the custom state properties to sync with the front-end\n", | |
830 | " _keys = ['value']\n", |
|
756 | " _keys = ['value']\n", | |
831 | " value = Unicode()\n", |
|
757 | " value = Unicode()\n", | |
832 | " \n", |
|
758 | " \n", | |
833 | " # This function automatically gets called by the traitlet machinery when\n", |
|
759 | " # This function automatically gets called by the traitlet machinery when\n", | |
834 | " # value is modified because of this function's name.\n", |
|
760 | " # value is modified because of this function's name.\n", | |
835 | " def _value_changed(self, name, old_value, new_value):\n", |
|
761 | " def _value_changed(self, name, old_value, new_value):\n", | |
836 | " pass\n", |
|
762 | " pass\n", | |
837 | " " |
|
763 | " " | |
838 | ], |
|
764 | ], | |
839 | "language": "python", |
|
765 | "language": "python", | |
840 | "metadata": {}, |
|
766 | "metadata": {}, | |
841 | "outputs": [], |
|
767 | "outputs": [], | |
842 | "prompt_number": 15 |
|
768 | "prompt_number": 15 | |
843 | }, |
|
769 | }, | |
844 | { |
|
770 | { | |
845 | "cell_type": "markdown", |
|
771 | "cell_type": "markdown", | |
846 | "metadata": {}, |
|
772 | "metadata": {}, | |
847 | "source": [ |
|
773 | "source": [ | |
848 | "Now the function that parses the date string and only sets it in the correct format can be added." |
|
774 | "Now the function that parses the date string and only sets it in the correct format can be added." | |
849 | ] |
|
775 | ] | |
850 | }, |
|
776 | }, | |
851 | { |
|
777 | { | |
852 | "cell_type": "code", |
|
778 | "cell_type": "code", | |
853 | "collapsed": false, |
|
779 | "collapsed": false, | |
854 | "input": [ |
|
780 | "input": [ | |
855 | "# Import the dateutil library to parse date strings.\n", |
|
781 | "# Import the dateutil library to parse date strings.\n", | |
856 | "from dateutil import parser\n", |
|
782 | "from dateutil import parser\n", | |
857 | "\n", |
|
783 | "\n", | |
858 | "# Import the base Widget class and the traitlets Unicode class.\n", |
|
784 | "# Import the base Widget class and the traitlets Unicode class.\n", | |
859 | "from IPython.html.widgets import Widget\n", |
|
785 | "from IPython.html.widgets import Widget\n", | |
860 | "from IPython.utils.traitlets import Unicode\n", |
|
786 | "from IPython.utils.traitlets import Unicode\n", | |
861 | "\n", |
|
787 | "\n", | |
862 | "# Define our DateWidget and its target model and default view.\n", |
|
788 | "# Define our DateWidget and its target model and default view.\n", | |
863 | "class DateWidget(Widget):\n", |
|
789 | "class DateWidget(Widget):\n", | |
864 | " target_name = Unicode('DateWidgetModel')\n", |
|
790 | " target_name = Unicode('DateWidgetModel')\n", | |
865 | " default_view_name = Unicode('DatePickerView')\n", |
|
791 | " default_view_name = Unicode('DatePickerView')\n", | |
866 | " \n", |
|
792 | " \n", | |
867 | " # Define the custom state properties to sync with the front-end\n", |
|
793 | " # Define the custom state properties to sync with the front-end\n", | |
868 | " _keys = ['value']\n", |
|
794 | " _keys = ['value']\n", | |
869 | " value = Unicode()\n", |
|
795 | " value = Unicode()\n", | |
870 | " \n", |
|
796 | " \n", | |
871 | " # This function automatically gets called by the traitlet machinery when\n", |
|
797 | " # This function automatically gets called by the traitlet machinery when\n", | |
872 | " # value is modified because of this function's name.\n", |
|
798 | " # value is modified because of this function's name.\n", | |
873 | " def _value_changed(self, name, old_value, new_value):\n", |
|
799 | " def _value_changed(self, name, old_value, new_value):\n", | |
874 | " \n", |
|
800 | " \n", | |
875 | " # Parse the date time value.\n", |
|
801 | " # Parse the date time value.\n", | |
876 | " try:\n", |
|
802 | " try:\n", | |
877 | " parsed_date = parser.parse(new_value)\n", |
|
803 | " parsed_date = parser.parse(new_value)\n", | |
878 | " parsed_date_string = parsed_date.strftime(\"%Y-%m-%d\")\n", |
|
804 | " parsed_date_string = parsed_date.strftime(\"%Y-%m-%d\")\n", | |
879 | " except:\n", |
|
805 | " except:\n", | |
880 | " parsed_date_string = ''\n", |
|
806 | " parsed_date_string = ''\n", | |
881 | " \n", |
|
807 | " \n", | |
882 | " # Set the parsed date string if the current date string is different.\n", |
|
808 | " # Set the parsed date string if the current date string is different.\n", | |
883 | " if self.value != parsed_date_string:\n", |
|
809 | " if self.value != parsed_date_string:\n", | |
884 | " self.value = parsed_date_string" |
|
810 | " self.value = parsed_date_string" | |
885 | ], |
|
811 | ], | |
886 | "language": "python", |
|
812 | "language": "python", | |
887 | "metadata": {}, |
|
813 | "metadata": {}, | |
888 | "outputs": [], |
|
814 | "outputs": [], | |
889 | "prompt_number": 16 |
|
815 | "prompt_number": 16 | |
890 | }, |
|
816 | }, | |
891 | { |
|
817 | { | |
892 | "cell_type": "markdown", |
|
818 | "cell_type": "markdown", | |
893 | "metadata": {}, |
|
819 | "metadata": {}, | |
894 | "source": [ |
|
820 | "source": [ | |
895 | "The standard property name used for widget labels is `description`. In the code block below, `description` has been added to the Python widget." |
|
821 | "The standard property name used for widget labels is `description`. In the code block below, `description` has been added to the Python widget." | |
896 | ] |
|
822 | ] | |
897 | }, |
|
823 | }, | |
898 | { |
|
824 | { | |
899 | "cell_type": "code", |
|
825 | "cell_type": "code", | |
900 | "collapsed": false, |
|
826 | "collapsed": false, | |
901 | "input": [ |
|
827 | "input": [ | |
902 | "# Import the dateutil library to parse date strings.\n", |
|
828 | "# Import the dateutil library to parse date strings.\n", | |
903 | "from dateutil import parser\n", |
|
829 | "from dateutil import parser\n", | |
904 | "\n", |
|
830 | "\n", | |
905 | "# Import the base Widget class and the traitlets Unicode class.\n", |
|
831 | "# Import the base Widget class and the traitlets Unicode class.\n", | |
906 | "from IPython.html.widgets import Widget\n", |
|
832 | "from IPython.html.widgets import Widget\n", | |
907 | "from IPython.utils.traitlets import Unicode\n", |
|
833 | "from IPython.utils.traitlets import Unicode\n", | |
908 | "\n", |
|
834 | "\n", | |
909 | "# Define our DateWidget and its target model and default view.\n", |
|
835 | "# Define our DateWidget and its target model and default view.\n", | |
910 | "class DateWidget(Widget):\n", |
|
836 | "class DateWidget(Widget):\n", | |
911 | " target_name = Unicode('DateWidgetModel')\n", |
|
837 | " target_name = Unicode('DateWidgetModel')\n", | |
912 | " default_view_name = Unicode('DatePickerView')\n", |
|
838 | " default_view_name = Unicode('DatePickerView')\n", | |
913 | " \n", |
|
839 | " \n", | |
914 | " # Define the custom state properties to sync with the front-end\n", |
|
840 | " # Define the custom state properties to sync with the front-end\n", | |
915 | " _keys = ['value', 'description']\n", |
|
841 | " _keys = ['value', 'description']\n", | |
916 | " value = Unicode()\n", |
|
842 | " value = Unicode()\n", | |
917 | " description = Unicode()\n", |
|
843 | " description = Unicode()\n", | |
918 | " \n", |
|
844 | " \n", | |
919 | " # This function automatically gets called by the traitlet machinery when\n", |
|
845 | " # This function automatically gets called by the traitlet machinery when\n", | |
920 | " # value is modified because of this function's name.\n", |
|
846 | " # value is modified because of this function's name.\n", | |
921 | " def _value_changed(self, name, old_value, new_value):\n", |
|
847 | " def _value_changed(self, name, old_value, new_value):\n", | |
922 | " \n", |
|
848 | " \n", | |
923 | " # Parse the date time value.\n", |
|
849 | " # Parse the date time value.\n", | |
924 | " try:\n", |
|
850 | " try:\n", | |
925 | " parsed_date = parser.parse(new_value)\n", |
|
851 | " parsed_date = parser.parse(new_value)\n", | |
926 | " parsed_date_string = parsed_date.strftime(\"%Y-%m-%d\")\n", |
|
852 | " parsed_date_string = parsed_date.strftime(\"%Y-%m-%d\")\n", | |
927 | " except:\n", |
|
853 | " except:\n", | |
928 | " parsed_date_string = ''\n", |
|
854 | " parsed_date_string = ''\n", | |
929 | " \n", |
|
855 | " \n", | |
930 | " # Set the parsed date string if the current date string is different.\n", |
|
856 | " # Set the parsed date string if the current date string is different.\n", | |
931 | " if self.value != parsed_date_string:\n", |
|
857 | " if self.value != parsed_date_string:\n", | |
932 | " self.value = parsed_date_string" |
|
858 | " self.value = parsed_date_string" | |
933 | ], |
|
859 | ], | |
934 | "language": "python", |
|
860 | "language": "python", | |
935 | "metadata": {}, |
|
861 | "metadata": {}, | |
936 | "outputs": [], |
|
862 | "outputs": [], | |
937 | "prompt_number": 17 |
|
863 | "prompt_number": 17 | |
938 | }, |
|
864 | }, | |
939 | { |
|
865 | { | |
940 | "cell_type": "markdown", |
|
866 | "cell_type": "markdown", | |
941 | "metadata": {}, |
|
867 | "metadata": {}, | |
942 | "source": [ |
|
868 | "source": [ | |
943 | "Finally, a callback list is added so the user can perform custom validation. If any one of the callbacks returns False, the new date time is not set.\n", |
|
869 | "Finally, a callback list is added so the user can perform custom validation. If any one of the callbacks returns False, the new date time is not set.\n", | |
944 | "\n", |
|
870 | "\n", | |
945 | "**Final Python code below:**" |
|
871 | "**Final Python code below:**" | |
946 | ] |
|
872 | ] | |
947 | }, |
|
873 | }, | |
948 | { |
|
874 | { | |
949 | "cell_type": "code", |
|
875 | "cell_type": "code", | |
950 | "collapsed": false, |
|
876 | "collapsed": false, | |
951 | "input": [ |
|
877 | "input": [ | |
952 | "# Import the dateutil library to parse date strings.\n", |
|
878 | "# Import the dateutil library to parse date strings.\n", | |
953 | "from dateutil import parser\n", |
|
879 | "from dateutil import parser\n", | |
954 | "\n", |
|
880 | "\n", | |
955 | "# Import the base Widget class and the traitlets Unicode class.\n", |
|
881 | "# Import the base Widget class and the traitlets Unicode class.\n", | |
956 | "from IPython.html.widgets import Widget\n", |
|
882 | "from IPython.html.widgets import Widget\n", | |
957 | "from IPython.utils.traitlets import Unicode\n", |
|
883 | "from IPython.utils.traitlets import Unicode\n", | |
958 | "\n", |
|
884 | "\n", | |
959 | "# Define our DateWidget and its target model and default view.\n", |
|
885 | "# Define our DateWidget and its target model and default view.\n", | |
960 | "class DateWidget(Widget):\n", |
|
886 | "class DateWidget(Widget):\n", | |
961 | " target_name = Unicode('DateWidgetModel')\n", |
|
887 | " target_name = Unicode('DateWidgetModel')\n", | |
962 | " default_view_name = Unicode('DatePickerView')\n", |
|
888 | " default_view_name = Unicode('DatePickerView')\n", | |
963 | " \n", |
|
889 | " \n", | |
964 | " # Define the custom state properties to sync with the front-end\n", |
|
890 | " # Define the custom state properties to sync with the front-end\n", | |
965 | " _keys = ['value', 'description']\n", |
|
891 | " _keys = ['value', 'description']\n", | |
966 | " value = Unicode()\n", |
|
892 | " value = Unicode()\n", | |
967 | " description = Unicode()\n", |
|
893 | " description = Unicode()\n", | |
968 | " \n", |
|
894 | " \n", | |
969 | " def __init__(self, **kwargs):\n", |
|
895 | " def __init__(self, **kwargs):\n", | |
970 | " super(DateWidget, self).__init__(**kwargs)\n", |
|
896 | " super(DateWidget, self).__init__(**kwargs)\n", | |
971 | " self._validation_callbacks = []\n", |
|
897 | " self._validation_callbacks = []\n", | |
972 | " \n", |
|
898 | " \n", | |
973 | " # This function automatically gets called by the traitlet machinery when\n", |
|
899 | " # This function automatically gets called by the traitlet machinery when\n", | |
974 | " # value is modified because of this function's name.\n", |
|
900 | " # value is modified because of this function's name.\n", | |
975 | " def _value_changed(self, name, old_value, new_value):\n", |
|
901 | " def _value_changed(self, name, old_value, new_value):\n", | |
976 | " \n", |
|
902 | " \n", | |
977 | " # Parse the date time value.\n", |
|
903 | " # Parse the date time value.\n", | |
978 | " try:\n", |
|
904 | " try:\n", | |
979 | " parsed_date = parser.parse(new_value)\n", |
|
905 | " parsed_date = parser.parse(new_value)\n", | |
980 | " parsed_date_string = parsed_date.strftime(\"%Y-%m-%d\")\n", |
|
906 | " parsed_date_string = parsed_date.strftime(\"%Y-%m-%d\")\n", | |
981 | " except:\n", |
|
907 | " except:\n", | |
982 | " parsed_date = None\n", |
|
908 | " parsed_date = None\n", | |
983 | " parsed_date_string = ''\n", |
|
909 | " parsed_date_string = ''\n", | |
984 | " \n", |
|
910 | " \n", | |
985 | " # Set the parsed date string if the current date string is different.\n", |
|
911 | " # Set the parsed date string if the current date string is different.\n", | |
986 | " if old_value != new_value:\n", |
|
912 | " if old_value != new_value:\n", | |
987 | " if self.handle_validate(parsed_date):\n", |
|
913 | " if self.handle_validate(parsed_date):\n", | |
988 | " self.value = parsed_date_string\n", |
|
914 | " self.value = parsed_date_string\n", | |
989 | " else:\n", |
|
915 | " else:\n", | |
990 | " self.value = old_value\n", |
|
916 | " self.value = old_value\n", | |
991 | " self.send_state() # The traitlet event won't fire since the value isn't changing.\n", |
|
917 | " self.send_state() # The traitlet event won't fire since the value isn't changing.\n", | |
992 | " # We need to force the back-end to send the front-end the state\n", |
|
918 | " # We need to force the back-end to send the front-end the state\n", | |
993 | " # to make sure that the date control date doesn't change.\n", |
|
919 | " # to make sure that the date control date doesn't change.\n", | |
994 | " \n", |
|
920 | " \n", | |
995 | " \n", |
|
921 | " \n", | |
996 | " # Allow the user to register custom validation callbacks.\n", |
|
922 | " # Allow the user to register custom validation callbacks.\n", | |
997 | " # callback(new value as a datetime object)\n", |
|
923 | " # callback(new value as a datetime object)\n", | |
998 | " def on_validate(self, callback, remove=False):\n", |
|
924 | " def on_validate(self, callback, remove=False):\n", | |
999 | " if remove and callback in self._validation_callbacks:\n", |
|
925 | " if remove and callback in self._validation_callbacks:\n", | |
1000 | " self._validation_callbacks.remove(callback)\n", |
|
926 | " self._validation_callbacks.remove(callback)\n", | |
1001 | " elif (not remove) and (not callback in self._validation_callbacks):\n", |
|
927 | " elif (not remove) and (not callback in self._validation_callbacks):\n", | |
1002 | " self._validation_callbacks.append(callback)\n", |
|
928 | " self._validation_callbacks.append(callback)\n", | |
1003 | " \n", |
|
929 | " \n", | |
1004 | " # Call user validation callbacks. Return True if valid.\n", |
|
930 | " # Call user validation callbacks. Return True if valid.\n", | |
1005 | " def handle_validate(self, new_value):\n", |
|
931 | " def handle_validate(self, new_value):\n", | |
1006 | " for callback in self._validation_callbacks:\n", |
|
932 | " for callback in self._validation_callbacks:\n", | |
1007 | " if not callback(new_value):\n", |
|
933 | " if not callback(new_value):\n", | |
1008 | " return False\n", |
|
934 | " return False\n", | |
1009 | " return True\n", |
|
935 | " return True\n", | |
1010 | " " |
|
936 | " " | |
1011 | ], |
|
937 | ], | |
1012 | "language": "python", |
|
938 | "language": "python", | |
1013 | "metadata": {}, |
|
939 | "metadata": {}, | |
1014 | "outputs": [], |
|
940 | "outputs": [], | |
1015 | "prompt_number": 18 |
|
941 | "prompt_number": 18 | |
1016 | }, |
|
942 | }, | |
1017 | { |
|
943 | { | |
1018 | "cell_type": "heading", |
|
944 | "cell_type": "heading", | |
1019 | "level": 2, |
|
945 | "level": 2, | |
1020 | "metadata": {}, |
|
946 | "metadata": {}, | |
1021 | "source": [ |
|
947 | "source": [ | |
1022 | "JavaScript" |
|
948 | "JavaScript" | |
1023 | ] |
|
949 | ] | |
1024 | }, |
|
950 | }, | |
1025 | { |
|
951 | { | |
1026 | "cell_type": "markdown", |
|
952 | "cell_type": "markdown", | |
1027 | "metadata": {}, |
|
953 | "metadata": {}, | |
1028 | "source": [ |
|
954 | "source": [ | |
1029 | "Using the Javascript code from the last section, we add a label to the date time object. The label is a div with the `widget-hlabel` class applied to it. The `widget-hlabel` is a class provided by the widget framework that applies special styling to a div to make it look like the rest of the horizontal labels used with the built in widgets. Similar to the `widget-hlabel` class is the `widget-hbox-single` class. The `widget-hbox-single` class applies special styling to widget containers that store a single line horizontal widget. \n", |
|
955 | "Using the Javascript code from the last section, we add a label to the date time object. The label is a div with the `widget-hlabel` class applied to it. The `widget-hlabel` is a class provided by the widget framework that applies special styling to a div to make it look like the rest of the horizontal labels used with the built in widgets. Similar to the `widget-hlabel` class is the `widget-hbox-single` class. The `widget-hbox-single` class applies special styling to widget containers that store a single line horizontal widget. \n", | |
1030 | "\n", |
|
956 | "\n", | |
1031 | "We hide the label if the description value is blank." |
|
957 | "We hide the label if the description value is blank." | |
1032 | ] |
|
958 | ] | |
1033 | }, |
|
959 | }, | |
1034 | { |
|
960 | { | |
1035 | "cell_type": "code", |
|
961 | "cell_type": "code", | |
1036 | "collapsed": false, |
|
962 | "collapsed": false, | |
1037 | "input": [ |
|
963 | "input": [ | |
1038 | "%%javascript\n", |
|
964 | "%%javascript\n", | |
1039 | "\n", |
|
965 | "\n", | |
1040 | "require([\"notebook/js/widget\"], function(){\n", |
|
966 | "require([\"notebook/js/widget\"], function(){\n", | |
1041 | " \n", |
|
967 | " \n", | |
1042 | " // Define the DateModel and register it with the widget manager.\n", |
|
968 | " // Define the DateModel and register it with the widget manager.\n", | |
1043 | " var DateModel = IPython.WidgetModel.extend({});\n", |
|
969 | " var DateModel = IPython.WidgetModel.extend({});\n", | |
1044 |
" IPython. |
|
970 | " IPython.widget_manager.register_widget_model('DateWidgetModel', DateModel);\n", | |
1045 | " \n", |
|
971 | " \n", | |
1046 | " // Define the DatePickerView\n", |
|
972 | " // Define the DatePickerView\n", | |
1047 | " var DatePickerView = IPython.WidgetView.extend({\n", |
|
973 | " var DatePickerView = IPython.WidgetView.extend({\n", | |
1048 | " \n", |
|
974 | " \n", | |
1049 | " render: function(){\n", |
|
975 | " render: function(){\n", | |
1050 | " \n", |
|
976 | " \n", | |
1051 | " // Create a div to hold our widget.\n", |
|
977 | " // Create a div to hold our widget.\n", | |
1052 | " this.$el = $('<div />')\n", |
|
978 | " this.$el = $('<div />')\n", | |
1053 | " .addClass('widget-hbox-single'); // Apply this class to the widget container to make\n", |
|
979 | " .addClass('widget-hbox-single'); // Apply this class to the widget container to make\n", | |
1054 | " // it fit with the other built in widgets.\n", |
|
980 | " // it fit with the other built in widgets.\n", | |
1055 | " this.delegateEvents();\n", |
|
981 | " this.delegateEvents();\n", | |
1056 | " \n", |
|
982 | " \n", | |
1057 | " // Create a label.\n", |
|
983 | " // Create a label.\n", | |
1058 | " this.$label = $('<div />')\n", |
|
984 | " this.$label = $('<div />')\n", | |
1059 | " .addClass('widget-hlabel')\n", |
|
985 | " .addClass('widget-hlabel')\n", | |
1060 | " .appendTo(this.$el)\n", |
|
986 | " .appendTo(this.$el)\n", | |
1061 | " .hide(); // Hide the label by default.\n", |
|
987 | " .hide(); // Hide the label by default.\n", | |
1062 | " \n", |
|
988 | " \n", | |
1063 | " // Create the date picker control.\n", |
|
989 | " // Create the date picker control.\n", | |
1064 | " this.$date = $('<input />')\n", |
|
990 | " this.$date = $('<input />')\n", | |
1065 | " .attr('type', 'date')\n", |
|
991 | " .attr('type', 'date')\n", | |
1066 | " .appendTo(this.$el);\n", |
|
992 | " .appendTo(this.$el);\n", | |
1067 | " },\n", |
|
993 | " },\n", | |
1068 | " \n", |
|
994 | " \n", | |
1069 | " update: function() {\n", |
|
995 | " update: function() {\n", | |
1070 | " \n", |
|
996 | " \n", | |
1071 | " // Set the value of the date control and then call base.\n", |
|
997 | " // Set the value of the date control and then call base.\n", | |
1072 | " this.$date.val(this.model.get('value')); // ISO format \"YYYY-MM-DDTHH:mm:ss.sssZ\" is required\n", |
|
998 | " this.$date.val(this.model.get('value')); // ISO format \"YYYY-MM-DDTHH:mm:ss.sssZ\" is required\n", | |
1073 | " \n", |
|
999 | " \n", | |
1074 | " // Hide or show the label depending on the existance of a description.\n", |
|
1000 | " // Hide or show the label depending on the existance of a description.\n", | |
1075 | " var description = this.model.get('description');\n", |
|
1001 | " var description = this.model.get('description');\n", | |
1076 | " if (description == undefined || description == '') {\n", |
|
1002 | " if (description == undefined || description == '') {\n", | |
1077 | " this.$label.hide();\n", |
|
1003 | " this.$label.hide();\n", | |
1078 | " } else {\n", |
|
1004 | " } else {\n", | |
1079 | " this.$label.show();\n", |
|
1005 | " this.$label.show();\n", | |
1080 | " this.$label.html(description);\n", |
|
1006 | " this.$label.html(description);\n", | |
1081 | " }\n", |
|
1007 | " }\n", | |
1082 | " \n", |
|
1008 | " \n", | |
1083 | " return IPython.WidgetView.prototype.update.call(this);\n", |
|
1009 | " return IPython.WidgetView.prototype.update.call(this);\n", | |
1084 | " },\n", |
|
1010 | " },\n", | |
1085 | " \n", |
|
1011 | " \n", | |
1086 | " // Tell Backbone to listen to the change event of input controls (which the HTML date picker is)\n", |
|
1012 | " // Tell Backbone to listen to the change event of input controls (which the HTML date picker is)\n", | |
1087 | " events: {\"change\": \"handle_date_change\"},\n", |
|
1013 | " events: {\"change\": \"handle_date_change\"},\n", | |
1088 | " \n", |
|
1014 | " \n", | |
1089 | " // Callback for when the date is changed.\n", |
|
1015 | " // Callback for when the date is changed.\n", | |
1090 | " handle_date_change: function(event) {\n", |
|
1016 | " handle_date_change: function(event) {\n", | |
1091 | " this.model.set('value', this.$date.val());\n", |
|
1017 | " this.model.set('value', this.$date.val());\n", | |
1092 | " this.model.update_other_views(this);\n", |
|
1018 | " this.model.update_other_views(this);\n", | |
1093 | " },\n", |
|
1019 | " },\n", | |
1094 | " \n", |
|
1020 | " \n", | |
1095 | " });\n", |
|
1021 | " });\n", | |
1096 | " \n", |
|
1022 | " \n", | |
1097 | " // Register the DatePickerView with the widget manager.\n", |
|
1023 | " // Register the DatePickerView with the widget manager.\n", | |
1098 |
" IPython. |
|
1024 | " IPython.widget_manager.register_widget_view('DatePickerView', DatePickerView);\n", | |
1099 | "});" |
|
1025 | "});" | |
1100 | ], |
|
1026 | ], | |
1101 | "language": "python", |
|
1027 | "language": "python", | |
1102 | "metadata": {}, |
|
1028 | "metadata": {}, | |
1103 | "outputs": [ |
|
1029 | "outputs": [ | |
1104 | { |
|
1030 | { | |
1105 | "javascript": [ |
|
1031 | "javascript": [ | |
1106 | "\n", |
|
1032 | "\n", | |
1107 | "require([\"notebook/js/widget\"], function(){\n", |
|
1033 | "require([\"notebook/js/widget\"], function(){\n", | |
1108 | " \n", |
|
1034 | " \n", | |
1109 | " // Define the DateModel and register it with the widget manager.\n", |
|
1035 | " // Define the DateModel and register it with the widget manager.\n", | |
1110 | " var DateModel = IPython.WidgetModel.extend({});\n", |
|
1036 | " var DateModel = IPython.WidgetModel.extend({});\n", | |
1111 |
" IPython. |
|
1037 | " IPython.widget_manager.register_widget_model('DateWidgetModel', DateModel);\n", | |
1112 | " \n", |
|
1038 | " \n", | |
1113 | " // Define the DatePickerView\n", |
|
1039 | " // Define the DatePickerView\n", | |
1114 | " var DatePickerView = IPython.WidgetView.extend({\n", |
|
1040 | " var DatePickerView = IPython.WidgetView.extend({\n", | |
1115 | " \n", |
|
1041 | " \n", | |
1116 | " render: function(){\n", |
|
1042 | " render: function(){\n", | |
1117 | " \n", |
|
1043 | " \n", | |
1118 | " // Create a div to hold our widget.\n", |
|
1044 | " // Create a div to hold our widget.\n", | |
1119 | " this.$el = $('<div />')\n", |
|
1045 | " this.$el = $('<div />')\n", | |
1120 | " .addClass('widget-hbox-single'); // Apply this class to the widget container to make\n", |
|
1046 | " .addClass('widget-hbox-single'); // Apply this class to the widget container to make\n", | |
1121 | " // it fit with the other built in widgets.\n", |
|
1047 | " // it fit with the other built in widgets.\n", | |
1122 | " this.delegateEvents();\n", |
|
1048 | " this.delegateEvents();\n", | |
1123 | " \n", |
|
1049 | " \n", | |
1124 | " // Create a label.\n", |
|
1050 | " // Create a label.\n", | |
1125 | " this.$label = $('<div />')\n", |
|
1051 | " this.$label = $('<div />')\n", | |
1126 | " .addClass('widget-hlabel')\n", |
|
1052 | " .addClass('widget-hlabel')\n", | |
1127 | " .appendTo(this.$el)\n", |
|
1053 | " .appendTo(this.$el)\n", | |
1128 | " .hide(); // Hide the label by default.\n", |
|
1054 | " .hide(); // Hide the label by default.\n", | |
1129 | " \n", |
|
1055 | " \n", | |
1130 | " // Create the date picker control.\n", |
|
1056 | " // Create the date picker control.\n", | |
1131 | " this.$date = $('<input />')\n", |
|
1057 | " this.$date = $('<input />')\n", | |
1132 | " .attr('type', 'date')\n", |
|
1058 | " .attr('type', 'date')\n", | |
1133 | " .appendTo(this.$el);\n", |
|
1059 | " .appendTo(this.$el);\n", | |
1134 | " },\n", |
|
1060 | " },\n", | |
1135 | " \n", |
|
1061 | " \n", | |
1136 | " update: function() {\n", |
|
1062 | " update: function() {\n", | |
1137 | " \n", |
|
1063 | " \n", | |
1138 | " // Set the value of the date control and then call base.\n", |
|
1064 | " // Set the value of the date control and then call base.\n", | |
1139 | " this.$date.val(this.model.get('value')); // ISO format \"YYYY-MM-DDTHH:mm:ss.sssZ\" is required\n", |
|
1065 | " this.$date.val(this.model.get('value')); // ISO format \"YYYY-MM-DDTHH:mm:ss.sssZ\" is required\n", | |
1140 | " \n", |
|
1066 | " \n", | |
1141 | " // Hide or show the label depending on the existance of a description.\n", |
|
1067 | " // Hide or show the label depending on the existance of a description.\n", | |
1142 | " var description = this.model.get('description');\n", |
|
1068 | " var description = this.model.get('description');\n", | |
1143 | " if (description == undefined || description == '') {\n", |
|
1069 | " if (description == undefined || description == '') {\n", | |
1144 | " this.$label.hide();\n", |
|
1070 | " this.$label.hide();\n", | |
1145 | " } else {\n", |
|
1071 | " } else {\n", | |
1146 | " this.$label.show();\n", |
|
1072 | " this.$label.show();\n", | |
1147 | " this.$label.html(description);\n", |
|
1073 | " this.$label.html(description);\n", | |
1148 | " }\n", |
|
1074 | " }\n", | |
1149 | " \n", |
|
1075 | " \n", | |
1150 | " return IPython.WidgetView.prototype.update.call(this);\n", |
|
1076 | " return IPython.WidgetView.prototype.update.call(this);\n", | |
1151 | " },\n", |
|
1077 | " },\n", | |
1152 | " \n", |
|
1078 | " \n", | |
1153 | " // Tell Backbone to listen to the change event of input controls (which the HTML date picker is)\n", |
|
1079 | " // Tell Backbone to listen to the change event of input controls (which the HTML date picker is)\n", | |
1154 | " events: {\"change\": \"handle_date_change\"},\n", |
|
1080 | " events: {\"change\": \"handle_date_change\"},\n", | |
1155 | " \n", |
|
1081 | " \n", | |
1156 | " // Callback for when the date is changed.\n", |
|
1082 | " // Callback for when the date is changed.\n", | |
1157 | " handle_date_change: function(event) {\n", |
|
1083 | " handle_date_change: function(event) {\n", | |
1158 | " this.model.set('value', this.$date.val());\n", |
|
1084 | " this.model.set('value', this.$date.val());\n", | |
1159 | " this.model.update_other_views(this);\n", |
|
1085 | " this.model.update_other_views(this);\n", | |
1160 | " },\n", |
|
1086 | " },\n", | |
1161 | " \n", |
|
1087 | " \n", | |
1162 | " });\n", |
|
1088 | " });\n", | |
1163 | " \n", |
|
1089 | " \n", | |
1164 | " // Register the DatePickerView with the widget manager.\n", |
|
1090 | " // Register the DatePickerView with the widget manager.\n", | |
1165 |
" IPython. |
|
1091 | " IPython.widget_manager.register_widget_view('DatePickerView', DatePickerView);\n", | |
1166 | "});" |
|
1092 | "});" | |
1167 | ], |
|
1093 | ], | |
1168 | "metadata": {}, |
|
1094 | "metadata": {}, | |
1169 | "output_type": "display_data", |
|
1095 | "output_type": "display_data", | |
1170 | "text": [ |
|
1096 | "text": [ | |
1171 |
"<IPython.core.display.Javascript at 0x |
|
1097 | "<IPython.core.display.Javascript at 0x221a850>" | |
1172 | ] |
|
1098 | ] | |
1173 | } |
|
1099 | } | |
1174 | ], |
|
1100 | ], | |
1175 | "prompt_number": 19 |
|
1101 | "prompt_number": 19 | |
1176 | }, |
|
1102 | }, | |
1177 | { |
|
1103 | { | |
1178 | "cell_type": "heading", |
|
1104 | "cell_type": "heading", | |
1179 | "level": 2, |
|
1105 | "level": 2, | |
1180 | "metadata": {}, |
|
1106 | "metadata": {}, | |
1181 | "source": [ |
|
1107 | "source": [ | |
1182 | "Test" |
|
1108 | "Test" | |
1183 | ] |
|
1109 | ] | |
1184 | }, |
|
1110 | }, | |
1185 | { |
|
1111 | { | |
1186 | "cell_type": "markdown", |
|
1112 | "cell_type": "markdown", | |
1187 | "metadata": {}, |
|
1113 | "metadata": {}, | |
1188 | "source": [ |
|
1114 | "source": [ | |
1189 | "To test the drawing of the label we create the widget like normal but supply the additional description property a value." |
|
1115 | "To test the drawing of the label we create the widget like normal but supply the additional description property a value." | |
1190 | ] |
|
1116 | ] | |
1191 | }, |
|
1117 | }, | |
1192 | { |
|
1118 | { | |
1193 | "cell_type": "code", |
|
1119 | "cell_type": "code", | |
1194 | "collapsed": false, |
|
1120 | "collapsed": false, | |
1195 | "input": [ |
|
1121 | "input": [ | |
1196 | "# Add some additional widgets for aesthetic purpose\n", |
|
1122 | "# Add some additional widgets for aesthetic purpose\n", | |
1197 | "display(widgets.StringWidget(description=\"First:\"))\n", |
|
1123 | "display(widgets.StringWidget(description=\"First:\"))\n", | |
1198 | "display(widgets.StringWidget(description=\"Last:\"))\n", |
|
1124 | "display(widgets.StringWidget(description=\"Last:\"))\n", | |
1199 | "\n", |
|
1125 | "\n", | |
1200 | "my_widget = DateWidget(description=\"DOB:\")\n", |
|
1126 | "my_widget = DateWidget(description=\"DOB:\")\n", | |
1201 | "display(my_widget)" |
|
1127 | "display(my_widget)" | |
1202 | ], |
|
1128 | ], | |
1203 | "language": "python", |
|
1129 | "language": "python", | |
1204 | "metadata": {}, |
|
1130 | "metadata": {}, | |
1205 | "outputs": [], |
|
1131 | "outputs": [], | |
1206 | "prompt_number": 20 |
|
1132 | "prompt_number": 20 | |
1207 | }, |
|
1133 | }, | |
1208 | { |
|
1134 | { | |
1209 | "cell_type": "markdown", |
|
1135 | "cell_type": "markdown", | |
1210 | "metadata": {}, |
|
1136 | "metadata": {}, | |
1211 | "source": [ |
|
1137 | "source": [ | |
1212 | "Since the date widget uses `value` and `description`, we can also display its value using a `TextBoxView`. The allows us to look at the raw date value being passed to and from the back-end and front-end." |
|
1138 | "Since the date widget uses `value` and `description`, we can also display its value using a `TextBoxView`. The allows us to look at the raw date value being passed to and from the back-end and front-end." | |
1213 | ] |
|
1139 | ] | |
1214 | }, |
|
1140 | }, | |
1215 | { |
|
1141 | { | |
1216 | "cell_type": "code", |
|
1142 | "cell_type": "code", | |
1217 | "collapsed": false, |
|
1143 | "collapsed": false, | |
1218 | "input": [ |
|
1144 | "input": [ | |
1219 | "\n", |
|
|||
1220 | "display(my_widget, view_name=\"TextBoxView\")" |
|
1145 | "display(my_widget, view_name=\"TextBoxView\")" | |
1221 | ], |
|
1146 | ], | |
1222 | "language": "python", |
|
1147 | "language": "python", | |
1223 | "metadata": {}, |
|
1148 | "metadata": {}, | |
1224 | "outputs": [], |
|
1149 | "outputs": [], | |
1225 | "prompt_number": 21 |
|
1150 | "prompt_number": 21 | |
1226 | }, |
|
1151 | }, | |
1227 | { |
|
1152 | { | |
1228 | "cell_type": "markdown", |
|
1153 | "cell_type": "markdown", | |
1229 | "metadata": {}, |
|
1154 | "metadata": {}, | |
1230 | "source": [ |
|
1155 | "source": [ | |
1231 | "Now we will try to create a widget that only accepts dates in the year 2013. We render the widget without a description to verify that it can still render without a label." |
|
1156 | "Now we will try to create a widget that only accepts dates in the year 2013. We render the widget without a description to verify that it can still render without a label." | |
1232 | ] |
|
1157 | ] | |
1233 | }, |
|
1158 | }, | |
1234 | { |
|
1159 | { | |
1235 | "cell_type": "code", |
|
1160 | "cell_type": "code", | |
1236 | "collapsed": false, |
|
1161 | "collapsed": false, | |
1237 | "input": [ |
|
1162 | "input": [ | |
1238 | "my_widget = DateWidget()\n", |
|
1163 | "my_widget = DateWidget()\n", | |
1239 | "display(my_widget)\n", |
|
1164 | "display(my_widget)\n", | |
1240 | "\n", |
|
1165 | "\n", | |
1241 | "def validate_date(date):\n", |
|
1166 | "def validate_date(date):\n", | |
1242 | " return not date is None and date.year == 2013\n", |
|
1167 | " return not date is None and date.year == 2013\n", | |
1243 | "my_widget.on_validate(validate_date)" |
|
1168 | "my_widget.on_validate(validate_date)" | |
1244 | ], |
|
1169 | ], | |
1245 | "language": "python", |
|
1170 | "language": "python", | |
1246 | "metadata": {}, |
|
1171 | "metadata": {}, | |
1247 | "outputs": [], |
|
1172 | "outputs": [], | |
1248 | "prompt_number": 22 |
|
1173 | "prompt_number": 22 | |
1249 | }, |
|
1174 | }, | |
1250 | { |
|
1175 | { | |
1251 | "cell_type": "code", |
|
1176 | "cell_type": "code", | |
1252 | "collapsed": false, |
|
1177 | "collapsed": false, | |
1253 | "input": [ |
|
1178 | "input": [ | |
1254 | "# Try setting a valid date\n", |
|
1179 | "# Try setting a valid date\n", | |
1255 | "my_widget.value = \"December 2, 2013\"" |
|
1180 | "my_widget.value = \"December 2, 2013\"" | |
1256 | ], |
|
1181 | ], | |
1257 | "language": "python", |
|
1182 | "language": "python", | |
1258 | "metadata": {}, |
|
1183 | "metadata": {}, | |
1259 | "outputs": [], |
|
1184 | "outputs": [], | |
1260 | "prompt_number": 23 |
|
1185 | "prompt_number": 23 | |
1261 | }, |
|
1186 | }, | |
1262 | { |
|
1187 | { | |
1263 | "cell_type": "code", |
|
1188 | "cell_type": "code", | |
1264 | "collapsed": false, |
|
1189 | "collapsed": false, | |
1265 | "input": [ |
|
1190 | "input": [ | |
1266 | "# Try setting an invalid date\n", |
|
1191 | "# Try setting an invalid date\n", | |
1267 | "my_widget.value = \"June 12, 1999\"" |
|
1192 | "my_widget.value = \"June 12, 1999\"" | |
1268 | ], |
|
1193 | ], | |
1269 | "language": "python", |
|
1194 | "language": "python", | |
1270 | "metadata": {}, |
|
1195 | "metadata": {}, | |
1271 | "outputs": [], |
|
1196 | "outputs": [], | |
1272 | "prompt_number": 24 |
|
1197 | "prompt_number": 24 | |
1273 | } |
|
1198 | } | |
1274 | ], |
|
1199 | ], | |
1275 | "metadata": {} |
|
1200 | "metadata": {} | |
1276 | } |
|
1201 | } | |
1277 | ] |
|
1202 | ] | |
1278 | } No newline at end of file |
|
1203 | } |
General Comments 0
You need to be logged in to leave comments.
Login now