Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
base fork: ipython/ipython
base: master
...
head fork: stefanv/ipython
Checking mergeability… Don’t worry, you can still create the pull request.
  • 1 commit
  • 8 files changed
  • 0 commit comments
  • 1 contributor
View
21 IPython/frontend/html/notebook/handlers.py
@@ -577,3 +577,24 @@ def post(self):
self.finish(html)
+#-----------------------------------------------------------------------------
+# Client ping back handler
+#-----------------------------------------------------------------------------
+
+class PingHandler(RequestHandler):
+ """IPython clients call this method to let us know that they are
+ viewing a worksheet.
+
+ """
+
+ def post(self, notebook_id):
+ nbm = self.application.notebook_manager
+
+ body = self.request.body.strip()
+ ip = self.request.remote_ip
+ host = self.request.host
+ user = self.get_argument('user', default='Anon')
+ viewers = nbm.update_viewers(notebook_id, ip=ip, host=host, user=user,
+ read_only=self.application.read_only)
+
+ self.finish(jsonapi.dumps({'viewers': viewers}))
View
6 IPython/frontend/html/notebook/notebookapp.py
@@ -48,7 +48,8 @@
from .handlers import (LoginHandler, LogoutHandler,
ProjectDashboardHandler, NewHandler, NamedNotebookHandler,
MainKernelHandler, KernelHandler, KernelActionHandler, IOPubHandler,
- ShellHandler, NotebookRootHandler, NotebookHandler, RSTHandler
+ ShellHandler, NotebookRootHandler, NotebookHandler, RSTHandler,
+ PingHandler
)
from .notebookmanager import NotebookManager
@@ -102,7 +103,8 @@ def __init__(self, ipython_app, kernel_manager, notebook_manager, log):
(r"/kernels/%s/shell" % _kernel_id_regex, ShellHandler),
(r"/notebooks", NotebookRootHandler),
(r"/notebooks/%s" % _notebook_id_regex, NotebookHandler),
- (r"/rstservice/render", RSTHandler)
+ (r"/rstservice/render", RSTHandler),
+ (r"/ping/%s" % _notebook_id_regex, PingHandler),
]
settings = dict(
template_path=os.path.join(os.path.dirname(__file__), "templates"),
View
38 IPython/frontend/html/notebook/notebookmanager.py
@@ -17,6 +17,7 @@
#-----------------------------------------------------------------------------
import datetime
+import time
import os
import uuid
import glob
@@ -46,6 +47,8 @@ class NotebookManager(LoggingConfigurable):
# Map notebook names to notebook_ids
rev_mapping = Dict()
+ viewers = Dict()
+
def list_notebooks(self):
"""List all notebooks in the notebook dir.
@@ -231,3 +234,38 @@ def new_notebook(self):
current.write(nb, f, u'json')
return notebook_id
+ def update_viewers(self, notebook_id, ip=None, host=None, user=None,
+ read_only=False):
+ """Update the list of current viewers/editors of a notebook.
+
+ """
+ if not notebook_id in self.mapping:
+ return []
+
+ if user is None:
+ user = 'Unknown'
+
+ if host is None:
+ host = ''
+ else:
+ host = host.split(':', 1)[0]
+
+ viewers_all = self.viewers
+ viewers_this = self.viewers.get(notebook_id, [])
+
+ viewer_info = {'user': user,
+ 'ip': ip,
+ 'host': host,
+ 'timestamp': time.strftime('%H:%M'),
+ 'read_only': read_only}
+
+ for n, info in enumerate(viewers_this):
+ if (user == info['user']) and (ip == info['ip']):
+ viewers_this[n] = viewer_info
+ break
+ else:
+ viewers_this.insert(0, viewer_info)
+
+ viewers_all[notebook_id] = viewers_this
+
+ return viewers_this
View
1  IPython/frontend/html/notebook/static/js/leftpanel.js
@@ -70,6 +70,7 @@ var IPython = (function (IPython) {
this.kernel_section = new IPython.KernelSection('div#kernel_section');
}
this.help_section = new IPython.HelpSection('div#help_section');
+ this.viewer_section = new IPython.ViewerSection('div#viewer_section');
}
LeftPanel.prototype.collapse = function () {
View
21 IPython/frontend/html/notebook/static/js/notebook.js
@@ -1000,6 +1000,27 @@ var IPython = (function (IPython) {
}, 50);
};
+
+ Notebook.prototype.ping = function() {
+ /* Let the server know that this client is still watching */
+
+ var notebook_id = IPython.save_widget.get_notebook_id();
+
+ var data = {
+ type : "POST",
+ success : function (data, status, hdr) {
+ if (status === "success") {
+ IPython.left_panel.viewer_section.update_viewers(data);
+ } else {
+ console.log("Could not update viewers (status ", status, ")");
+ }
+ }
+ };
+ var url = $('body').data('baseProjectUrl') + 'ping/' + notebook_id;
+ $.ajax(url, data);
+ };
+
+
IPython.Notebook = Notebook;
View
7 IPython/frontend/html/notebook/static/js/notebookmain.js
@@ -52,6 +52,7 @@ $(document).ready(function () {
$('button#new_notebook').addClass('hidden');
$('div#cell_section').addClass('hidden');
$('div#kernel_section').addClass('hidden');
+ $('div#viewer_Section').addClass('hidden');
$('span#login_widget').removeClass('hidden');
// left panel starts collapsed, but the collapse must happen after
// elements start drawing. Don't draw contents of the panel until
@@ -75,10 +76,12 @@ $(document).ready(function () {
// and finally unhide the panel contents after collapse
setTimeout(function(){
IPython.left_panel.left_panel_element.css('visibility', 'visible');
- }, 200)
+ }, 200);
}
},100);
+
+ setInterval(IPython.notebook.ping, 30 * 1000);
+
});
});
-
View
30 IPython/frontend/html/notebook/static/js/panelsection.js
@@ -275,6 +275,35 @@ var IPython = (function (IPython) {
};
+ // ViewerSection
+
+ var ViewerSection = function () {
+ PanelSection.apply(this, arguments);
+ };
+
+ ViewerSection.prototype = new PanelSection();
+
+
+ ViewerSection.prototype.style = function () {
+ PanelSection.prototype.style.apply(this);
+ };
+
+ ViewerSection.prototype.update_viewers = function (data) {
+ viewers = $.parseJSON(data).viewers;
+ new_list = $('<div id="viewer_list">');
+ ul = $('<ul>');
+
+ for (var i = 0; i < viewers.length; i += 1) {
+ info = viewers[i];
+ new_list.append(ul.text(info.user + ' on ' + info.ip +
+ ' (' + info.host + ')' +
+ ' seen ' + info.timestamp));
+ }
+
+ $('#viewer_list').replaceWith(new_list);
+ };
+
+
// Set module variables
IPython.PanelSection = PanelSection;
@@ -282,6 +311,7 @@ var IPython = (function (IPython) {
IPython.CellSection = CellSection;
IPython.KernelSection = KernelSection;
IPython.HelpSection = HelpSection;
+ IPython.ViewerSection = ViewerSection;
return IPython;
View
9 IPython/frontend/html/notebook/templates/notebook.html
@@ -251,6 +251,15 @@
</div>
</div>
+ <div id="viewer_section">
+ <div class="section_header">
+ <h3>Participants</h3>
+ </div>
+ <div class="section_content">
+ <div id="viewer_list"></div>
+ </div>
+ </div>
+
</div>
<div id="left_panel_splitter"></div>
<div id="notebook_panel">

No commit comments for this range

Something went wrong with that request. Please try again.