##// END OF EJS Templates
Merge pull request #6190 from minrk/bootstrap-shim...
Matthias Bussonnier -
r17314:555f4435 merge
parent child Browse files
Show More
@@ -1,351 +1,351 b''
1 1 // Copyright (c) IPython Development Team.
2 2 // Distributed under the terms of the Modified BSD License.
3 3
4 4 define([
5 5 'base/js/namespace',
6 6 'jquery',
7 7 'base/js/utils',
8 8 'notebook/js/tour',
9 'components/bootstrap/js/bootstrap.min',
9 'bootstrap',
10 10 ], function(IPython, $, utils, tour) {
11 11 "use strict";
12 12
13 13 var MenuBar = function (selector, options) {
14 14 // Constructor
15 15 //
16 16 // A MenuBar Class to generate the menubar of IPython notebook
17 17 //
18 18 // Parameters:
19 19 // selector: string
20 20 // options: dictionary
21 21 // Dictionary of keyword arguments.
22 22 // notebook: Notebook instance
23 23 // layout_manager: LayoutManager instance
24 24 // events: $(Events) instance
25 25 // save_widget: SaveWidget instance
26 26 // quick_help: QuickHelp instance
27 27 // base_url : string
28 28 // notebook_path : string
29 29 // notebook_name : string
30 30 options = options || {};
31 31 this.base_url = options.base_url || utils.get_body_data("baseUrl");
32 32 this.selector = selector;
33 33 this.notebook = options.notebook;
34 34 this.layout_manager = options.layout_manager;
35 35 this.events = options.events;
36 36 this.save_widget = options.save_widget;
37 37 this.quick_help = options.quick_help;
38 38
39 39 try {
40 40 this.tour = new tour.Tour(this.notebook, this.events);
41 41 } catch (e) {
42 42 this.tour = undefined;
43 43 console.log("Failed to instantiate Notebook Tour", e);
44 44 }
45 45
46 46 if (this.selector !== undefined) {
47 47 this.element = $(selector);
48 48 this.style();
49 49 this.bind_events();
50 50 }
51 51 };
52 52
53 53 MenuBar.prototype.style = function () {
54 54 var that = this;
55 55 this.element.addClass('border-box-sizing');
56 56 this.element.find("li").click(function (event, ui) {
57 57 // The selected cell loses focus when the menu is entered, so we
58 58 // re-select it upon selection.
59 59 var i = that.notebook.get_selected_index();
60 60 that.notebook.select(i);
61 61 }
62 62 );
63 63 };
64 64
65 65 MenuBar.prototype._nbconvert = function (format, download) {
66 66 download = download || false;
67 67 var notebook_path = this.notebook.notebook_path;
68 68 var notebook_name = this.notebook.notebook_name;
69 69 if (this.notebook.dirty) {
70 70 this.notebook.save_notebook({async : false});
71 71 }
72 72 var url = utils.url_join_encode(
73 73 this.base_url,
74 74 'nbconvert',
75 75 format,
76 76 notebook_path,
77 77 notebook_name
78 78 ) + "?download=" + download.toString();
79 79
80 80 window.open(url);
81 81 };
82 82
83 83 MenuBar.prototype.bind_events = function () {
84 84 // File
85 85 var that = this;
86 86 this.element.find('#new_notebook').click(function () {
87 87 that.notebook.new_notebook();
88 88 });
89 89 this.element.find('#open_notebook').click(function () {
90 90 window.open(utils.url_join_encode(
91 91 that.notebook.base_url,
92 92 'tree',
93 93 that.notebook.notebook_path
94 94 ));
95 95 });
96 96 this.element.find('#copy_notebook').click(function () {
97 97 that.notebook.copy_notebook();
98 98 return false;
99 99 });
100 100 this.element.find('#download_ipynb').click(function () {
101 101 var base_url = that.notebook.base_url;
102 102 var notebook_path = that.notebook.notebook_path;
103 103 var notebook_name = that.notebook.notebook_name;
104 104 if (that.notebook.dirty) {
105 105 that.notebook.save_notebook({async : false});
106 106 }
107 107
108 108 var url = utils.url_join_encode(
109 109 base_url,
110 110 'files',
111 111 notebook_path,
112 112 notebook_name
113 113 );
114 114 window.location.assign(url);
115 115 });
116 116
117 117 this.element.find('#print_preview').click(function () {
118 118 that._nbconvert('html', false);
119 119 });
120 120
121 121 this.element.find('#download_py').click(function () {
122 122 that._nbconvert('python', true);
123 123 });
124 124
125 125 this.element.find('#download_html').click(function () {
126 126 that._nbconvert('html', true);
127 127 });
128 128
129 129 this.element.find('#download_rst').click(function () {
130 130 that._nbconvert('rst', true);
131 131 });
132 132
133 133 this.element.find('#download_pdf').click(function () {
134 134 that._nbconvert('pdf', true);
135 135 });
136 136
137 137 this.element.find('#rename_notebook').click(function () {
138 138 that.save_widget.rename_notebook({notebook: that.notebook});
139 139 });
140 140 this.element.find('#save_checkpoint').click(function () {
141 141 that.notebook.save_checkpoint();
142 142 });
143 143 this.element.find('#restore_checkpoint').click(function () {
144 144 });
145 145 this.element.find('#trust_notebook').click(function () {
146 146 that.notebook.trust_notebook();
147 147 });
148 148 this.events.on('trust_changed.Notebook', function (event, trusted) {
149 149 if (trusted) {
150 150 that.element.find('#trust_notebook')
151 151 .addClass("disabled")
152 152 .find("a").text("Trusted Notebook");
153 153 } else {
154 154 that.element.find('#trust_notebook')
155 155 .removeClass("disabled")
156 156 .find("a").text("Trust Notebook");
157 157 }
158 158 });
159 159 this.element.find('#kill_and_exit').click(function () {
160 160 that.notebook.session.delete();
161 161 setTimeout(function(){
162 162 // allow closing of new tabs in Chromium, impossible in FF
163 163 window.open('', '_self', '');
164 164 window.close();
165 165 }, 500);
166 166 });
167 167 // Edit
168 168 this.element.find('#cut_cell').click(function () {
169 169 that.notebook.cut_cell();
170 170 });
171 171 this.element.find('#copy_cell').click(function () {
172 172 that.notebook.copy_cell();
173 173 });
174 174 this.element.find('#delete_cell').click(function () {
175 175 that.notebook.delete_cell();
176 176 });
177 177 this.element.find('#undelete_cell').click(function () {
178 178 that.notebook.undelete_cell();
179 179 });
180 180 this.element.find('#split_cell').click(function () {
181 181 that.notebook.split_cell();
182 182 });
183 183 this.element.find('#merge_cell_above').click(function () {
184 184 that.notebook.merge_cell_above();
185 185 });
186 186 this.element.find('#merge_cell_below').click(function () {
187 187 that.notebook.merge_cell_below();
188 188 });
189 189 this.element.find('#move_cell_up').click(function () {
190 190 that.notebook.move_cell_up();
191 191 });
192 192 this.element.find('#move_cell_down').click(function () {
193 193 that.notebook.move_cell_down();
194 194 });
195 195 this.element.find('#edit_nb_metadata').click(function () {
196 196 that.notebook.edit_metadata({
197 197 notebook: that.notebook,
198 198 keyboard_manager: that.notebook.keyboard_manager});
199 199 });
200 200
201 201 // View
202 202 this.element.find('#toggle_header').click(function () {
203 203 $('div#header').toggle();
204 204 that.layout_manager.do_resize();
205 205 });
206 206 this.element.find('#toggle_toolbar').click(function () {
207 207 $('div#maintoolbar').toggle();
208 208 that.layout_manager.do_resize();
209 209 });
210 210 // Insert
211 211 this.element.find('#insert_cell_above').click(function () {
212 212 that.notebook.insert_cell_above('code');
213 213 that.notebook.select_prev();
214 214 });
215 215 this.element.find('#insert_cell_below').click(function () {
216 216 that.notebook.insert_cell_below('code');
217 217 that.notebook.select_next();
218 218 });
219 219 // Cell
220 220 this.element.find('#run_cell').click(function () {
221 221 that.notebook.execute_cell();
222 222 });
223 223 this.element.find('#run_cell_select_below').click(function () {
224 224 that.notebook.execute_cell_and_select_below();
225 225 });
226 226 this.element.find('#run_cell_insert_below').click(function () {
227 227 that.notebook.execute_cell_and_insert_below();
228 228 });
229 229 this.element.find('#run_all_cells').click(function () {
230 230 that.notebook.execute_all_cells();
231 231 });
232 232 this.element.find('#run_all_cells_above').click(function () {
233 233 that.notebook.execute_cells_above();
234 234 });
235 235 this.element.find('#run_all_cells_below').click(function () {
236 236 that.notebook.execute_cells_below();
237 237 });
238 238 this.element.find('#to_code').click(function () {
239 239 that.notebook.to_code();
240 240 });
241 241 this.element.find('#to_markdown').click(function () {
242 242 that.notebook.to_markdown();
243 243 });
244 244 this.element.find('#to_raw').click(function () {
245 245 that.notebook.to_raw();
246 246 });
247 247 this.element.find('#to_heading1').click(function () {
248 248 that.notebook.to_heading(undefined, 1);
249 249 });
250 250 this.element.find('#to_heading2').click(function () {
251 251 that.notebook.to_heading(undefined, 2);
252 252 });
253 253 this.element.find('#to_heading3').click(function () {
254 254 that.notebook.to_heading(undefined, 3);
255 255 });
256 256 this.element.find('#to_heading4').click(function () {
257 257 that.notebook.to_heading(undefined, 4);
258 258 });
259 259 this.element.find('#to_heading5').click(function () {
260 260 that.notebook.to_heading(undefined, 5);
261 261 });
262 262 this.element.find('#to_heading6').click(function () {
263 263 that.notebook.to_heading(undefined, 6);
264 264 });
265 265
266 266 this.element.find('#toggle_current_output').click(function () {
267 267 that.notebook.toggle_output();
268 268 });
269 269 this.element.find('#toggle_current_output_scroll').click(function () {
270 270 that.notebook.toggle_output_scroll();
271 271 });
272 272 this.element.find('#clear_current_output').click(function () {
273 273 that.notebook.clear_output();
274 274 });
275 275
276 276 this.element.find('#toggle_all_output').click(function () {
277 277 that.notebook.toggle_all_output();
278 278 });
279 279 this.element.find('#toggle_all_output_scroll').click(function () {
280 280 that.notebook.toggle_all_output_scroll();
281 281 });
282 282 this.element.find('#clear_all_output').click(function () {
283 283 that.notebook.clear_all_output();
284 284 });
285 285
286 286 // Kernel
287 287 this.element.find('#int_kernel').click(function () {
288 288 that.notebook.session.interrupt_kernel();
289 289 });
290 290 this.element.find('#restart_kernel').click(function () {
291 291 that.notebook.restart_kernel();
292 292 });
293 293 // Help
294 294 if (this.tour) {
295 295 this.element.find('#notebook_tour').click(function () {
296 296 that.tour.start();
297 297 });
298 298 } else {
299 299 this.element.find('#notebook_tour').addClass("disabled");
300 300 }
301 301 this.element.find('#keyboard_shortcuts').click(function () {
302 302 that.quick_help.show_keyboard_shortcuts();
303 303 });
304 304
305 305 this.update_restore_checkpoint(null);
306 306
307 307 this.events.on('checkpoints_listed.Notebook', function (event, data) {
308 308 that.update_restore_checkpoint(that.notebook.checkpoints);
309 309 });
310 310
311 311 this.events.on('checkpoint_created.Notebook', function (event, data) {
312 312 that.update_restore_checkpoint(that.notebook.checkpoints);
313 313 });
314 314 };
315 315
316 316 MenuBar.prototype.update_restore_checkpoint = function(checkpoints) {
317 317 var ul = this.element.find("#restore_checkpoint").find("ul");
318 318 ul.empty();
319 319 if (!checkpoints || checkpoints.length === 0) {
320 320 ul.append(
321 321 $("<li/>")
322 322 .addClass("disabled")
323 323 .append(
324 324 $("<a/>")
325 325 .text("No checkpoints")
326 326 )
327 327 );
328 328 return;
329 329 }
330 330
331 331 var that = this;
332 332 checkpoints.map(function (checkpoint) {
333 333 var d = new Date(checkpoint.last_modified);
334 334 ul.append(
335 335 $("<li/>").append(
336 336 $("<a/>")
337 337 .attr("href", "#")
338 338 .text(d.format("mmm dd HH:MM:ss"))
339 339 .click(function () {
340 340 that.notebook.restore_checkpoint_dialog(checkpoint);
341 341 })
342 342 )
343 343 );
344 344 });
345 345 };
346 346
347 347 // Backwards compatability.
348 348 IPython.MenuBar = MenuBar;
349 349
350 350 return {'MenuBar': MenuBar};
351 351 });
@@ -1,119 +1,119 b''
1 1 // Copyright (c) IPython Development Team.
2 2 // Distributed under the terms of the Modified BSD License.
3 3
4 4 require([
5 5 'base/js/namespace',
6 6 'jquery',
7 7 'base/js/events',
8 8 'base/js/page',
9 9 'base/js/utils',
10 10 'tree/js/notebooklist',
11 11 'tree/js/clusterlist',
12 12 'tree/js/sessionlist',
13 13 'tree/js/kernellist',
14 14 'auth/js/loginwidget',
15 'components/jquery-ui/ui/minified/jquery-ui.min',
16 'components/bootstrap/js/bootstrap.min',
15 'jqueryui',
16 'bootstrap',
17 17 ], function(
18 18 IPython,
19 19 $,
20 20 events,
21 21 page,
22 22 utils,
23 23 notebooklist,
24 24 clusterlist,
25 25 sesssionlist,
26 26 kernellist,
27 27 loginwidget){
28 28
29 29 page = new page.Page();
30 30
31 31 var common_options = {
32 32 base_url: utils.get_body_data("baseUrl"),
33 33 notebook_path: utils.get_body_data("notebookPath"),
34 34 };
35 35 events = $([new events.Events()]);
36 36 session_list = new sesssionlist.SesssionList($.extend({
37 37 events: events},
38 38 common_options));
39 39 notebook_list = new notebooklist.NotebookList('#notebook_list', $.extend({
40 40 session_list: session_list},
41 41 common_options));
42 42 cluster_list = new clusterlist.ClusterList('#cluster_list', common_options);
43 43 kernel_list = new kernellist.KernelList('#running_list', $.extend({
44 44 session_list: session_list},
45 45 common_options));
46 46 login_widget = new loginwidget.LoginWidget('#login_widget', common_options);
47 47
48 48 $('#new_notebook').button().click(function (e) {
49 49 notebook_list.new_notebook();
50 50 });
51 51
52 52 var interval_id=0;
53 53 // auto refresh every xx secondes, no need to be fast,
54 54 // update is done at least when page get focus
55 55 var time_refresh = 60; // in sec
56 56
57 57 var enable_autorefresh = function(){
58 58 //refresh immediately , then start interval
59 59 if($('.upload_button').length === 0)
60 60 {
61 61 session_list.load_sessions();
62 62 cluster_list.load_list();
63 63 }
64 64 if (!interval_id){
65 65 interval_id = setInterval(function(){
66 66 if($('.upload_button').length === 0)
67 67 {
68 68 session_list.load_sessions();
69 69 cluster_list.load_list();
70 70 }
71 71 }, time_refresh*1000);
72 72 }
73 73 };
74 74
75 75 var disable_autorefresh = function(){
76 76 clearInterval(interval_id);
77 77 interval_id = 0;
78 78 };
79 79
80 80 // stop autorefresh when page lose focus
81 81 $(window).blur(function() {
82 82 disable_autorefresh();
83 83 });
84 84
85 85 //re-enable when page get focus back
86 86 $(window).focus(function() {
87 87 enable_autorefresh();
88 88 });
89 89
90 90 // finally start it, it will refresh immediately
91 91 enable_autorefresh();
92 92
93 93 page.show();
94 94 events.trigger('app_initialized.DashboardApp');
95 95
96 96 // bound the upload method to the on change of the file select list
97 97 $("#alternate_upload").change(function (event){
98 98 notebook_list.handleFilesUpload(event,'form');
99 99 });
100 100
101 101 // set hash on tab click
102 102 $("#tabs").find("a").click(function() {
103 103 window.location.hash = $(this).attr("href");
104 104 });
105 105
106 106 // load tab if url hash
107 107 if (window.location.hash) {
108 108 $("#tabs").find("a[href=" + window.location.hash + "]").click();
109 109 }
110 110
111 111 // For backwards compatability.
112 112 IPython.page = page;
113 113 IPython.notebook_list = notebook_list;
114 114 IPython.cluster_list = cluster_list;
115 115 IPython.session_list = session_list;
116 116 IPython.kernel_list = kernel_list;
117 117 IPython.login_widget = login_widget;
118 118 IPython.events = events;
119 119 });
@@ -1,120 +1,120 b''
1 1 // Copyright (c) IPython Development Team.
2 2 // Distributed under the terms of the Modified BSD License.
3 3
4 4 define([
5 5 "widgets/js/widget",
6 6 "jquery",
7 "components/bootstrap/js/bootstrap.min",
7 "bootstrap",
8 8 ], function(widget, $){
9 9
10 10 var CheckboxView = widget.DOMWidgetView.extend({
11 11 render : function(){
12 12 // Called when view is rendered.
13 13 this.$el
14 14 .addClass('widget-hbox-single');
15 15 this.$label = $('<div />')
16 16 .addClass('widget-hlabel')
17 17 .appendTo(this.$el)
18 18 .hide();
19 19 this.$checkbox = $('<input />')
20 20 .attr('type', 'checkbox')
21 21 .appendTo(this.$el)
22 22 .click($.proxy(this.handle_click, this));
23 23
24 24 this.$el_to_style = this.$checkbox; // Set default element to style
25 25 this.update(); // Set defaults.
26 26 },
27 27
28 28 handle_click: function() {
29 29 // Handles when the checkbox is clicked.
30 30
31 31 // Calling model.set will trigger all of the other views of the
32 32 // model to update.
33 33 var value = this.model.get('value');
34 34 this.model.set('value', ! value, {updated_view: this});
35 35 this.touch();
36 36 },
37 37
38 38 update : function(options){
39 39 // Update the contents of this view
40 40 //
41 41 // Called when the model is changed. The model may have been
42 42 // changed by another view or by a state update from the back-end.
43 43 this.$checkbox.prop('checked', this.model.get('value'));
44 44
45 45 if (options === undefined || options.updated_view != this) {
46 46 var disabled = this.model.get('disabled');
47 47 this.$checkbox.prop('disabled', disabled);
48 48
49 49 var description = this.model.get('description');
50 50 if (description.trim().length === 0) {
51 51 this.$label.hide();
52 52 } else {
53 53 this.$label.text(description);
54 54 MathJax.Hub.Queue(["Typeset",MathJax.Hub,this.$label.get(0)]);
55 55 this.$label.show();
56 56 }
57 57 }
58 58 return CheckboxView.__super__.update.apply(this);
59 59 },
60 60
61 61 });
62 62
63 63
64 64 var ToggleButtonView = widget.DOMWidgetView.extend({
65 65 render : function() {
66 66 // Called when view is rendered.
67 67 var that = this;
68 68 this.setElement($('<button />')
69 69 .addClass('btn btn-default')
70 70 .attr('type', 'button')
71 71 .on('click', function (e) {
72 72 e.preventDefault();
73 73 that.handle_click();
74 74 }));
75 75
76 76 this.update(); // Set defaults.
77 77 },
78 78
79 79 update : function(options){
80 80 // Update the contents of this view
81 81 //
82 82 // Called when the model is changed. The model may have been
83 83 // changed by another view or by a state update from the back-end.
84 84 if (this.model.get('value')) {
85 85 this.$el.addClass('active');
86 86 } else {
87 87 this.$el.removeClass('active');
88 88 }
89 89
90 90 if (options === undefined || options.updated_view != this) {
91 91
92 92 var disabled = this.model.get('disabled');
93 93 this.$el.prop('disabled', disabled);
94 94
95 95 var description = this.model.get('description');
96 96 if (description.trim().length === 0) {
97 97 this.$el.html("&nbsp;"); // Preserve button height
98 98 } else {
99 99 this.$el.text(description);
100 100 }
101 101 }
102 102 return ToggleButtonView.__super__.update.apply(this);
103 103 },
104 104
105 105 handle_click: function(e) {
106 106 // Handles and validates user input.
107 107
108 108 // Calling model.set will trigger all of the other views of the
109 109 // model to update.
110 110 var value = this.model.get('value');
111 111 this.model.set('value', ! value, {updated_view: this});
112 112 this.touch();
113 113 },
114 114 });
115 115
116 116 return {
117 117 'CheckboxView': CheckboxView,
118 118 'ToggleButtonView': ToggleButtonView,
119 119 };
120 120 });
@@ -1,54 +1,54 b''
1 1 // Copyright (c) IPython Development Team.
2 2 // Distributed under the terms of the Modified BSD License.
3 3
4 4 define([
5 5 "widgets/js/widget",
6 6 "jquery",
7 "components/bootstrap/js/bootstrap.min",
7 "bootstrap",
8 8 ], function(widget, $){
9 9
10 10 var ButtonView = widget.DOMWidgetView.extend({
11 11 render : function(){
12 12 // Called when view is rendered.
13 13 this.setElement($("<button />")
14 14 .addClass('btn btn-default'));
15 15
16 16 this.update(); // Set defaults.
17 17 },
18 18
19 19 update : function(){
20 20 // Update the contents of this view
21 21 //
22 22 // Called when the model is changed. The model may have been
23 23 // changed by another view or by a state update from the back-end.
24 24 var description = this.model.get('description');
25 25 if (description.length === 0) {
26 26 this.$el.html("&nbsp;"); // Preserve button height
27 27 } else {
28 28 this.$el.text(description);
29 29 }
30 30
31 31 if (this.model.get('disabled')) {
32 32 this.$el.attr('disabled','disabled');
33 33 } else {
34 34 this.$el.removeAttr('disabled');
35 35 }
36 36
37 37 return ButtonView.__super__.update.apply(this);
38 38 },
39 39
40 40 events: {
41 41 // Dictionary of events and their handlers.
42 42 'click': '_handle_click',
43 43 },
44 44
45 45 _handle_click: function(){
46 46 // Handles when the button is clicked.
47 47 this.send({event: 'click'});
48 48 },
49 49 });
50 50
51 51 return {
52 52 'ButtonView': ButtonView,
53 53 };
54 54 });
@@ -1,315 +1,315 b''
1 1 // Copyright (c) IPython Development Team.
2 2 // Distributed under the terms of the Modified BSD License.
3 3
4 4 define([
5 5 "widgets/js/widget",
6 6 "jqueryui",
7 "components/bootstrap/js/bootstrap.min",
7 "bootstrap",
8 8 ], function(widget, $){
9 9
10 10 var ContainerView = widget.DOMWidgetView.extend({
11 11 render: function(){
12 12 // Called when view is rendered.
13 13 this.$el.addClass('widget-container')
14 14 .addClass('vbox');
15 15 this.update_children([], this.model.get('children'));
16 16 this.model.on('change:children', function(model, value, options) {
17 17 this.update_children(model.previous('children'), value);
18 18 }, this);
19 19 this.update();
20 20
21 21 // Trigger model displayed events for any models that are child to
22 22 // this model when this model is displayed.
23 23 var that = this;
24 24 this.on('displayed', function(){
25 25 that.is_displayed = true;
26 26 for (var property in that.child_views) {
27 27 if (that.child_views.hasOwnProperty(property)) {
28 28 that.child_views[property].trigger('displayed');
29 29 }
30 30 }
31 31 });
32 32 },
33 33
34 34 update_children: function(old_list, new_list) {
35 35 // Called when the children list changes.
36 36 this.do_diff(old_list,
37 37 new_list,
38 38 $.proxy(this.remove_child_model, this),
39 39 $.proxy(this.add_child_model, this));
40 40 },
41 41
42 42 remove_child_model: function(model) {
43 43 // Called when a model is removed from the children list.
44 44 this.pop_child_view(model).remove();
45 45 },
46 46
47 47 add_child_model: function(model) {
48 48 // Called when a model is added to the children list.
49 49 var view = this.create_child_view(model);
50 50 this.$el.append(view.$el);
51 51
52 52 // Trigger the displayed event if this model is displayed.
53 53 if (this.is_displayed) {
54 54 view.trigger('displayed');
55 55 }
56 56 },
57 57
58 58 update: function(){
59 59 // Update the contents of this view
60 60 //
61 61 // Called when the model is changed. The model may have been
62 62 // changed by another view or by a state update from the back-end.
63 63 return ContainerView.__super__.update.apply(this);
64 64 },
65 65 });
66 66
67 67
68 68 var PopupView = widget.DOMWidgetView.extend({
69 69 render: function(){
70 70 // Called when view is rendered.
71 71 var that = this;
72 72
73 73 this.$el.on("remove", function(){
74 74 that.$backdrop.remove();
75 75 });
76 76 this.$backdrop = $('<div />')
77 77 .appendTo($('#notebook-container'))
78 78 .addClass('modal-dialog')
79 79 .css('position', 'absolute')
80 80 .css('left', '0px')
81 81 .css('top', '0px');
82 82 this.$window = $('<div />')
83 83 .appendTo(this.$backdrop)
84 84 .addClass('modal-content widget-modal')
85 85 .mousedown(function(){
86 86 that.bring_to_front();
87 87 });
88 88
89 89 // Set the elements array since the this.$window element is not child
90 90 // of this.$el and the parent widget manager or other widgets may
91 91 // need to know about all of the top-level widgets. The IPython
92 92 // widget manager uses this to register the elements with the
93 93 // keyboard manager.
94 94 this.additional_elements = [this.$window];
95 95
96 96 this.$title_bar = $('<div />')
97 97 .addClass('popover-title')
98 98 .appendTo(this.$window)
99 99 .mousedown(function(){
100 100 that.bring_to_front();
101 101 });
102 102 this.$close = $('<button />')
103 103 .addClass('close icon-remove')
104 104 .css('margin-left', '5px')
105 105 .appendTo(this.$title_bar)
106 106 .click(function(){
107 107 that.hide();
108 108 event.stopPropagation();
109 109 });
110 110 this.$minimize = $('<button />')
111 111 .addClass('close icon-arrow-down')
112 112 .appendTo(this.$title_bar)
113 113 .click(function(){
114 114 that.popped_out = !that.popped_out;
115 115 if (!that.popped_out) {
116 116 that.$minimize
117 117 .removeClass('icon-arrow-down')
118 118 .addClass('icon-arrow-up');
119 119
120 120 that.$window
121 121 .draggable('destroy')
122 122 .resizable('destroy')
123 123 .removeClass('widget-modal modal-content')
124 124 .addClass('docked-widget-modal')
125 125 .detach()
126 126 .insertBefore(that.$show_button);
127 127 that.$show_button.hide();
128 128 that.$close.hide();
129 129 } else {
130 130 that.$minimize
131 131 .addClass('icon-arrow-down')
132 132 .removeClass('icon-arrow-up');
133 133
134 134 that.$window
135 135 .removeClass('docked-widget-modal')
136 136 .addClass('widget-modal modal-content')
137 137 .detach()
138 138 .appendTo(that.$backdrop)
139 139 .draggable({handle: '.popover-title', snap: '#notebook, .modal', snapMode: 'both'})
140 140 .resizable()
141 141 .children('.ui-resizable-handle').show();
142 142 that.show();
143 143 that.$show_button.show();
144 144 that.$close.show();
145 145 }
146 146 event.stopPropagation();
147 147 });
148 148 this.$title = $('<div />')
149 149 .addClass('widget-modal-title')
150 150 .html("&nbsp;")
151 151 .appendTo(this.$title_bar);
152 152 this.$body = $('<div />')
153 153 .addClass('modal-body')
154 154 .addClass('widget-modal-body')
155 155 .addClass('widget-container')
156 156 .addClass('vbox')
157 157 .appendTo(this.$window);
158 158
159 159 this.$show_button = $('<button />')
160 160 .html("&nbsp;")
161 161 .addClass('btn btn-info widget-modal-show')
162 162 .appendTo(this.$el)
163 163 .click(function(){
164 164 that.show();
165 165 });
166 166
167 167 this.$window.draggable({handle: '.popover-title', snap: '#notebook, .modal', snapMode: 'both'});
168 168 this.$window.resizable();
169 169 this.$window.on('resize', function(){
170 170 that.$body.outerHeight(that.$window.innerHeight() - that.$title_bar.outerHeight());
171 171 });
172 172
173 173 this.$el_to_style = this.$body;
174 174 this._shown_once = false;
175 175 this.popped_out = true;
176 176
177 177 this.update_children([], this.model.get('children'));
178 178 this.model.on('change:children', function(model, value, options) {
179 179 this.update_children(model.previous('children'), value);
180 180 }, this);
181 181 this.update();
182 182
183 183 // Trigger model displayed events for any models that are child to
184 184 // this model when this model is displayed.
185 185 this.on('displayed', function(){
186 186 that.is_displayed = true;
187 187 for (var property in that.child_views) {
188 188 if (that.child_views.hasOwnProperty(property)) {
189 189 that.child_views[property].trigger('displayed');
190 190 }
191 191 }
192 192 });
193 193 },
194 194
195 195 hide: function() {
196 196 // Called when the modal hide button is clicked.
197 197 this.$window.hide();
198 198 this.$show_button.removeClass('btn-info');
199 199 },
200 200
201 201 show: function() {
202 202 // Called when the modal show button is clicked.
203 203 this.$show_button.addClass('btn-info');
204 204 this.$window.show();
205 205 if (this.popped_out) {
206 206 this.$window.css("positon", "absolute");
207 207 this.$window.css("top", "0px");
208 208 this.$window.css("left", Math.max(0, (($('body').outerWidth() - this.$window.outerWidth()) / 2) +
209 209 $(window).scrollLeft()) + "px");
210 210 this.bring_to_front();
211 211 }
212 212 },
213 213
214 214 bring_to_front: function() {
215 215 // Make the modal top-most, z-ordered about the other modals.
216 216 var $widget_modals = $(".widget-modal");
217 217 var max_zindex = 0;
218 218 $widget_modals.each(function (index, el){
219 219 var zindex = parseInt($(el).css('z-index'));
220 220 if (!isNaN(zindex)) {
221 221 max_zindex = Math.max(max_zindex, zindex);
222 222 }
223 223 });
224 224
225 225 // Start z-index of widget modals at 2000
226 226 max_zindex = Math.max(max_zindex, 2000);
227 227
228 228 $widget_modals.each(function (index, el){
229 229 $el = $(el);
230 230 if (max_zindex == parseInt($el.css('z-index'))) {
231 231 $el.css('z-index', max_zindex - 1);
232 232 }
233 233 });
234 234 this.$window.css('z-index', max_zindex);
235 235 },
236 236
237 237 update_children: function(old_list, new_list) {
238 238 // Called when the children list is modified.
239 239 this.do_diff(old_list,
240 240 new_list,
241 241 $.proxy(this.remove_child_model, this),
242 242 $.proxy(this.add_child_model, this));
243 243 },
244 244
245 245 remove_child_model: function(model) {
246 246 // Called when a child is removed from children list.
247 247 this.pop_child_view(model).remove();
248 248 },
249 249
250 250 add_child_model: function(model) {
251 251 // Called when a child is added to children list.
252 252 var view = this.create_child_view(model);
253 253 this.$body.append(view.$el);
254 254
255 255 // Trigger the displayed event if this model is displayed.
256 256 if (this.is_displayed) {
257 257 view.trigger('displayed');
258 258 }
259 259 },
260 260
261 261 update: function(){
262 262 // Update the contents of this view
263 263 //
264 264 // Called when the model is changed. The model may have been
265 265 // changed by another view or by a state update from the back-end.
266 266 var description = this.model.get('description');
267 267 if (description.trim().length === 0) {
268 268 this.$title.html("&nbsp;"); // Preserve title height
269 269 } else {
270 270 this.$title.text(description);
271 271 MathJax.Hub.Queue(["Typeset",MathJax.Hub,this.$title.get(0)]);
272 272 }
273 273
274 274 var button_text = this.model.get('button_text');
275 275 if (button_text.trim().length === 0) {
276 276 this.$show_button.html("&nbsp;"); // Preserve button height
277 277 } else {
278 278 this.$show_button.text(button_text);
279 279 }
280 280
281 281 if (!this._shown_once) {
282 282 this._shown_once = true;
283 283 this.show();
284 284 }
285 285
286 286 return PopupView.__super__.update.apply(this);
287 287 },
288 288
289 289 _get_selector_element: function(selector) {
290 290 // Get an element view a 'special' jquery selector. (see widget.js)
291 291 //
292 292 // Since the modal actually isn't within the $el in the DOM, we need to extend
293 293 // the selector logic to allow the user to set css on the modal if need be.
294 294 // The convention used is:
295 295 // "modal" - select the modal div
296 296 // "modal [selector]" - select element(s) within the modal div.
297 297 // "[selector]" - select elements within $el
298 298 // "" - select the $el_to_style
299 299 if (selector.substring(0, 5) == 'modal') {
300 300 if (selector == 'modal') {
301 301 return this.$window;
302 302 } else {
303 303 return this.$window.find(selector.substring(6));
304 304 }
305 305 } else {
306 306 return PopupView.__super__._get_selector_element.apply(this, [selector]);
307 307 }
308 308 },
309 309 });
310 310
311 311 return {
312 312 'ContainerView': ContainerView,
313 313 'PopupView': PopupView,
314 314 };
315 315 });
@@ -1,301 +1,301 b''
1 1 // Copyright (c) IPython Development Team.
2 2 // Distributed under the terms of the Modified BSD License.
3 3
4 4 define([
5 5 "widgets/js/widget",
6 6 "jqueryui",
7 "components/bootstrap/js/bootstrap.min",
7 "bootstrap",
8 8 ], function(widget, $){
9 9
10 10 var IntSliderView = widget.DOMWidgetView.extend({
11 11 render : function(){
12 12 // Called when view is rendered.
13 13 this.$el
14 14 .addClass('widget-hbox-single');
15 15 this.$label = $('<div />')
16 16 .appendTo(this.$el)
17 17 .addClass('widget-hlabel')
18 18 .hide();
19 19
20 20 this.$slider = $('<div />')
21 21 .slider({})
22 22 .addClass('slider');
23 23 // Put the slider in a container
24 24 this.$slider_container = $('<div />')
25 25 .addClass('widget-hslider')
26 26 .append(this.$slider);
27 27 this.$el_to_style = this.$slider_container; // Set default element to style
28 28 this.$el.append(this.$slider_container);
29 29
30 30 this.$readout = $('<div/>')
31 31 .appendTo(this.$el)
32 32 .addClass('widget-hreadout')
33 33 .hide();
34 34
35 35 // Set defaults.
36 36 this.update();
37 37 },
38 38
39 39 update : function(options){
40 40 // Update the contents of this view
41 41 //
42 42 // Called when the model is changed. The model may have been
43 43 // changed by another view or by a state update from the back-end.
44 44 if (options === undefined || options.updated_view != this) {
45 45 // JQuery slider option keys. These keys happen to have a
46 46 // one-to-one mapping with the corrosponding keys of the model.
47 47 var jquery_slider_keys = ['step', 'max', 'min', 'disabled'];
48 48 var that = this;
49 49 that.$slider.slider({});
50 50 _.each(jquery_slider_keys, function(key, i) {
51 51 var model_value = that.model.get(key);
52 52 if (model_value !== undefined) {
53 53 that.$slider.slider("option", key, model_value);
54 54 }
55 55 });
56 56
57 57 // WORKAROUND FOR JQUERY SLIDER BUG.
58 58 // The horizontal position of the slider handle
59 59 // depends on the value of the slider at the time
60 60 // of orientation change. Before applying the new
61 61 // workaround, we set the value to the minimum to
62 62 // make sure that the horizontal placement of the
63 63 // handle in the vertical slider is always
64 64 // consistent.
65 65 var orientation = this.model.get('orientation');
66 66 var value = this.model.get('min');
67 67 this.$slider.slider('option', 'value', value);
68 68 this.$slider.slider('option', 'orientation', orientation);
69 69 value = this.model.get('value');
70 70 this.$slider.slider('option', 'value', value);
71 71 this.$readout.text(value);
72 72
73 73 // Use the right CSS classes for vertical & horizontal sliders
74 74 if (orientation=='vertical') {
75 75 this.$slider_container
76 76 .removeClass('widget-hslider')
77 77 .addClass('widget-vslider');
78 78 this.$el
79 79 .removeClass('widget-hbox-single')
80 80 .addClass('widget-vbox-single');
81 81 this.$label
82 82 .removeClass('widget-hlabel')
83 83 .addClass('widget-vlabel');
84 84 this.$readout
85 85 .removeClass('widget-hreadout')
86 86 .addClass('widget-vreadout');
87 87
88 88 } else {
89 89 this.$slider_container
90 90 .removeClass('widget-vslider')
91 91 .addClass('widget-hslider');
92 92 this.$el
93 93 .removeClass('widget-vbox-single')
94 94 .addClass('widget-hbox-single');
95 95 this.$label
96 96 .removeClass('widget-vlabel')
97 97 .addClass('widget-hlabel');
98 98 this.$readout
99 99 .removeClass('widget-vreadout')
100 100 .addClass('widget-hreadout');
101 101 }
102 102
103 103 var description = this.model.get('description');
104 104 if (description.length === 0) {
105 105 this.$label.hide();
106 106 } else {
107 107 this.$label.text(description);
108 108 MathJax.Hub.Queue(["Typeset",MathJax.Hub,this.$label.get(0)]);
109 109 this.$label.show();
110 110 }
111 111
112 112 var readout = this.model.get('readout');
113 113 if (readout) {
114 114 this.$readout.show();
115 115 } else {
116 116 this.$readout.hide();
117 117 }
118 118 }
119 119 return IntSliderView.__super__.update.apply(this);
120 120 },
121 121
122 122 events: {
123 123 // Dictionary of events and their handlers.
124 124 "slide" : "handleSliderChange"
125 125 },
126 126
127 127 handleSliderChange: function(e, ui) {
128 128 // Called when the slider value is changed.
129 129
130 130 // Calling model.set will trigger all of the other views of the
131 131 // model to update.
132 132 var actual_value = this._validate_slide_value(ui.value);
133 133 this.model.set('value', actual_value, {updated_view: this});
134 134 this.$readout.text(actual_value);
135 135 this.touch();
136 136 },
137 137
138 138 _validate_slide_value: function(x) {
139 139 // Validate the value of the slider before sending it to the back-end
140 140 // and applying it to the other views on the page.
141 141
142 142 // Double bit-wise not truncates the decimel (int cast).
143 143 return ~~x;
144 144 },
145 145 });
146 146
147 147
148 148 var IntTextView = widget.DOMWidgetView.extend({
149 149 render : function(){
150 150 // Called when view is rendered.
151 151 this.$el
152 152 .addClass('widget-hbox-single');
153 153 this.$label = $('<div />')
154 154 .appendTo(this.$el)
155 155 .addClass('widget-hlabel')
156 156 .hide();
157 157 this.$textbox = $('<input type="text" />')
158 158 .addClass('form-control')
159 159 .addClass('widget-numeric-text')
160 160 .appendTo(this.$el);
161 161 this.$el_to_style = this.$textbox; // Set default element to style
162 162 this.update(); // Set defaults.
163 163 },
164 164
165 165 update : function(options){
166 166 // Update the contents of this view
167 167 //
168 168 // Called when the model is changed. The model may have been
169 169 // changed by another view or by a state update from the back-end.
170 170 if (options === undefined || options.updated_view != this) {
171 171 var value = this.model.get('value');
172 172 if (this._parse_value(this.$textbox.val()) != value) {
173 173 this.$textbox.val(value);
174 174 }
175 175
176 176 if (this.model.get('disabled')) {
177 177 this.$textbox.attr('disabled','disabled');
178 178 } else {
179 179 this.$textbox.removeAttr('disabled');
180 180 }
181 181
182 182 var description = this.model.get('description');
183 183 if (description.length === 0) {
184 184 this.$label.hide();
185 185 } else {
186 186 this.$label.text(description);
187 187 MathJax.Hub.Queue(["Typeset",MathJax.Hub,this.$label.get(0)]);
188 188 this.$label.show();
189 189 }
190 190 }
191 191 return IntTextView.__super__.update.apply(this);
192 192 },
193 193
194 194 events: {
195 195 // Dictionary of events and their handlers.
196 196 "keyup input" : "handleChanging",
197 197 "paste input" : "handleChanging",
198 198 "cut input" : "handleChanging",
199 199
200 200 // Fires only when control is validated or looses focus.
201 201 "change input" : "handleChanged"
202 202 },
203 203
204 204 handleChanging: function(e) {
205 205 // Handles and validates user input.
206 206
207 207 // Try to parse value as a int.
208 208 var numericalValue = 0;
209 209 if (e.target.value !== '') {
210 210 var trimmed = e.target.value.trim();
211 211 if (!(['-', '-.', '.', '+.', '+'].indexOf(trimmed) >= 0)) {
212 212 numericalValue = this._parse_value(e.target.value);
213 213 }
214 214 }
215 215
216 216 // If parse failed, reset value to value stored in model.
217 217 if (isNaN(numericalValue)) {
218 218 e.target.value = this.model.get('value');
219 219 } else if (!isNaN(numericalValue)) {
220 220 if (this.model.get('max') !== undefined) {
221 221 numericalValue = Math.min(this.model.get('max'), numericalValue);
222 222 }
223 223 if (this.model.get('min') !== undefined) {
224 224 numericalValue = Math.max(this.model.get('min'), numericalValue);
225 225 }
226 226
227 227 // Apply the value if it has changed.
228 228 if (numericalValue != this.model.get('value')) {
229 229
230 230 // Calling model.set will trigger all of the other views of the
231 231 // model to update.
232 232 this.model.set('value', numericalValue, {updated_view: this});
233 233 this.touch();
234 234 }
235 235 }
236 236 },
237 237
238 238 handleChanged: function(e) {
239 239 // Applies validated input.
240 240 if (this.model.get('value') != e.target.value) {
241 241 e.target.value = this.model.get('value');
242 242 }
243 243 },
244 244
245 245 _parse_value: function(value) {
246 246 // Parse the value stored in a string.
247 247 return parseInt(value);
248 248 },
249 249 });
250 250
251 251
252 252 var ProgressView = widget.DOMWidgetView.extend({
253 253 render : function(){
254 254 // Called when view is rendered.
255 255 this.$el
256 256 .addClass('widget-hbox-single');
257 257 this.$label = $('<div />')
258 258 .appendTo(this.$el)
259 259 .addClass('widget-hlabel')
260 260 .hide();
261 261 this.$progress = $('<div />')
262 262 .addClass('progress')
263 263 .addClass('widget-progress')
264 264 .appendTo(this.$el);
265 265 this.$el_to_style = this.$progress; // Set default element to style
266 266 this.$bar = $('<div />')
267 267 .addClass('progress-bar')
268 268 .css('width', '50%')
269 269 .appendTo(this.$progress);
270 270 this.update(); // Set defaults.
271 271 },
272 272
273 273 update : function(){
274 274 // Update the contents of this view
275 275 //
276 276 // Called when the model is changed. The model may have been
277 277 // changed by another view or by a state update from the back-end.
278 278 var value = this.model.get('value');
279 279 var max = this.model.get('max');
280 280 var min = this.model.get('min');
281 281 var percent = 100.0 * (value - min) / (max - min);
282 282 this.$bar.css('width', percent + '%');
283 283
284 284 var description = this.model.get('description');
285 285 if (description.length === 0) {
286 286 this.$label.hide();
287 287 } else {
288 288 this.$label.text(description);
289 289 MathJax.Hub.Queue(["Typeset",MathJax.Hub,this.$label.get(0)]);
290 290 this.$label.show();
291 291 }
292 292 return ProgressView.__super__.update.apply(this);
293 293 },
294 294 });
295 295
296 296 return {
297 297 'IntSliderView': IntSliderView,
298 298 'IntTextView': IntTextView,
299 299 'ProgressView': ProgressView,
300 300 };
301 301 });
@@ -1,380 +1,380 b''
1 1 // Copyright (c) IPython Development Team.
2 2 // Distributed under the terms of the Modified BSD License.
3 3
4 4 define([
5 5 "widgets/js/widget",
6 6 "base/js/utils",
7 7 "jquery",
8 "components/bootstrap/js/bootstrap.min",
8 "bootstrap",
9 9 ], function(widget, utils, $){
10 10
11 11 var DropdownView = widget.DOMWidgetView.extend({
12 12 render : function(){
13 13 // Called when view is rendered.
14 14 this.$el
15 15 .addClass('widget-hbox-single');
16 16 this.$label = $('<div />')
17 17 .appendTo(this.$el)
18 18 .addClass('widget-hlabel')
19 19 .hide();
20 20 this.$buttongroup = $('<div />')
21 21 .addClass('widget_item')
22 22 .addClass('btn-group')
23 23 .appendTo(this.$el);
24 24 this.$el_to_style = this.$buttongroup; // Set default element to style
25 25 this.$droplabel = $('<button />')
26 26 .addClass('btn btn-default')
27 27 .addClass('widget-combo-btn')
28 28 .html("&nbsp;")
29 29 .appendTo(this.$buttongroup);
30 30 this.$dropbutton = $('<button />')
31 31 .addClass('btn btn-default')
32 32 .addClass('dropdown-toggle')
33 33 .addClass('widget-combo-carrot-btn')
34 34 .attr('data-toggle', 'dropdown')
35 35 .append($('<span />').addClass("caret"))
36 36 .appendTo(this.$buttongroup);
37 37 this.$droplist = $('<ul />')
38 38 .addClass('dropdown-menu')
39 39 .appendTo(this.$buttongroup);
40 40
41 41 // Set defaults.
42 42 this.update();
43 43 },
44 44
45 45 update : function(options){
46 46 // Update the contents of this view
47 47 //
48 48 // Called when the model is changed. The model may have been
49 49 // changed by another view or by a state update from the back-end.
50 50
51 51 if (options === undefined || options.updated_view != this) {
52 52 var selected_item_text = this.model.get('value_name');
53 53 if (selected_item_text.trim().length === 0) {
54 54 this.$droplabel.html("&nbsp;");
55 55 } else {
56 56 this.$droplabel.text(selected_item_text);
57 57 }
58 58
59 59 var items = this.model.get('value_names');
60 60 var $replace_droplist = $('<ul />')
61 61 .addClass('dropdown-menu');
62 62 var that = this;
63 63 _.each(items, function(item, i) {
64 64 var item_button = $('<a href="#"/>')
65 65 .text(item)
66 66 .on('click', $.proxy(that.handle_click, that));
67 67 $replace_droplist.append($('<li />').append(item_button));
68 68 });
69 69
70 70 this.$droplist.replaceWith($replace_droplist);
71 71 this.$droplist.remove();
72 72 this.$droplist = $replace_droplist;
73 73
74 74 if (this.model.get('disabled')) {
75 75 this.$buttongroup.attr('disabled','disabled');
76 76 this.$droplabel.attr('disabled','disabled');
77 77 this.$dropbutton.attr('disabled','disabled');
78 78 this.$droplist.attr('disabled','disabled');
79 79 } else {
80 80 this.$buttongroup.removeAttr('disabled');
81 81 this.$droplabel.removeAttr('disabled');
82 82 this.$dropbutton.removeAttr('disabled');
83 83 this.$droplist.removeAttr('disabled');
84 84 }
85 85
86 86 var description = this.model.get('description');
87 87 if (description.length === 0) {
88 88 this.$label.hide();
89 89 } else {
90 90 this.$label.text(description);
91 91 MathJax.Hub.Queue(["Typeset",MathJax.Hub,this.$label.get(0)]);
92 92 this.$label.show();
93 93 }
94 94 }
95 95 return DropdownView.__super__.update.apply(this);
96 96 },
97 97
98 98 handle_click: function (e) {
99 99 // Handle when a value is clicked.
100 100
101 101 // Calling model.set will trigger all of the other views of the
102 102 // model to update.
103 103 this.model.set('value_name', $(e.target).text(), {updated_view: this});
104 104 this.touch();
105 105 },
106 106
107 107 });
108 108
109 109
110 110 var RadioButtonsView = widget.DOMWidgetView.extend({
111 111 render : function(){
112 112 // Called when view is rendered.
113 113 this.$el
114 114 .addClass('widget-hbox');
115 115 this.$label = $('<div />')
116 116 .appendTo(this.$el)
117 117 .addClass('widget-hlabel')
118 118 .hide();
119 119 this.$container = $('<div />')
120 120 .appendTo(this.$el)
121 121 .addClass('widget-radio-box');
122 122 this.$el_to_style = this.$container; // Set default element to style
123 123 this.update();
124 124 },
125 125
126 126 update : function(options){
127 127 // Update the contents of this view
128 128 //
129 129 // Called when the model is changed. The model may have been
130 130 // changed by another view or by a state update from the back-end.
131 131 if (options === undefined || options.updated_view != this) {
132 132 // Add missing items to the DOM.
133 133 var items = this.model.get('value_names');
134 134 var disabled = this.model.get('disabled');
135 135 var that = this;
136 136 _.each(items, function(item, index) {
137 137 var item_query = ' :input[value="' + item + '"]';
138 138 if (that.$el.find(item_query).length === 0) {
139 139 var $label = $('<label />')
140 140 .addClass('radio')
141 141 .text(item)
142 142 .appendTo(that.$container);
143 143
144 144 $('<input />')
145 145 .attr('type', 'radio')
146 146 .addClass(that.model)
147 147 .val(item)
148 148 .prependTo($label)
149 149 .on('click', $.proxy(that.handle_click, that));
150 150 }
151 151
152 152 var $item_element = that.$container.find(item_query);
153 153 if (that.model.get('value_name') == item) {
154 154 $item_element.prop('checked', true);
155 155 } else {
156 156 $item_element.prop('checked', false);
157 157 }
158 158 $item_element.prop('disabled', disabled);
159 159 });
160 160
161 161 // Remove items that no longer exist.
162 162 this.$container.find('input').each(function(i, obj) {
163 163 var value = $(obj).val();
164 164 var found = false;
165 165 _.each(items, function(item, index) {
166 166 if (item == value) {
167 167 found = true;
168 168 return false;
169 169 }
170 170 });
171 171
172 172 if (!found) {
173 173 $(obj).parent().remove();
174 174 }
175 175 });
176 176
177 177 var description = this.model.get('description');
178 178 if (description.length === 0) {
179 179 this.$label.hide();
180 180 } else {
181 181 this.$label.text(description);
182 182 MathJax.Hub.Queue(["Typeset",MathJax.Hub,this.$label.get(0)]);
183 183 this.$label.show();
184 184 }
185 185 }
186 186 return RadioButtonsView.__super__.update.apply(this);
187 187 },
188 188
189 189 handle_click: function (e) {
190 190 // Handle when a value is clicked.
191 191
192 192 // Calling model.set will trigger all of the other views of the
193 193 // model to update.
194 194 this.model.set('value_name', $(e.target).val(), {updated_view: this});
195 195 this.touch();
196 196 },
197 197 });
198 198
199 199
200 200 var ToggleButtonsView = widget.DOMWidgetView.extend({
201 201 render : function(){
202 202 // Called when view is rendered.
203 203 this.$el
204 204 .addClass('widget-hbox-single');
205 205 this.$label = $('<div />')
206 206 .appendTo(this.$el)
207 207 .addClass('widget-hlabel')
208 208 .hide();
209 209 this.$buttongroup = $('<div />')
210 210 .addClass('btn-group')
211 211 .attr('data-toggle', 'buttons-radio')
212 212 .appendTo(this.$el);
213 213 this.$el_to_style = this.$buttongroup; // Set default element to style
214 214 this.update();
215 215 },
216 216
217 217 update : function(options){
218 218 // Update the contents of this view
219 219 //
220 220 // Called when the model is changed. The model may have been
221 221 // changed by another view or by a state update from the back-end.
222 222 if (options === undefined || options.updated_view != this) {
223 223 // Add missing items to the DOM.
224 224 var items = this.model.get('value_names');
225 225 var disabled = this.model.get('disabled');
226 226 var that = this;
227 227 var item_html;
228 228 _.each(items, function(item, index) {
229 229 if (item.trim().length == 0) {
230 230 item_html = "&nbsp;";
231 231 } else {
232 232 item_html = utils.escape_html(item);
233 233 }
234 234 var item_query = '[data-value="' + item + '"]';
235 235 var $item_element = that.$buttongroup.find(item_query);
236 236 if (!$item_element.length) {
237 237 $item_element = $('<button/>')
238 238 .attr('type', 'button')
239 239 .addClass('btn btn-default')
240 240 .html(item_html)
241 241 .appendTo(that.$buttongroup)
242 242 .attr('data-value', item)
243 243 .on('click', $.proxy(that.handle_click, that));
244 244 }
245 245 if (that.model.get('value_name') == item) {
246 246 $item_element.addClass('active');
247 247 } else {
248 248 $item_element.removeClass('active');
249 249 }
250 250 $item_element.prop('disabled', disabled);
251 251 });
252 252
253 253 // Remove items that no longer exist.
254 254 this.$buttongroup.find('button').each(function(i, obj) {
255 255 var value = $(obj).data('value');
256 256 var found = false;
257 257 _.each(items, function(item, index) {
258 258 if (item == value) {
259 259 found = true;
260 260 return false;
261 261 }
262 262 });
263 263
264 264 if (!found) {
265 265 $(obj).remove();
266 266 }
267 267 });
268 268
269 269 var description = this.model.get('description');
270 270 if (description.length === 0) {
271 271 this.$label.hide();
272 272 } else {
273 273 this.$label.text(description);
274 274 MathJax.Hub.Queue(["Typeset",MathJax.Hub,this.$label.get(0)]);
275 275 this.$label.show();
276 276 }
277 277 }
278 278 return ToggleButtonsView.__super__.update.apply(this);
279 279 },
280 280
281 281 handle_click: function (e) {
282 282 // Handle when a value is clicked.
283 283
284 284 // Calling model.set will trigger all of the other views of the
285 285 // model to update.
286 286 this.model.set('value_name', $(e.target).data('value'), {updated_view: this});
287 287 this.touch();
288 288 },
289 289 });
290 290
291 291
292 292 var SelectView = widget.DOMWidgetView.extend({
293 293 render : function(){
294 294 // Called when view is rendered.
295 295 this.$el
296 296 .addClass('widget-hbox');
297 297 this.$label = $('<div />')
298 298 .appendTo(this.$el)
299 299 .addClass('widget-hlabel')
300 300 .hide();
301 301 this.$listbox = $('<select />')
302 302 .addClass('widget-listbox form-control')
303 303 .attr('size', 6)
304 304 .appendTo(this.$el);
305 305 this.$el_to_style = this.$listbox; // Set default element to style
306 306 this.update();
307 307 },
308 308
309 309 update : function(options){
310 310 // Update the contents of this view
311 311 //
312 312 // Called when the model is changed. The model may have been
313 313 // changed by another view or by a state update from the back-end.
314 314 if (options === undefined || options.updated_view != this) {
315 315 // Add missing items to the DOM.
316 316 var items = this.model.get('value_names');
317 317 var that = this;
318 318 _.each(items, function(item, index) {
319 319 var item_query = ' :contains("' + item + '")';
320 320 if (that.$listbox.find(item_query).length === 0) {
321 321 $('<option />')
322 322 .text(item)
323 323 .attr('value_name', item)
324 324 .appendTo(that.$listbox)
325 325 .on('click', $.proxy(that.handle_click, that));
326 326 }
327 327 });
328 328
329 329 // Select the correct element
330 330 this.$listbox.val(this.model.get('value_name'));
331 331
332 332 // Disable listbox if needed
333 333 var disabled = this.model.get('disabled');
334 334 this.$listbox.prop('disabled', disabled);
335 335
336 336 // Remove items that no longer exist.
337 337 this.$listbox.find('option').each(function(i, obj) {
338 338 var value = $(obj).text();
339 339 var found = false;
340 340 _.each(items, function(item, index) {
341 341 if (item == value) {
342 342 found = true;
343 343 return false;
344 344 }
345 345 });
346 346
347 347 if (!found) {
348 348 $(obj).remove();
349 349 }
350 350 });
351 351
352 352 var description = this.model.get('description');
353 353 if (description.length === 0) {
354 354 this.$label.hide();
355 355 } else {
356 356 this.$label.text(description);
357 357 MathJax.Hub.Queue(["Typeset",MathJax.Hub,this.$label.get(0)]);
358 358 this.$label.show();
359 359 }
360 360 }
361 361 return SelectView.__super__.update.apply(this);
362 362 },
363 363
364 364 handle_click: function (e) {
365 365 // Handle when a value is clicked.
366 366
367 367 // Calling model.set will trigger all of the other views of the
368 368 // model to update.
369 369 this.model.set('value_name', $(e.target).text(), {updated_view: this});
370 370 this.touch();
371 371 },
372 372 });
373 373
374 374 return {
375 375 'DropdownView': DropdownView,
376 376 'RadioButtonsView': RadioButtonsView,
377 377 'ToggleButtonsView': ToggleButtonsView,
378 378 'SelectView': SelectView,
379 379 };
380 380 });
@@ -1,267 +1,267 b''
1 1 // Copyright (c) IPython Development Team.
2 2 // Distributed under the terms of the Modified BSD License.
3 3
4 4 define([
5 5 "widgets/js/widget",
6 6 "base/js/utils",
7 7 "jquery",
8 "components/bootstrap/js/bootstrap.min",
8 "bootstrap",
9 9 ], function(widget, utils, $){
10 10
11 11 var AccordionView = widget.DOMWidgetView.extend({
12 12 render: function(){
13 13 // Called when view is rendered.
14 14 var guid = 'panel-group' + utils.uuid();
15 15 this.$el
16 16 .attr('id', guid)
17 17 .addClass('panel-group');
18 18 this.containers = [];
19 19 this.model_containers = {};
20 20 this.update_children([], this.model.get('children'));
21 21 this.model.on('change:children', function(model, value, options) {
22 22 this.update_children(model.previous('children'), value);
23 23 }, this);
24 24 this.model.on('change:selected_index', function(model, value, options) {
25 25 this.update_selected_index(model.previous('selected_index'), value, options);
26 26 }, this);
27 27 this.model.on('change:_titles', function(model, value, options) {
28 28 this.update_titles(value);
29 29 }, this);
30 30 var that = this;
31 31 this.on('displayed', function() {
32 32 this.update_titles();
33 33 // Trigger model displayed events for any models that are child to
34 34 // this model when this model is displayed.
35 35 that.is_displayed = true;
36 36 for (var property in that.child_views) {
37 37 if (that.child_views.hasOwnProperty(property)) {
38 38 that.child_views[property].trigger('displayed');
39 39 }
40 40 }
41 41 }, this);
42 42 },
43 43
44 44 update_titles: function(titles) {
45 45 // Set tab titles
46 46 if (!titles) {
47 47 titles = this.model.get('_titles');
48 48 }
49 49
50 50 var that = this;
51 51 _.each(titles, function(title, page_index) {
52 52 var accordian = that.containers[page_index];
53 53 if (accordian !== undefined) {
54 54 accordian
55 55 .find('.panel-heading')
56 56 .find('.accordion-toggle')
57 57 .text(title);
58 58 }
59 59 });
60 60 },
61 61
62 62 update_selected_index: function(old_index, new_index, options) {
63 63 // Only update the selection if the selection wasn't triggered
64 64 // by the front-end. It must be triggered by the back-end.
65 65 if (options === undefined || options.updated_view != this) {
66 66 this.containers[old_index].find('.panel-collapse').collapse('hide');
67 67 if (0 <= new_index && new_index < this.containers.length) {
68 68 this.containers[new_index].find('.panel-collapse').collapse('show');
69 69 }
70 70 }
71 71 },
72 72
73 73 update_children: function(old_list, new_list) {
74 74 // Called when the children list is modified.
75 75 this.do_diff(old_list,
76 76 new_list,
77 77 $.proxy(this.remove_child_model, this),
78 78 $.proxy(this.add_child_model, this));
79 79 },
80 80
81 81 remove_child_model: function(model) {
82 82 // Called when a child is removed from children list.
83 83 var accordion_group = this.model_containers[model.id];
84 84 this.containers.splice(accordion_group.container_index, 1);
85 85 delete this.model_containers[model.id];
86 86 accordion_group.remove();
87 87 this.pop_child_view(model);
88 88 },
89 89
90 90 add_child_model: function(model) {
91 91 // Called when a child is added to children list.
92 92 var view = this.create_child_view(model);
93 93 var index = this.containers.length;
94 94 var uuid = utils.uuid();
95 95 var accordion_group = $('<div />')
96 96 .addClass('panel panel-default')
97 97 .appendTo(this.$el);
98 98 var accordion_heading = $('<div />')
99 99 .addClass('panel-heading')
100 100 .appendTo(accordion_group);
101 101 var that = this;
102 102 var accordion_toggle = $('<a />')
103 103 .addClass('accordion-toggle')
104 104 .attr('data-toggle', 'collapse')
105 105 .attr('data-parent', '#' + this.$el.attr('id'))
106 106 .attr('href', '#' + uuid)
107 107 .click(function(evt){
108 108
109 109 // Calling model.set will trigger all of the other views of the
110 110 // model to update.
111 111 that.model.set("selected_index", index, {updated_view: that});
112 112 that.touch();
113 113 })
114 114 .text('Page ' + index)
115 115 .appendTo(accordion_heading);
116 116 var accordion_body = $('<div />', {id: uuid})
117 117 .addClass('panel-collapse collapse')
118 118 .appendTo(accordion_group);
119 119 var accordion_inner = $('<div />')
120 120 .addClass('panel-body')
121 121 .appendTo(accordion_body);
122 122 var container_index = this.containers.push(accordion_group) - 1;
123 123 accordion_group.container_index = container_index;
124 124 this.model_containers[model.id] = accordion_group;
125 125 accordion_inner.append(view.$el);
126 126
127 127 this.update();
128 128 this.update_titles();
129 129
130 130 // Trigger the displayed event if this model is displayed.
131 131 if (this.is_displayed) {
132 132 view.trigger('displayed');
133 133 }
134 134 },
135 135 });
136 136
137 137
138 138 var TabView = widget.DOMWidgetView.extend({
139 139 initialize: function() {
140 140 // Public constructor.
141 141 this.containers = [];
142 142 TabView.__super__.initialize.apply(this, arguments);
143 143 },
144 144
145 145 render: function(){
146 146 // Called when view is rendered.
147 147 var uuid = 'tabs'+utils.uuid();
148 148 var that = this;
149 149 this.$tabs = $('<div />', {id: uuid})
150 150 .addClass('nav')
151 151 .addClass('nav-tabs')
152 152 .appendTo(this.$el);
153 153 this.$tab_contents = $('<div />', {id: uuid + 'Content'})
154 154 .addClass('tab-content')
155 155 .appendTo(this.$el);
156 156 this.containers = [];
157 157 this.update_children([], this.model.get('children'));
158 158 this.model.on('change:children', function(model, value, options) {
159 159 this.update_children(model.previous('children'), value);
160 160 }, this);
161 161
162 162 // Trigger model displayed events for any models that are child to
163 163 // this model when this model is displayed.
164 164 this.on('displayed', function(){
165 165 that.is_displayed = true;
166 166 for (var property in that.child_views) {
167 167 if (that.child_views.hasOwnProperty(property)) {
168 168 that.child_views[property].trigger('displayed');
169 169 }
170 170 }
171 171 });
172 172 },
173 173
174 174 update_children: function(old_list, new_list) {
175 175 // Called when the children list is modified.
176 176 this.do_diff(old_list,
177 177 new_list,
178 178 $.proxy(this.remove_child_model, this),
179 179 $.proxy(this.add_child_model, this));
180 180 },
181 181
182 182 remove_child_model: function(model) {
183 183 // Called when a child is removed from children list.
184 184 var view = this.pop_child_view(model);
185 185 this.containers.splice(view.parent_tab.tab_text_index, 1);
186 186 view.parent_tab.remove();
187 187 view.parent_container.remove();
188 188 view.remove();
189 189 },
190 190
191 191 add_child_model: function(model) {
192 192 // Called when a child is added to children list.
193 193 var view = this.create_child_view(model);
194 194 var index = this.containers.length;
195 195 var uuid = utils.uuid();
196 196
197 197 var that = this;
198 198 var tab = $('<li />')
199 199 .css('list-style-type', 'none')
200 200 .appendTo(this.$tabs);
201 201 view.parent_tab = tab;
202 202
203 203 var tab_text = $('<a />')
204 204 .attr('href', '#' + uuid)
205 205 .attr('data-toggle', 'tab')
206 206 .text('Page ' + index)
207 207 .appendTo(tab)
208 208 .click(function (e) {
209 209
210 210 // Calling model.set will trigger all of the other views of the
211 211 // model to update.
212 212 that.model.set("selected_index", index, {updated_view: this});
213 213 that.touch();
214 214 that.select_page(index);
215 215 });
216 216 tab.tab_text_index = this.containers.push(tab_text) - 1;
217 217
218 218 var contents_div = $('<div />', {id: uuid})
219 219 .addClass('tab-pane')
220 220 .addClass('fade')
221 221 .append(view.$el)
222 222 .appendTo(this.$tab_contents);
223 223 view.parent_container = contents_div;
224 224
225 225 // Trigger the displayed event if this model is displayed.
226 226 if (this.is_displayed) {
227 227 view.trigger('displayed');
228 228 }
229 229 },
230 230
231 231 update: function(options) {
232 232 // Update the contents of this view
233 233 //
234 234 // Called when the model is changed. The model may have been
235 235 // changed by another view or by a state update from the back-end.
236 236 if (options === undefined || options.updated_view != this) {
237 237 // Set tab titles
238 238 var titles = this.model.get('_titles');
239 239 var that = this;
240 240 _.each(titles, function(title, page_index) {
241 241 var tab_text = that.containers[page_index];
242 242 if (tab_text !== undefined) {
243 243 tab_text.text(title);
244 244 }
245 245 });
246 246
247 247 var selected_index = this.model.get('selected_index');
248 248 if (0 <= selected_index && selected_index < this.containers.length) {
249 249 this.select_page(selected_index);
250 250 }
251 251 }
252 252 return TabView.__super__.update.apply(this);
253 253 },
254 254
255 255 select_page: function(index) {
256 256 // Select a page.
257 257 this.$tabs.find('li')
258 258 .removeClass('active');
259 259 this.containers[index].tab('show');
260 260 },
261 261 });
262 262
263 263 return {
264 264 'AccordionView': AccordionView,
265 265 'TabView': TabView,
266 266 };
267 267 });
@@ -1,242 +1,242 b''
1 1 // Copyright (c) IPython Development Team.
2 2 // Distributed under the terms of the Modified BSD License.
3 3
4 4 define([
5 5 "widgets/js/widget",
6 6 "jquery",
7 "components/bootstrap/js/bootstrap.min",
7 "bootstrap",
8 8 ], function(widget, $){
9 9
10 10 var HTMLView = widget.DOMWidgetView.extend({
11 11 render : function(){
12 12 // Called when view is rendered.
13 13 this.update(); // Set defaults.
14 14 },
15 15
16 16 update : function(){
17 17 // Update the contents of this view
18 18 //
19 19 // Called when the model is changed. The model may have been
20 20 // changed by another view or by a state update from the back-end.
21 21 this.$el.html(this.model.get('value')); // CAUTION! .html(...) CALL MANDITORY!!!
22 22 return HTMLView.__super__.update.apply(this);
23 23 },
24 24 });
25 25
26 26
27 27 var LatexView = widget.DOMWidgetView.extend({
28 28 render : function(){
29 29 // Called when view is rendered.
30 30 this.update(); // Set defaults.
31 31 },
32 32
33 33 update : function(){
34 34 // Update the contents of this view
35 35 //
36 36 // Called when the model is changed. The model may have been
37 37 // changed by another view or by a state update from the back-end.
38 38 this.$el.text(this.model.get('value'));
39 39 MathJax.Hub.Queue(["Typeset",MathJax.Hub,this.$el.get(0)]);
40 40
41 41 return LatexView.__super__.update.apply(this);
42 42 },
43 43 });
44 44
45 45
46 46 var TextareaView = widget.DOMWidgetView.extend({
47 47 render: function(){
48 48 // Called when view is rendered.
49 49 this.$el
50 50 .addClass('widget-hbox');
51 51 this.$label = $('<div />')
52 52 .appendTo(this.$el)
53 53 .addClass('widget-hlabel')
54 54 .hide();
55 55 this.$textbox = $('<textarea />')
56 56 .attr('rows', 5)
57 57 .addClass('widget-text form-control')
58 58 .appendTo(this.$el);
59 59 this.$el_to_style = this.$textbox; // Set default element to style
60 60 this.update(); // Set defaults.
61 61
62 62 this.model.on('msg:custom', $.proxy(this._handle_textarea_msg, this));
63 63 this.model.on('change:placeholder', function(model, value, options) {
64 64 this.update_placeholder(value);
65 65 }, this);
66 66
67 67 this.update_placeholder();
68 68 },
69 69
70 70 _handle_textarea_msg: function (content){
71 71 // Handle when a custom msg is recieved from the back-end.
72 72 if (content.method == "scroll_to_bottom") {
73 73 this.scroll_to_bottom();
74 74 }
75 75 },
76 76
77 77 update_placeholder: function(value) {
78 78 if (!value) {
79 79 value = this.model.get('placeholder');
80 80 }
81 81 this.$textbox.attr('placeholder', value);
82 82 },
83 83
84 84 scroll_to_bottom: function (){
85 85 // Scroll the text-area view to the bottom.
86 86 this.$textbox.scrollTop(this.$textbox[0].scrollHeight);
87 87 },
88 88
89 89 update: function(options){
90 90 // Update the contents of this view
91 91 //
92 92 // Called when the model is changed. The model may have been
93 93 // changed by another view or by a state update from the back-end.
94 94 if (options === undefined || options.updated_view != this) {
95 95 this.$textbox.val(this.model.get('value'));
96 96
97 97 var disabled = this.model.get('disabled');
98 98 this.$textbox.prop('disabled', disabled);
99 99
100 100 var description = this.model.get('description');
101 101 if (description.length === 0) {
102 102 this.$label.hide();
103 103 } else {
104 104 this.$label.text(description);
105 105 MathJax.Hub.Queue(["Typeset",MathJax.Hub,this.$label.get(0)]);
106 106 this.$label.show();
107 107 }
108 108 }
109 109 return TextareaView.__super__.update.apply(this);
110 110 },
111 111
112 112 events: {
113 113 // Dictionary of events and their handlers.
114 114 "keyup textarea" : "handleChanging",
115 115 "paste textarea" : "handleChanging",
116 116 "cut textarea" : "handleChanging"
117 117 },
118 118
119 119 handleChanging: function(e) {
120 120 // Handles and validates user input.
121 121
122 122 // Calling model.set will trigger all of the other views of the
123 123 // model to update.
124 124 this.model.set('value', e.target.value, {updated_view: this});
125 125 this.touch();
126 126 },
127 127 });
128 128
129 129
130 130 var TextView = widget.DOMWidgetView.extend({
131 131 render: function(){
132 132 // Called when view is rendered.
133 133 this.$el
134 134 .addClass('widget-hbox-single');
135 135 this.$label = $('<div />')
136 136 .addClass('widget-hlabel')
137 137 .appendTo(this.$el)
138 138 .hide();
139 139 this.$textbox = $('<input type="text" />')
140 140 .addClass('input')
141 141 .addClass('widget-text form-control')
142 142 .appendTo(this.$el);
143 143 this.$el_to_style = this.$textbox; // Set default element to style
144 144 this.update(); // Set defaults.
145 145 this.model.on('change:placeholder', function(model, value, options) {
146 146 this.update_placeholder(value);
147 147 }, this);
148 148
149 149 this.update_placeholder();
150 150 },
151 151
152 152 update_placeholder: function(value) {
153 153 if (!value) {
154 154 value = this.model.get('placeholder');
155 155 }
156 156 this.$textbox.attr('placeholder', value);
157 157 },
158 158
159 159 update: function(options){
160 160 // Update the contents of this view
161 161 //
162 162 // Called when the model is changed. The model may have been
163 163 // changed by another view or by a state update from the back-end.
164 164 if (options === undefined || options.updated_view != this) {
165 165 if (this.$textbox.val() != this.model.get('value')) {
166 166 this.$textbox.val(this.model.get('value'));
167 167 }
168 168
169 169 var disabled = this.model.get('disabled');
170 170 this.$textbox.prop('disabled', disabled);
171 171
172 172 var description = this.model.get('description');
173 173 if (description.length === 0) {
174 174 this.$label.hide();
175 175 } else {
176 176 this.$label.text(description);
177 177 MathJax.Hub.Queue(["Typeset",MathJax.Hub,this.$label.get(0)]);
178 178 this.$label.show();
179 179 }
180 180 }
181 181 return TextView.__super__.update.apply(this);
182 182 },
183 183
184 184 events: {
185 185 // Dictionary of events and their handlers.
186 186 "keyup input" : "handleChanging",
187 187 "paste input" : "handleChanging",
188 188 "cut input" : "handleChanging",
189 189 "keypress input" : "handleKeypress",
190 190 "blur input" : "handleBlur",
191 191 "focusout input" : "handleFocusOut"
192 192 },
193 193
194 194 handleChanging: function(e) {
195 195 // Handles user input.
196 196
197 197 // Calling model.set will trigger all of the other views of the
198 198 // model to update.
199 199 this.model.set('value', e.target.value, {updated_view: this});
200 200 this.touch();
201 201 },
202 202
203 203 handleKeypress: function(e) {
204 204 // Handles text submition
205 205 if (e.keyCode == 13) { // Return key
206 206 this.send({event: 'submit'});
207 207 event.stopPropagation();
208 208 event.preventDefault();
209 209 return false;
210 210 }
211 211 },
212 212
213 213 handleBlur: function(e) {
214 214 // Prevent a blur from firing if the blur was not user intended.
215 215 // This is a workaround for the return-key focus loss bug.
216 216 // TODO: Is the original bug actually a fault of the keyboard
217 217 // manager?
218 218 if (e.relatedTarget === null) {
219 219 event.stopPropagation();
220 220 event.preventDefault();
221 221 return false;
222 222 }
223 223 },
224 224
225 225 handleFocusOut: function(e) {
226 226 // Prevent a blur from firing if the blur was not user intended.
227 227 // This is a workaround for the return-key focus loss bug.
228 228 if (e.relatedTarget === null) {
229 229 event.stopPropagation();
230 230 event.preventDefault();
231 231 return false;
232 232 }
233 233 },
234 234 });
235 235
236 236 return {
237 237 'HTMLView': HTMLView,
238 238 'LatexView': LatexView,
239 239 'TextareaView': TextareaView,
240 240 'TextView': TextView,
241 241 };
242 242 });
@@ -1,99 +1,105 b''
1 1 <!DOCTYPE HTML>
2 2 <html>
3 3
4 4 <head>
5 5 <meta charset="utf-8">
6 6
7 7 <title>{% block title %}IPython Notebook{% endblock %}</title>
8 8 <link rel="shortcut icon" type="image/x-icon" href="{{static_url("base/images/favicon.ico") }}">
9 9 <meta http-equiv="X-UA-Compatible" content="chrome=1">
10 10 <link rel="stylesheet" href="{{static_url("components/jquery-ui/themes/smoothness/jquery-ui.min.css") }}" type="text/css" />
11 11 <meta name="viewport" content="width=device-width, initial-scale=1.0">
12 12
13 13 {% block stylesheet %}
14 14 <link rel="stylesheet" href="{{ static_url("style/style.min.css") }}" type="text/css"/>
15 15 {% endblock %}
16 16 <link rel="stylesheet" href="{{ static_url("custom/custom.css") }}" type="text/css" />
17 17 <script src="{{static_url("components/requirejs/require.js") }}" type="text/javascript" charset="utf-8"></script>
18 18 <script>
19 19 require.config({
20 20 baseUrl: '{{static_url("", include_version=False)}}',
21 21 paths: {
22 22 nbextensions : '{{ base_url }}nbextensions',
23 23 underscore : 'components/underscore/underscore-min',
24 24 backbone : 'components/backbone/backbone-min',
25 25 jquery: 'components/jquery/jquery.min',
26 bootstrap: 'components/bootstrap/js/bootstrap.min',
26 27 bootstraptour: 'components/bootstrap-tour/build/js/bootstrap-tour.min',
27 28 dateformat: 'dateformat/date.format',
28 29 jqueryui: 'components/jquery-ui/ui/minified/jquery-ui.min',
29 30 },
30 31 shim: {
31 32 underscore: {
32 33 exports: '_'
33 34 },
34 35 backbone: {
35 36 deps: ["underscore", "jquery"],
36 37 exports: "Backbone"
37 38 },
39 bootstrap: {
40 deps: ["jquery"],
41 exports: "bootstrap"
42 },
38 43 bootstraptour: {
44 deps: ["bootstrap"],
39 45 exports: "Tour"
40 46 },
41 47 dateformat: {
42 48 exports: "dateFormat"
43 49 },
44 50 jqueryui: {
45 51 deps: ["jquery"],
46 52 exports: "$"
47 53 }
48 54 }
49 55 });
50 56 </script>
51 57
52 58 {% block meta %}
53 59 {% endblock %}
54 60
55 61 </head>
56 62
57 63 <body {% block params %}{% endblock %}>
58 64
59 65 <noscript>
60 66 <div id='noscript'>
61 67 IPython Notebook requires JavaScript.<br>
62 68 Please enable it to proceed.
63 69 </div>
64 70 </noscript>
65 71
66 72 <div id="header" class="navbar navbar-static-top">
67 73 <div class="container">
68 74 <div id="ipython_notebook" class="nav navbar-brand pull-left"><a href="{{base_url}}tree/{{notebook_path}}" alt='dashboard'><img src='{{static_url("base/images/ipynblogo.png") }}' alt='IPython Notebook'/></a></div>
69 75
70 76 {% block login_widget %}
71 77
72 78 <span id="login_widget">
73 79 {% if logged_in %}
74 80 <button id="logout">Logout</button>
75 81 {% elif login_available and not logged_in %}
76 82 <button id="login">Login</button>
77 83 {% endif %}
78 84 </span>
79 85
80 86 {% endblock %}
81 87
82 88 {% block header %}
83 89 {% endblock %}
84 90 </div>
85 91 </div>
86 92
87 93 <div id="site">
88 94 {% block site %}
89 95 {% endblock %}
90 96 </div>
91 97
92 98 {% block script %}
93 99 {% endblock %}
94 100
95 101 <script src="{{static_url("custom/custom.js") }}" type="text/javascript" charset="utf-8"></script>
96 102
97 103 </body>
98 104
99 105 </html>
General Comments 0
You need to be logged in to leave comments. Login now