define([ 'base/js/namespace', 'jquery', 'base/js/utils', 'base/js/dialog', 'base/js/notificationarea', 'moment' ], function(IPython, $, utils, dialog, notificationarea, moment) { "use strict"; var NotificationArea = notificationarea.NotificationArea; var NotebookNotificationArea = function(selector, options) { NotificationArea.apply(this, [selector, options]); this.save_widget = options.save_widget; this.notebook = options.notebook; this.keyboard_manager = options.keyboard_manager; }; NotebookNotificationArea.prototype = Object.create(NotificationArea.prototype); /** * Initialize the default set of notification widgets. * * @method init_notification_widgets */ NotebookNotificationArea.prototype.init_notification_widgets = function () { this.init_kernel_notification_widget(); this.init_notebook_notification_widget(); }; /** * Initialize the notification widget for kernel status messages. * * @method init_kernel_notification_widget */ NotebookNotificationArea.prototype.init_kernel_notification_widget = function () { var that = this; var knw = this.new_notification_widget('kernel'); var $kernel_ind_icon = $("#kernel_indicator_icon"); var $modal_ind_icon = $("#modal_indicator"); var $readonly_ind_icon = $('#readonly-indicator'); var $body = $('body'); // Listen for the notebook loaded event. Set readonly indicator. this.events.on('notebook_loaded.Notebook', function() { if (that.notebook.writable) { $readonly_ind_icon.hide(); } else { $readonly_ind_icon.show(); } }); // Command/Edit mode this.events.on('edit_mode.Notebook', function () { that.save_widget.update_document_title(); $body.addClass('edit_mode'); $body.removeClass('command_mode'); $modal_ind_icon.attr('title','Edit Mode'); }); this.events.on('command_mode.Notebook', function () { that.save_widget.update_document_title(); $body.removeClass('edit_mode'); $body.addClass('command_mode'); $modal_ind_icon.attr('title','Command Mode'); }); // Implicitly start off in Command mode, switching to Edit mode will trigger event $modal_ind_icon.addClass('modal_indicator').attr('title','Command Mode'); $body.addClass('command_mode'); // Kernel events // this can be either kernel_created.Kernel or kernel_created.Session this.events.on('kernel_created.Kernel kernel_created.Session', function () { knw.info("Kernel Created", 500); }); this.events.on('kernel_reconnecting.Kernel', function () { knw.warning("Connecting to kernel"); }); this.events.on('kernel_connection_dead.Kernel', function (evt, info) { knw.danger("Not Connected", undefined, function () { // schedule reconnect a short time in the future, don't reconnect immediately setTimeout($.proxy(info.kernel.reconnect, info.kernel), 500); }, {title: 'click to reconnect'}); }); this.events.on('kernel_connected.Kernel', function () { knw.info("Connected", 500); }); this.events.on('kernel_restarting.Kernel', function () { that.save_widget.update_document_title(); knw.set_message("Restarting kernel", 2000); }); this.events.on('kernel_autorestarting.Kernel', function (evt, info) { // Only show the dialog on the first restart attempt. This // number gets tracked by the `Kernel` object and passed // along here, because we don't want to show the user 5 // dialogs saying the same thing (which is the number of // times it tries restarting). if (info.attempt === 1) { dialog.kernel_modal({ notebook: that.notebook, keyboard_manager: that.keyboard_manager, title: "Kernel Restarting", body: "The kernel appears to have died. It will restart automatically.", buttons: { OK : { class : "btn-primary" } } }); } that.save_widget.update_document_title(); knw.danger("Dead kernel"); $kernel_ind_icon.attr('class','kernel_dead_icon').attr('title','Kernel Dead'); }); this.events.on('kernel_interrupting.Kernel', function () { knw.set_message("Interrupting kernel", 2000); }); this.events.on('kernel_disconnected.Kernel', function () { $kernel_ind_icon .attr('class', 'kernel_disconnected_icon') .attr('title', 'No Connection to Kernel'); }); this.events.on('kernel_connection_failed.Kernel', function (evt, info) { // only show the dialog if this is the first failed // connect attempt, because the kernel will continue // trying to reconnect and we don't want to spam the user // with messages if (info.attempt === 1) { var msg = "A connection to the notebook server could not be established." + " The notebook will continue trying to reconnect, but" + " until it does, you will NOT be able to run code. Check your" + " network connection or notebook server configuration."; dialog.kernel_modal({ title: "Connection failed", body: msg, keyboard_manager: that.keyboard_manager, notebook: that.notebook, buttons : { "OK": {} } }); } }); this.events.on('kernel_killed.Kernel kernel_killed.Session', function () { that.save_widget.update_document_title(); knw.warning("No kernel"); $kernel_ind_icon.attr('class','kernel_busy_icon').attr('title','Kernel is not running'); }); this.events.on('kernel_dead.Kernel', function () { var showMsg = function () { var msg = 'The kernel has died, and the automatic restart has failed.' + ' It is possible the kernel cannot be restarted.' + ' If you are not able to restart the kernel, you will still be able to save' + ' the notebook, but running code will no longer work until the notebook' + ' is reopened.'; dialog.kernel_modal({ title: "Dead kernel", body : msg, keyboard_manager: that.keyboard_manager, notebook: that.notebook, buttons : { "Manual Restart": { class: "btn-danger", click: function () { that.notebook.start_session(); } }, "Don't restart": {} } }); return false; }; that.save_widget.update_document_title(); knw.danger("Dead kernel", undefined, showMsg); $kernel_ind_icon.attr('class','kernel_dead_icon').attr('title','Kernel Dead'); showMsg(); }); this.events.on("no_kernel.Kernel", function (evt, data) { $("#kernel_indicator").find('.kernel_indicator_name').text("No Kernel"); }); this.events.on('kernel_dead.Session', function (evt, info) { var full = info.xhr.responseJSON.message; var short = info.xhr.responseJSON.short_message || 'Kernel error'; var traceback = info.xhr.responseJSON.traceback; var showMsg = function () { var msg = $('
').append($('

').text(full)); var cm, cm_elem, cm_open; if (traceback) { cm_elem = $('

') .css('margin-top', '1em') .css('padding', '1em') .addClass('output_scroll'); msg.append(cm_elem); cm = CodeMirror(cm_elem.get(0), { mode: "python", readOnly : true }); cm.setValue(traceback); cm_open = $.proxy(cm.refresh, cm); } dialog.kernel_modal({ title: "Failed to start the kernel", body : msg, keyboard_manager: that.keyboard_manager, notebook: that.notebook, open: cm_open, buttons : { "Ok": { class: 'btn-primary' } } }); return false; }; that.save_widget.update_document_title(); $kernel_ind_icon.attr('class','kernel_dead_icon').attr('title','Kernel Dead'); knw.danger(short, undefined, showMsg); }); this.events.on('kernel_starting.Kernel kernel_created.Session', function () { window.document.title='(Starting) '+window.document.title; $kernel_ind_icon.attr('class','kernel_busy_icon').attr('title','Kernel Busy'); knw.set_message("Kernel starting, please wait..."); }); this.events.on('kernel_ready.Kernel', function () { that.save_widget.update_document_title(); $kernel_ind_icon.attr('class','kernel_idle_icon').attr('title','Kernel Idle'); knw.info("Kernel ready", 500); }); this.events.on('kernel_idle.Kernel', function () { that.save_widget.update_document_title(); $kernel_ind_icon.attr('class','kernel_idle_icon').attr('title','Kernel Idle'); }); this.events.on('kernel_busy.Kernel', function () { window.document.title='(Busy) '+window.document.title; $kernel_ind_icon.attr('class','kernel_busy_icon').attr('title','Kernel Busy'); }); this.events.on('spec_match_found.Kernel', function (evt, data) { that.widget('kernelspec').info("Using kernel: " + data.found.spec.display_name, 3000, undefined, { title: "Only candidate for language: " + data.selected.language + " was " + data.found.spec.display_name }); }); // Start the kernel indicator in the busy state, and send a kernel_info request. // When the kernel_info reply arrives, the kernel is idle. $kernel_ind_icon.attr('class','kernel_busy_icon').attr('title','Kernel Busy'); }; /** * Initialize the notification widget for notebook status messages. * * @method init_notebook_notification_widget */ NotebookNotificationArea.prototype.init_notebook_notification_widget = function () { var nnw = this.new_notification_widget('notebook'); // Notebook events this.events.on('notebook_loading.Notebook', function () { nnw.set_message("Loading notebook",500); }); this.events.on('notebook_loaded.Notebook', function () { nnw.set_message("Notebook loaded",500); }); this.events.on('notebook_saving.Notebook', function () { nnw.set_message("Saving notebook",500); }); this.events.on('notebook_saved.Notebook', function () { nnw.set_message("Notebook saved",2000); }); this.events.on('notebook_save_failed.Notebook', function (evt, error) { nnw.warning(error.message || "Notebook save failed"); }); this.events.on('notebook_copy_failed.Notebook', function (evt, error) { nnw.warning(error.message || "Notebook copy failed"); }); // Checkpoint events this.events.on('checkpoint_created.Notebook', function (evt, data) { var msg = "Checkpoint created"; if (data.last_modified) { var d = new Date(data.last_modified); msg = msg + ": " + moment(d).format("HH:mm:ss"); } nnw.set_message(msg, 2000); }); this.events.on('checkpoint_failed.Notebook', function () { nnw.warning("Checkpoint failed"); }); this.events.on('checkpoint_deleted.Notebook', function () { nnw.set_message("Checkpoint deleted", 500); }); this.events.on('checkpoint_delete_failed.Notebook', function () { nnw.warning("Checkpoint delete failed"); }); this.events.on('checkpoint_restoring.Notebook', function () { nnw.set_message("Restoring to checkpoint...", 500); }); this.events.on('checkpoint_restore_failed.Notebook', function () { nnw.warning("Checkpoint restore failed"); }); // Autosave events this.events.on('autosave_disabled.Notebook', function () { nnw.set_message("Autosave disabled", 2000); }); this.events.on('autosave_enabled.Notebook', function (evt, interval) { nnw.set_message("Saving every " + interval / 1000 + "s", 1000); }); }; // Backwards compatibility. IPython.NotificationArea = NotebookNotificationArea; return {'NotebookNotificationArea': NotebookNotificationArea}; });