##// END OF EJS Templates
Added require.js shims for underscore and backbone...
Jonathan Frederic -
Show More
@@ -1,129 +1,129 b''
1 1 //----------------------------------------------------------------------------
2 2 // Copyright (C) 2013 The IPython Development Team
3 3 //
4 4 // Distributed under the terms of the BSD License. The full license is in
5 5 // the file COPYING, distributed as part of this software.
6 6 //----------------------------------------------------------------------------
7 7
8 8 //============================================================================
9 9 // WidgetModel, WidgetView, and WidgetManager
10 10 //============================================================================
11 11 /**
12 12 * Base Widget classes
13 13 * @module IPython
14 14 * @namespace IPython
15 15 * @submodule widget
16 16 */
17 17
18 18 (function () {
19 19 "use strict";
20 20
21 21 // Use require.js 'define' method so that require.js is intelligent enough to
22 22 // syncronously load everything within this file when it is being 'required'
23 23 // elsewhere.
24 define(["components/underscore/underscore-min",
25 "components/backbone/backbone-min",
24 define(["underscore",
25 "backbone",
26 26 ], function (underscore, backbone) {
27 27
28 28 //--------------------------------------------------------------------
29 29 // WidgetManager class
30 30 //--------------------------------------------------------------------
31 31 var WidgetManager = function () {
32 32 this.comm_manager = null;
33 33 this.widget_model_types = {};
34 34 this.widget_view_types = {};
35 35 this._model_instances = {};
36 36
37 37 Backbone.sync = function (method, model, options, error) {
38 38 var result = model._handle_sync(method, options);
39 39 if (options.success) {
40 40 options.success(result);
41 41 }
42 42 };
43 43 };
44 44
45 45
46 46 WidgetManager.prototype.attach_comm_manager = function (comm_manager) {
47 47 this.comm_manager = comm_manager;
48 48
49 49 // Register already register widget model types with the comm manager.
50 50 for (var widget_model_name in this.widget_model_types) {
51 51 this.comm_manager.register_target(widget_model_name, $.proxy(this._handle_com_open, this));
52 52 }
53 53 };
54 54
55 55
56 56 WidgetManager.prototype.register_widget_model = function (widget_model_name, widget_model_type) {
57 57 // Register the widget with the comm manager. Make sure to pass this object's context
58 58 // in so `this` works in the call back.
59 59 if (this.comm_manager !== null) {
60 60 this.comm_manager.register_target(widget_model_name, $.proxy(this._handle_com_open, this));
61 61 }
62 62 this.widget_model_types[widget_model_name] = widget_model_type;
63 63 };
64 64
65 65
66 66 WidgetManager.prototype.register_widget_view = function (widget_view_name, widget_view_type) {
67 67 this.widget_view_types[widget_view_name] = widget_view_type;
68 68 };
69 69
70 70
71 71 WidgetManager.prototype.get_msg_cell = function (msg_id) {
72 72 if (IPython.notebook !== undefined && IPython.notebook !== null) {
73 73 return IPython.notebook.get_msg_cell(msg_id);
74 74 }
75 75 };
76 76
77 77
78 78 WidgetManager.prototype.get_model = function (widget_id) {
79 79 var model = this._model_instances[widget_id];
80 80 if (model !== undefined && model.id == widget_id) {
81 81 return model;
82 82 }
83 83 return null;
84 84 };
85 85
86 86
87 87 WidgetManager.prototype.get_kernel = function () {
88 88 if (this.comm_manager === null) {
89 89 return null;
90 90 } else {
91 91 return this.comm_manager.kernel;
92 92 }
93 93 };
94 94
95 95
96 96 WidgetManager.prototype.on_create_widget = function (callback) {
97 97 this._create_widget_callback = callback;
98 98 };
99 99
100 100
101 101 WidgetManager.prototype._handle_create_widget = function (widget_model) {
102 102 if (this._create_widget_callback) {
103 103 try {
104 104 this._create_widget_callback(widget_model);
105 105 } catch (e) {
106 106 console.log("Exception in WidgetManager callback", e, widget_model);
107 107 }
108 108 }
109 109 };
110 110
111 111
112 112 WidgetManager.prototype._handle_com_open = function (comm, msg) {
113 113 var widget_type_name = msg.content.target_name;
114 114 var widget_model = new this.widget_model_types[widget_type_name](this, comm.comm_id, comm);
115 115 this._model_instances[comm.comm_id] = widget_model;
116 116 this._handle_create_widget(widget_model);
117 117 };
118 118
119 119 //--------------------------------------------------------------------
120 120 // Init code
121 121 //--------------------------------------------------------------------
122 122 IPython.WidgetManager = WidgetManager;
123 123 if (IPython.widget_manager === undefined || IPython.widget_manager === null) {
124 124 IPython.widget_manager = new WidgetManager();
125 125 }
126 126
127 127 return IPython.widget_manager;
128 128 });
129 129 }()); No newline at end of file
@@ -1,555 +1,555 b''
1 1 //----------------------------------------------------------------------------
2 2 // Copyright (C) 2013 The IPython Development Team
3 3 //
4 4 // Distributed under the terms of the BSD License. The full license is in
5 5 // the file COPYING, distributed as part of this software.
6 6 //----------------------------------------------------------------------------
7 7
8 8 //============================================================================
9 9 // Base Widget Model and View classes
10 10 //============================================================================
11 11
12 12 /**
13 13 * @module IPython
14 14 * @namespace IPython
15 15 **/
16 16
17 17 define(["notebook/js/widgetmanager",
18 "components/underscore/underscore-min",
19 "components/backbone/backbone-min"],
18 "underscore",
19 "backbone"],
20 20 function(widget_manager, underscore, backbone){
21 21
22 22 //--------------------------------------------------------------------
23 23 // WidgetModel class
24 24 //--------------------------------------------------------------------
25 25 var WidgetModel = Backbone.Model.extend({
26 26 constructor: function (widget_manager, widget_id, comm) {
27 27 this.widget_manager = widget_manager;
28 28 this.pending_msgs = 0;
29 29 this.msg_throttle = 3;
30 30 this.msg_buffer = null;
31 31 this.views = [];
32 32 this.id = widget_id;
33 33 this._custom_msg_callbacks = [];
34 34
35 35 if (comm !== undefined) {
36 36
37 37 // Remember comm associated with the model.
38 38 this.comm = comm;
39 39 comm.model = this;
40 40
41 41 // Hook comm messages up to model.
42 42 comm.on_close($.proxy(this._handle_comm_closed, this));
43 43 comm.on_msg($.proxy(this._handle_comm_msg, this));
44 44 }
45 45
46 46 return Backbone.Model.apply(this);
47 47 },
48 48
49 49
50 50 send: function (content, cell) {
51 51 if (this._has_comm()) {
52 52 // Used the last modified view as the sender of the message. This
53 53 // will insure that any python code triggered by the sent message
54 54 // can create and display widgets and output.
55 55 if (cell === undefined) {
56 56 if (this.last_modified_view !== undefined &&
57 57 this.last_modified_view.cell !== undefined) {
58 58 cell = this.last_modified_view.cell;
59 59 }
60 60 }
61 61 var callbacks = this._make_callbacks(cell);
62 62 var data = {method: 'custom', custom_content: content};
63 63
64 64 this.comm.send(data, callbacks);
65 65 }
66 66 },
67 67
68 68
69 69 on_view_created: function (callback) {
70 70 this._view_created_callback = callback;
71 71 },
72 72
73 73
74 74 on_close: function (callback) {
75 75 this._close_callback = callback;
76 76 },
77 77
78 78
79 79 on_msg: function (callback, remove) {
80 80 if (remove) {
81 81 var found_index = -1;
82 82 for (var index in this._custom_msg_callbacks) {
83 83 if (callback === this._custom_msg_callbacks[index]) {
84 84 found_index = index;
85 85 break;
86 86 }
87 87 }
88 88
89 89 if (found_index >= 0) {
90 90 this._custom_msg_callbacks.splice(found_index, 1);
91 91 }
92 92 } else {
93 93 this._custom_msg_callbacks.push(callback);
94 94 }
95 95 },
96 96
97 97
98 98 _handle_custom_msg: function (content) {
99 99 for (var index in this._custom_msg_callbacks) {
100 100 try {
101 101 this._custom_msg_callbacks[index](content);
102 102 } catch (e) {
103 103 console.log("Exception in widget model msg callback", e, content);
104 104 }
105 105 }
106 106 },
107 107
108 108
109 109 // Handle when a widget is closed.
110 110 _handle_comm_closed: function (msg) {
111 111 this._execute_views_method('remove');
112 112 if (this._has_comm()) {
113 113 delete this.comm.model; // Delete ref so GC will collect widget model.
114 114 delete this.comm;
115 115 }
116 116 delete this.widget_id; // Delete id from model so widget manager cleans up.
117 117 },
118 118
119 119
120 120 // Handle incomming comm msg.
121 121 _handle_comm_msg: function (msg) {
122 122 var method = msg.content.data.method;
123 123 switch (method) {
124 124 case 'display':
125 125
126 126 // Try to get the cell.
127 127 var cell = this._get_msg_cell(msg.parent_header.msg_id);
128 128 if (cell === null) {
129 129 console.log("Could not determine where the display" +
130 130 " message was from. Widget will not be displayed");
131 131 } else {
132 132 this.create_views(msg.content.data.view_name,
133 133 msg.content.data.parent,
134 134 cell);
135 135 }
136 136 break;
137 137 case 'update':
138 138 this.apply_update(msg.content.data.state);
139 139 break;
140 140 case 'add_class':
141 141 case 'remove_class':
142 142 var selector = msg.content.data.selector;
143 143 if (selector === undefined) {
144 144 selector = '';
145 145 }
146 146
147 147 var class_list = msg.content.data.class_list;
148 148 this._execute_views_method(method, selector, class_list);
149 149 break;
150 150 case 'set_snapshot':
151 151 var cell = this._get_msg_cell(msg.parent_header.msg_id);
152 152 cell.metadata.snapshot = msg.content.data.snapshot;
153 153 break;
154 154 case 'custom':
155 155 this._handle_custom_msg(msg.content.data.custom_content);
156 156 break;
157 157 }
158 158 },
159 159
160 160
161 161 // Handle when a widget is updated via the python side.
162 162 apply_update: function (state) {
163 163 this.updating = true;
164 164 try {
165 165 for (var key in state) {
166 166 if (state.hasOwnProperty(key)) {
167 167 if (key == "_css") {
168 168
169 169 // Set the css value of the model as an attribute
170 170 // instead of a backbone trait because we are only
171 171 // interested in backend css -> frontend css. In
172 172 // other words, if the css dict changes in the
173 173 // frontend, we don't need to push the changes to
174 174 // the backend.
175 175 this.css = state[key];
176 176 } else {
177 177 this.set(key, state[key]);
178 178 }
179 179 }
180 180 }
181 181 this.save();
182 182 } finally {
183 183 this.updating = false;
184 184 }
185 185 },
186 186
187 187
188 188 _handle_status: function (cell, msg) {
189 189 //execution_state : ('busy', 'idle', 'starting')
190 190 if (this._has_comm()) {
191 191 if (msg.content.execution_state=='idle') {
192 192
193 193 // Send buffer if this message caused another message to be
194 194 // throttled.
195 195 if (this.msg_buffer !== null &&
196 196 this.msg_throttle == this.pending_msgs) {
197 197
198 198 var callbacks = this._make_callbacks(cell);
199 199 var data = {method: 'backbone', sync_method: 'update', sync_data: this.msg_buffer};
200 200 this.comm.send(data, callbacks);
201 201 this.msg_buffer = null;
202 202 } else {
203 203
204 204 // Only decrease the pending message count if the buffer
205 205 // doesn't get flushed (sent).
206 206 --this.pending_msgs;
207 207 }
208 208 }
209 209 }
210 210 },
211 211
212 212
213 213 // Custom syncronization logic.
214 214 _handle_sync: function (method, options) {
215 215 var model_json = this.toJSON();
216 216 var attr;
217 217
218 218 // Only send updated state if the state hasn't been changed
219 219 // during an update.
220 220 if (this._has_comm()) {
221 221 if (!this.updating) {
222 222 if (this.pending_msgs >= this.msg_throttle) {
223 223 // The throttle has been exceeded, buffer the current msg so
224 224 // it can be sent once the kernel has finished processing
225 225 // some of the existing messages.
226 226 if (method=='patch') {
227 227 if (this.msg_buffer === null) {
228 228 this.msg_buffer = $.extend({}, model_json); // Copy
229 229 }
230 230 for (attr in options.attrs) {
231 231 this.msg_buffer[attr] = options.attrs[attr];
232 232 }
233 233 } else {
234 234 this.msg_buffer = $.extend({}, model_json); // Copy
235 235 }
236 236
237 237 } else {
238 238 // We haven't exceeded the throttle, send the message like
239 239 // normal. If this is a patch operation, just send the
240 240 // changes.
241 241 var send_json = model_json;
242 242 if (method =='patch') {
243 243 send_json = {};
244 244 for (attr in options.attrs) {
245 245 send_json[attr] = options.attrs[attr];
246 246 }
247 247 }
248 248
249 249 var data = {method: 'backbone', sync_method: method, sync_data: send_json};
250 250
251 251 var cell = null;
252 252 if (this.last_modified_view !== undefined && this.last_modified_view !== null) {
253 253 cell = this.last_modified_view.cell;
254 254 }
255 255
256 256 var callbacks = this._make_callbacks(cell);
257 257 this.comm.send(data, callbacks);
258 258 this.pending_msgs++;
259 259 }
260 260 }
261 261 }
262 262
263 263 // Since the comm is a one-way communication, assume the message
264 264 // arrived.
265 265 return model_json;
266 266 },
267 267
268 268
269 269 _handle_view_created: function (view) {
270 270 if (this._view_created_callback) {
271 271 try {
272 272 this._view_created_callback(view);
273 273 } catch (e) {
274 274 console.log("Exception in widget model view displayed callback", e, view, this);
275 275 }
276 276 }
277 277 },
278 278
279 279
280 280 _execute_views_method: function (/* method_name, [argument0], [argument1], [...] */) {
281 281 var method_name = arguments[0];
282 282 var args = null;
283 283 if (arguments.length > 1) {
284 284 args = [].splice.call(arguments,1);
285 285 }
286 286
287 287 for (var view_index in this.views) {
288 288 var view = this.views[view_index];
289 289 var method = view[method_name];
290 290 if (args === null) {
291 291 method.apply(view);
292 292 } else {
293 293 method.apply(view, args);
294 294 }
295 295 }
296 296 },
297 297
298 298
299 299 // Create view that represents the model.
300 300 create_views: function (view_name, parent_id, cell) {
301 301 var new_views = [];
302 302 var view;
303 303
304 304 // Try creating and adding the view to it's parent.
305 305 var displayed = false;
306 306 if (parent_id !== undefined) {
307 307 var parent_model = this.widget_manager.get_model(parent_id);
308 308 if (parent_model !== null) {
309 309 var parent_views = parent_model.views;
310 310 for (var parent_view_index in parent_views) {
311 311 var parent_view = parent_views[parent_view_index];
312 312 if (parent_view.cell === cell) {
313 313 if (parent_view.display_child !== undefined) {
314 314 view = this._create_view(view_name, cell);
315 315 if (view !== null) {
316 316 new_views.push(view);
317 317 parent_view.display_child(view);
318 318 displayed = true;
319 319 this._handle_view_created(view);
320 320 }
321 321 }
322 322 }
323 323 }
324 324 }
325 325 }
326 326
327 327 // If no parent view is defined or exists. Add the view's
328 328 // element to cell's widget div.
329 329 if (!displayed) {
330 330 view = this._create_view(view_name, cell);
331 331 if (view !== null) {
332 332 new_views.push(view);
333 333
334 334 if (cell.widget_subarea !== undefined && cell.widget_subarea !== null) {
335 335 cell.widget_area.show();
336 336 cell.widget_subarea.append(view.$el);
337 337 this._handle_view_created(view);
338 338 }
339 339 }
340 340 }
341 341
342 342 // Force the new view(s) to update their selves
343 343 for (var view_index in new_views) {
344 344 view = new_views[view_index];
345 345 view.update();
346 346 }
347 347 },
348 348
349 349
350 350 // Create a view
351 351 _create_view: function (view_name, cell) {
352 352 var ViewType = this.widget_manager.widget_view_types[view_name];
353 353 if (ViewType !== undefined && ViewType !== null) {
354 354 var view = new ViewType({model: this});
355 355 view.render();
356 356 this.views.push(view);
357 357 view.cell = cell;
358 358
359 359 // Handle when the view element is remove from the page.
360 360 var that = this;
361 361 view.$el.on("remove", function () {
362 362 var index = that.views.indexOf(view);
363 363 if (index > -1) {
364 364 that.views.splice(index, 1);
365 365 }
366 366 view.remove(); // Clean-up view
367 367
368 368 // Close the comm if there are no views left.
369 369 if (that.views.length() === 0) {
370 370 if (that._close_callback) {
371 371 try {
372 372 that._close_callback(that);
373 373 } catch (e) {
374 374 console.log("Exception in widget model close callback", e, that);
375 375 }
376 376 }
377 377
378 378 if (that._has_comm()) {
379 379 that.comm.close();
380 380 delete that.comm.model; // Delete ref so GC will collect widget model.
381 381 delete that.comm;
382 382 }
383 383 delete that.widget_id; // Delete id from model so widget manager cleans up.
384 384 }
385 385 });
386 386 return view;
387 387 }
388 388 return null;
389 389 },
390 390
391 391
392 392 // Build a callback dict.
393 393 _make_callbacks: function (cell) {
394 394 var callbacks = {};
395 395 if (cell !== null) {
396 396
397 397 // Try to get output handlers
398 398 var handle_output = null;
399 399 var handle_clear_output = null;
400 400 if (cell.output_area !== undefined && cell.output_area !== null) {
401 401 handle_output = $.proxy(cell.output_area.handle_output, cell.output_area);
402 402 handle_clear_output = $.proxy(cell.output_area.handle_clear_output, cell.output_area);
403 403 }
404 404
405 405 // Create callback dict usign what is known
406 406 var that = this;
407 407 callbacks = {
408 408 iopub : {
409 409 output : handle_output,
410 410 clear_output : handle_clear_output,
411 411
412 412 status : function (msg) {
413 413 that._handle_status(cell, msg);
414 414 },
415 415
416 416 // Special function only registered by widget messages.
417 417 // Allows us to get the cell for a message so we know
418 418 // where to add widgets if the code requires it.
419 419 get_cell : function () {
420 420 return cell;
421 421 },
422 422 },
423 423 };
424 424 }
425 425 return callbacks;
426 426 },
427 427
428 428
429 429 // Get the output area corresponding to the msg_id.
430 430 // cell is an instance of IPython.Cell
431 431 _get_msg_cell: function (msg_id) {
432 432
433 433 // First, check to see if the msg was triggered by cell execution.
434 434 var cell = this.widget_manager.get_msg_cell(msg_id);
435 435 if (cell !== null) {
436 436 return cell;
437 437 }
438 438
439 439 // Second, check to see if a get_cell callback was defined
440 440 // for the message. get_cell callbacks are registered for
441 441 // widget messages, so this block is actually checking to see if the
442 442 // message was triggered by a widget.
443 443 var kernel = this.widget_manager.get_kernel();
444 444 if (kernel !== undefined && kernel !== null) {
445 445 var callbacks = kernel.get_callbacks_for_msg(msg_id);
446 446 if (callbacks !== undefined &&
447 447 callbacks.iopub !== undefined &&
448 448 callbacks.iopub.get_cell !== undefined) {
449 449
450 450 return callbacks.iopub.get_cell();
451 451 }
452 452 }
453 453
454 454 // Not triggered by a cell or widget (no get_cell callback
455 455 // exists).
456 456 return null;
457 457 },
458 458
459 459
460 460 // Function that checks if a comm has been attached to this widget
461 461 // model. Returns True if a valid comm is attached.
462 462 _has_comm: function() {
463 463 return this.comm !== undefined && this.comm !== null;
464 464 },
465 465 });
466 466
467 467
468 468 //--------------------------------------------------------------------
469 469 // WidgetView class
470 470 //--------------------------------------------------------------------
471 471 var WidgetView = Backbone.View.extend({
472 472
473 473 initialize: function () {
474 474 this.visible = true;
475 475 this.model.on('sync',this.update,this);
476 476 },
477 477
478 478 add_class: function (selector, class_list) {
479 479 var elements = this._get_selector_element(selector);
480 480 if (elements.length > 0) {
481 481 elements.addClass(class_list);
482 482 }
483 483 },
484 484
485 485 remove_class: function (selector, class_list) {
486 486 var elements = this._get_selector_element(selector);
487 487 if (elements.length > 0) {
488 488 elements.removeClass(class_list);
489 489 }
490 490 },
491 491
492 492
493 493 send: function (content) {
494 494 this.model.send(content, this.cell);
495 495 },
496 496
497 497
498 498 touch: function () {
499 499 this.model.last_modified_view = this;
500 500 this.model.save(this.model.changedAttributes(), {patch: true});
501 501 },
502 502
503 503 update: function () {
504 504 if (this.model.get('visible') !== undefined) {
505 505 if (this.visible != this.model.get('visible')) {
506 506 this.visible = this.model.get('visible');
507 507 if (this.visible) {
508 508 this.$el.show();
509 509 } else {
510 510 this.$el.hide();
511 511 }
512 512 }
513 513 }
514 514
515 515 if (this.model.css !== undefined) {
516 516 for (var selector in this.model.css) {
517 517 if (this.model.css.hasOwnProperty(selector)) {
518 518
519 519 // Apply the css traits to all elements that match the selector.
520 520 var elements = this._get_selector_element(selector);
521 521 if (elements.length > 0) {
522 522 var css_traits = this.model.css[selector];
523 523 for (var css_key in css_traits) {
524 524 if (css_traits.hasOwnProperty(css_key)) {
525 525 elements.css(css_key, css_traits[css_key]);
526 526 }
527 527 }
528 528 }
529 529 }
530 530 }
531 531 }
532 532 },
533 533
534 534 _get_selector_element: function (selector) {
535 535 // Get the elements via the css selector. If the selector is
536 536 // blank, apply the style to the $el_to_style element. If
537 537 // the $el_to_style element is not defined, use apply the
538 538 // style to the view's element.
539 539 var elements = this.$el.find(selector);
540 540 if (selector === undefined || selector === null || selector === '') {
541 541 if (this.$el_to_style === undefined) {
542 542 elements = this.$el;
543 543 } else {
544 544 elements = this.$el_to_style;
545 545 }
546 546 }
547 547 return elements;
548 548 },
549 549 });
550 550
551 551 IPython.WidgetModel = WidgetModel;
552 552 IPython.WidgetView = WidgetView;
553 553
554 554 return widget_manager;
555 555 }); No newline at end of file
@@ -1,85 +1,96 b''
1 1
2 2
3 3 <!DOCTYPE HTML>
4 4 <html>
5 5
6 6 <head>
7 7 <meta charset="utf-8">
8 8
9 9 <title>{% block title %}IPython Notebook{% endblock %}</title>
10 10 <link rel="shortcut icon" type="image/x-icon" href="{{static_url("base/images/favicon.ico") }}">
11 11 <meta http-equiv="X-UA-Compatible" content="chrome=1">
12 12 <link rel="stylesheet" href="{{static_url("components/jquery-ui/themes/smoothness/jquery-ui.min.css") }}" type="text/css" />
13 13 <meta name="viewport" content="width=device-width, initial-scale=1.0">
14 14
15 15 {% block stylesheet %}
16 16 <link rel="stylesheet" href="{{ static_url("style/style.min.css") }}" type="text/css"/>
17 17 {% endblock %}
18 18 <link rel="stylesheet" href="{{ static_url("custom/custom.css") }}" type="text/css" />
19 19 <script src="{{static_url("components/requirejs/require.js") }}" type="text/javascript" charset="utf-8"></script>
20 20 <script>
21 21 require.config({
22 22 baseUrl: '{{static_url("")}}',
23 23 paths: {
24 nbextensions : '{{ base_project_url }}nbextensions'
24 nbextensions : '{{ base_project_url }}nbextensions',
25 underscore : '{{static_url()}}components/underscore/underscore-min',
26 backbone : '{{static_url()}}components/backbone/backbone-min',
27 },
28 shim: {
29 underscore: {
30 exports: '_'
31 },
32 backbone: {
33 deps: ["underscore", "jquery"],
34 exports: "Backbone"
35 }
25 36 }
26 37 });
27 38 </script>
28 39
29 40 {% block meta %}
30 41 {% endblock %}
31 42
32 43 </head>
33 44
34 45 <body {% block params %}{% endblock %}>
35 46
36 47 <noscript>
37 48 <div id='noscript'>
38 49 IPython Notebook requires JavaScript.<br>
39 50 Please enable it to proceed.
40 51 </div>
41 52 </noscript>
42 53
43 54 <div id="header" class="navbar navbar-static-top">
44 55 <div class="navbar-inner navbar-nobg">
45 56 <div class="container">
46 57 <div id="ipython_notebook" class="nav brand pull-left"><a href="{{base_project_url}}tree/{{notebook_path}}" alt='dashboard'><img src='{{static_url("base/images/ipynblogo.png") }}' alt='IPython Notebook'/></a></div>
47 58
48 59 {% block login_widget %}
49 60
50 61 <span id="login_widget">
51 62 {% if logged_in %}
52 63 <button id="logout">Logout</button>
53 64 {% elif login_available and not logged_in %}
54 65 <button id="login">Login</button>
55 66 {% endif %}
56 67 </span>
57 68
58 69 {% endblock %}
59 70
60 71 {% block header %}
61 72 {% endblock %}
62 73 </div>
63 74 </div>
64 75 </div>
65 76
66 77 <div id="site">
67 78 {% block site %}
68 79 {% endblock %}
69 80 </div>
70 81
71 82 <script src="{{static_url("components/jquery/jquery.min.js") }}" type="text/javascript" charset="utf-8"></script>
72 83 <script src="{{static_url("components/jquery-ui/ui/minified/jquery-ui.min.js") }}" type="text/javascript" charset="utf-8"></script>
73 84 <script src="{{static_url("components/bootstrap/bootstrap/js/bootstrap.min.js") }}" type="text/javascript" charset="utf-8"></script>
74 85 <script src="{{static_url("base/js/namespace.js") }}" type="text/javascript" charset="utf-8"></script>
75 86 <script src="{{static_url("base/js/page.js") }}" type="text/javascript" charset="utf-8"></script>
76 87 <script src="{{static_url("auth/js/loginwidget.js") }}" type="text/javascript" charset="utf-8"></script>
77 88
78 89 {% block script %}
79 90 {% endblock %}
80 91
81 92 <script src="{{static_url("custom/custom.js") }}" type="text/javascript" charset="utf-8"></script>
82 93
83 94 </body>
84 95
85 96 </html>
General Comments 0
You need to be logged in to leave comments. Login now