Show More
@@ -0,0 +1,38 | |||||
|
1 | //---------------------------------------------------------------------------- | |||
|
2 | // Copyright (C) 2008-2011 The IPython Development Team | |||
|
3 | // | |||
|
4 | // Distributed under the terms of the BSD License. The full license is in | |||
|
5 | // the file COPYING, distributed as part of this software. | |||
|
6 | //---------------------------------------------------------------------------- | |||
|
7 | ||||
|
8 | //============================================================================ | |||
|
9 | // Login button | |||
|
10 | //============================================================================ | |||
|
11 | ||||
|
12 | var IPython = (function (IPython) { | |||
|
13 | ||||
|
14 | var LoginWidget = function (selector) { | |||
|
15 | this.selector = selector; | |||
|
16 | if (this.selector !== undefined) { | |||
|
17 | this.element = $(selector); | |||
|
18 | this.style(); | |||
|
19 | this.bind_events(); | |||
|
20 | } | |||
|
21 | }; | |||
|
22 | ||||
|
23 | LoginWidget.prototype.style = function () { | |||
|
24 | this.element.find('button#login').button(); | |||
|
25 | }; | |||
|
26 | LoginWidget.prototype.bind_events = function () { | |||
|
27 | var that = this; | |||
|
28 | this.element.find("button#login").click(function () { | |||
|
29 | window.location = "/login?next="+location.pathname; | |||
|
30 | }); | |||
|
31 | }; | |||
|
32 | ||||
|
33 | // Set module variables | |||
|
34 | IPython.LoginWidget = LoginWidget; | |||
|
35 | ||||
|
36 | return IPython; | |||
|
37 | ||||
|
38 | }(IPython)); |
@@ -26,6 +26,7 from tornado import websocket | |||||
26 | from zmq.eventloop import ioloop |
|
26 | from zmq.eventloop import ioloop | |
27 | from zmq.utils import jsonapi |
|
27 | from zmq.utils import jsonapi | |
28 |
|
28 | |||
|
29 | from IPython.external.decorator import decorator | |||
29 | from IPython.zmq.session import Session |
|
30 | from IPython.zmq.session import Session | |
30 |
|
31 | |||
31 | try: |
|
32 | try: | |
@@ -34,6 +35,32 except ImportError: | |||||
34 | publish_string = None |
|
35 | publish_string = None | |
35 |
|
36 | |||
36 |
|
37 | |||
|
38 | #----------------------------------------------------------------------------- | |||
|
39 | # Decorator for disabling read-only handlers | |||
|
40 | #----------------------------------------------------------------------------- | |||
|
41 | ||||
|
42 | @decorator | |||
|
43 | def not_if_readonly(f, self, *args, **kwargs): | |||
|
44 | if self.application.read_only: | |||
|
45 | raise web.HTTPError(403, "Notebook server is read-only") | |||
|
46 | else: | |||
|
47 | return f(self, *args, **kwargs) | |||
|
48 | ||||
|
49 | @decorator | |||
|
50 | def authenticate_unless_readonly(f, self, *args, **kwargs): | |||
|
51 | """authenticate this page *unless* readonly view is active. | |||
|
52 | ||||
|
53 | In read-only mode, the notebook list and print view should | |||
|
54 | be accessible without authentication. | |||
|
55 | """ | |||
|
56 | ||||
|
57 | @web.authenticated | |||
|
58 | def auth_f(self, *args, **kwargs): | |||
|
59 | return f(self, *args, **kwargs) | |||
|
60 | if self.application.read_only: | |||
|
61 | return f(self, *args, **kwargs) | |||
|
62 | else: | |||
|
63 | return auth_f(self, *args, **kwargs) | |||
37 |
|
64 | |||
38 | #----------------------------------------------------------------------------- |
|
65 | #----------------------------------------------------------------------------- | |
39 | # Top-level handlers |
|
66 | # Top-level handlers | |
@@ -50,34 +77,48 class AuthenticatedHandler(web.RequestHandler): | |||||
50 | if user_id is None: |
|
77 | if user_id is None: | |
51 | # prevent extra Invalid cookie sig warnings: |
|
78 | # prevent extra Invalid cookie sig warnings: | |
52 | self.clear_cookie('username') |
|
79 | self.clear_cookie('username') | |
53 | if not self.application.password: |
|
80 | if not self.application.password and not self.application.read_only: | |
54 | user_id = 'anonymous' |
|
81 | user_id = 'anonymous' | |
55 | return user_id |
|
82 | return user_id | |
|
83 | ||||
|
84 | @property | |||
|
85 | def read_only(self): | |||
|
86 | if self.application.read_only: | |||
|
87 | if self.application.password: | |||
|
88 | return self.get_current_user() is None | |||
|
89 | else: | |||
|
90 | return True | |||
|
91 | else: | |||
|
92 | return False | |||
|
93 | ||||
56 |
|
94 | |||
57 |
|
95 | |||
58 | class ProjectDashboardHandler(AuthenticatedHandler): |
|
96 | class ProjectDashboardHandler(AuthenticatedHandler): | |
59 |
|
97 | |||
60 |
@ |
|
98 | @authenticate_unless_readonly | |
61 | def get(self): |
|
99 | def get(self): | |
62 | nbm = self.application.notebook_manager |
|
100 | nbm = self.application.notebook_manager | |
63 | project = nbm.notebook_dir |
|
101 | project = nbm.notebook_dir | |
64 | self.render( |
|
102 | self.render( | |
65 | 'projectdashboard.html', project=project, |
|
103 | 'projectdashboard.html', project=project, | |
66 | base_project_url=u'/', base_kernel_url=u'/' |
|
104 | base_project_url=u'/', base_kernel_url=u'/', | |
|
105 | read_only=self.read_only, | |||
67 | ) |
|
106 | ) | |
68 |
|
107 | |||
69 |
|
108 | |||
70 | class LoginHandler(AuthenticatedHandler): |
|
109 | class LoginHandler(AuthenticatedHandler): | |
71 |
|
110 | |||
72 | def get(self): |
|
111 | def get(self): | |
73 |
self.render('login.html', |
|
112 | self.render('login.html', | |
|
113 | next=self.get_argument('next', default='/'), | |||
|
114 | read_only=self.read_only, | |||
|
115 | ) | |||
74 |
|
116 | |||
75 | def post(self): |
|
117 | def post(self): | |
76 | pwd = self.get_argument('password', default=u'') |
|
118 | pwd = self.get_argument('password', default=u'') | |
77 | if self.application.password and pwd == self.application.password: |
|
119 | if self.application.password and pwd == self.application.password: | |
78 | self.set_secure_cookie('username', str(uuid.uuid4())) |
|
120 | self.set_secure_cookie('username', str(uuid.uuid4())) | |
79 |
|
|
121 | self.redirect(self.get_argument('next', default='/')) | |
80 | self.redirect(url) |
|
|||
81 |
|
122 | |||
82 |
|
123 | |||
83 | class NewHandler(AuthenticatedHandler): |
|
124 | class NewHandler(AuthenticatedHandler): | |
@@ -91,23 +132,26 class NewHandler(AuthenticatedHandler): | |||||
91 | 'notebook.html', project=project, |
|
132 | 'notebook.html', project=project, | |
92 | notebook_id=notebook_id, |
|
133 | notebook_id=notebook_id, | |
93 | base_project_url=u'/', base_kernel_url=u'/', |
|
134 | base_project_url=u'/', base_kernel_url=u'/', | |
94 | kill_kernel=False |
|
135 | kill_kernel=False, | |
|
136 | read_only=False, | |||
95 | ) |
|
137 | ) | |
96 |
|
138 | |||
97 |
|
139 | |||
98 | class NamedNotebookHandler(AuthenticatedHandler): |
|
140 | class NamedNotebookHandler(AuthenticatedHandler): | |
99 |
|
141 | |||
100 |
@ |
|
142 | @authenticate_unless_readonly | |
101 | def get(self, notebook_id): |
|
143 | def get(self, notebook_id): | |
102 | nbm = self.application.notebook_manager |
|
144 | nbm = self.application.notebook_manager | |
103 | project = nbm.notebook_dir |
|
145 | project = nbm.notebook_dir | |
104 | if not nbm.notebook_exists(notebook_id): |
|
146 | if not nbm.notebook_exists(notebook_id): | |
105 | raise web.HTTPError(404, u'Notebook does not exist: %s' % notebook_id) |
|
147 | raise web.HTTPError(404, u'Notebook does not exist: %s' % notebook_id) | |
|
148 | ||||
106 | self.render( |
|
149 | self.render( | |
107 | 'notebook.html', project=project, |
|
150 | 'notebook.html', project=project, | |
108 | notebook_id=notebook_id, |
|
151 | notebook_id=notebook_id, | |
109 | base_project_url=u'/', base_kernel_url=u'/', |
|
152 | base_project_url=u'/', base_kernel_url=u'/', | |
110 | kill_kernel=False |
|
153 | kill_kernel=False, | |
|
154 | read_only=self.read_only, | |||
111 | ) |
|
155 | ) | |
112 |
|
156 | |||
113 |
|
157 | |||
@@ -363,8 +407,9 class ShellHandler(AuthenticatedZMQStreamHandler): | |||||
363 |
|
407 | |||
364 | class NotebookRootHandler(AuthenticatedHandler): |
|
408 | class NotebookRootHandler(AuthenticatedHandler): | |
365 |
|
409 | |||
366 |
@ |
|
410 | @authenticate_unless_readonly | |
367 | def get(self): |
|
411 | def get(self): | |
|
412 | ||||
368 | nbm = self.application.notebook_manager |
|
413 | nbm = self.application.notebook_manager | |
369 | files = nbm.list_notebooks() |
|
414 | files = nbm.list_notebooks() | |
370 | self.finish(jsonapi.dumps(files)) |
|
415 | self.finish(jsonapi.dumps(files)) | |
@@ -387,11 +432,12 class NotebookHandler(AuthenticatedHandler): | |||||
387 |
|
432 | |||
388 | SUPPORTED_METHODS = ('GET', 'PUT', 'DELETE') |
|
433 | SUPPORTED_METHODS = ('GET', 'PUT', 'DELETE') | |
389 |
|
434 | |||
390 |
@ |
|
435 | @authenticate_unless_readonly | |
391 | def get(self, notebook_id): |
|
436 | def get(self, notebook_id): | |
392 | nbm = self.application.notebook_manager |
|
437 | nbm = self.application.notebook_manager | |
393 | format = self.get_argument('format', default='json') |
|
438 | format = self.get_argument('format', default='json') | |
394 | last_mod, name, data = nbm.get_notebook(notebook_id, format) |
|
439 | last_mod, name, data = nbm.get_notebook(notebook_id, format) | |
|
440 | ||||
395 | if format == u'json': |
|
441 | if format == u'json': | |
396 | self.set_header('Content-Type', 'application/json') |
|
442 | self.set_header('Content-Type', 'application/json') | |
397 | self.set_header('Content-Disposition','attachment; filename="%s.ipynb"' % name) |
|
443 | self.set_header('Content-Disposition','attachment; filename="%s.ipynb"' % name) |
@@ -110,6 +110,7 class NotebookWebApplication(web.Application): | |||||
110 | self.log = log |
|
110 | self.log = log | |
111 | self.notebook_manager = notebook_manager |
|
111 | self.notebook_manager = notebook_manager | |
112 | self.ipython_app = ipython_app |
|
112 | self.ipython_app = ipython_app | |
|
113 | self.read_only = self.ipython_app.read_only | |||
113 |
|
114 | |||
114 |
|
115 | |||
115 | #----------------------------------------------------------------------------- |
|
116 | #----------------------------------------------------------------------------- | |
@@ -121,11 +122,23 flags['no-browser']=( | |||||
121 | {'NotebookApp' : {'open_browser' : False}}, |
|
122 | {'NotebookApp' : {'open_browser' : False}}, | |
122 | "Don't open the notebook in a browser after startup." |
|
123 | "Don't open the notebook in a browser after startup." | |
123 | ) |
|
124 | ) | |
|
125 | flags['read-only'] = ( | |||
|
126 | {'NotebookApp' : {'read_only' : True}}, | |||
|
127 | """Allow read-only access to notebooks. | |||
|
128 | ||||
|
129 | When using a password to protect the notebook server, this flag | |||
|
130 | allows unauthenticated clients to view the notebook list, and | |||
|
131 | individual notebooks, but not edit them, start kernels, or run | |||
|
132 | code. | |||
|
133 | ||||
|
134 | If no password is set, the server will be entirely read-only. | |||
|
135 | """ | |||
|
136 | ) | |||
124 |
|
137 | |||
125 | # the flags that are specific to the frontend |
|
138 | # the flags that are specific to the frontend | |
126 | # these must be scrubbed before being passed to the kernel, |
|
139 | # these must be scrubbed before being passed to the kernel, | |
127 | # or it will raise an error on unrecognized flags |
|
140 | # or it will raise an error on unrecognized flags | |
128 | notebook_flags = ['no-browser'] |
|
141 | notebook_flags = ['no-browser', 'read-only'] | |
129 |
|
142 | |||
130 | aliases = dict(ipkernel_aliases) |
|
143 | aliases = dict(ipkernel_aliases) | |
131 |
|
144 | |||
@@ -208,6 +221,10 class NotebookApp(BaseIPythonApplication): | |||||
208 |
|
221 | |||
209 | open_browser = Bool(True, config=True, |
|
222 | open_browser = Bool(True, config=True, | |
210 | help="Whether to open in a browser after starting.") |
|
223 | help="Whether to open in a browser after starting.") | |
|
224 | ||||
|
225 | read_only = Bool(False, config=True, | |||
|
226 | help="Whether to prevent editing/execution of notebooks." | |||
|
227 | ) | |||
211 |
|
228 | |||
212 | def get_ws_url(self): |
|
229 | def get_ws_url(self): | |
213 | """Return the WebSocket URL for this server.""" |
|
230 | """Return the WebSocket URL for this server.""" | |
@@ -288,7 +305,7 class NotebookApp(BaseIPythonApplication): | |||||
288 | # Try random ports centered around the default. |
|
305 | # Try random ports centered around the default. | |
289 | from random import randint |
|
306 | from random import randint | |
290 | n = 50 # Max number of attempts, keep reasonably large. |
|
307 | n = 50 # Max number of attempts, keep reasonably large. | |
291 |
for port in |
|
308 | for port in range(self.port, self.port+5) + [self.port + randint(-2*n, 2*n) for i in range(n-5)]: | |
292 | try: |
|
309 | try: | |
293 | self.http_server.listen(port, self.ip) |
|
310 | self.http_server.listen(port, self.ip) | |
294 | except socket.error, e: |
|
311 | except socket.error, e: |
@@ -51,3 +51,12 div#main_app { | |||||
51 | padding: 0.2em 0.8em; |
|
51 | padding: 0.2em 0.8em; | |
52 | font-size: 77%; |
|
52 | font-size: 77%; | |
53 | } |
|
53 | } | |
|
54 | ||||
|
55 | span#login_widget { | |||
|
56 | float: right; | |||
|
57 | } | |||
|
58 | ||||
|
59 | /* generic class for hidden objects */ | |||
|
60 | .hidden { | |||
|
61 | display: none; | |||
|
62 | } No newline at end of file |
@@ -15,6 +15,10 var IPython = (function (IPython) { | |||||
15 |
|
15 | |||
16 | var Cell = function (notebook) { |
|
16 | var Cell = function (notebook) { | |
17 | this.notebook = notebook; |
|
17 | this.notebook = notebook; | |
|
18 | this.read_only = false; | |||
|
19 | if (notebook){ | |||
|
20 | this.read_only = notebook.read_only; | |||
|
21 | } | |||
18 | this.selected = false; |
|
22 | this.selected = false; | |
19 | this.element = null; |
|
23 | this.element = null; | |
20 | this.create_element(); |
|
24 | this.create_element(); |
@@ -37,6 +37,7 var IPython = (function (IPython) { | |||||
37 | indentUnit : 4, |
|
37 | indentUnit : 4, | |
38 | mode: 'python', |
|
38 | mode: 'python', | |
39 | theme: 'ipython', |
|
39 | theme: 'ipython', | |
|
40 | readOnly: this.read_only, | |||
40 | onKeyEvent: $.proxy(this.handle_codemirror_keyevent,this) |
|
41 | onKeyEvent: $.proxy(this.handle_codemirror_keyevent,this) | |
41 | }); |
|
42 | }); | |
42 | input.append(input_area); |
|
43 | input.append(input_area); |
@@ -65,8 +65,10 var IPython = (function (IPython) { | |||||
65 |
|
65 | |||
66 | LeftPanel.prototype.create_children = function () { |
|
66 | LeftPanel.prototype.create_children = function () { | |
67 | this.notebook_section = new IPython.NotebookSection('div#notebook_section'); |
|
67 | this.notebook_section = new IPython.NotebookSection('div#notebook_section'); | |
68 | this.cell_section = new IPython.CellSection('div#cell_section'); |
|
68 | if (! IPython.read_only){ | |
69 |
this. |
|
69 | this.cell_section = new IPython.CellSection('div#cell_section'); | |
|
70 | this.kernel_section = new IPython.KernelSection('div#kernel_section'); | |||
|
71 | } | |||
70 | this.help_section = new IPython.HelpSection('div#help_section'); |
|
72 | this.help_section = new IPython.HelpSection('div#help_section'); | |
71 | } |
|
73 | } | |
72 |
|
74 |
@@ -14,6 +14,7 var IPython = (function (IPython) { | |||||
14 | var utils = IPython.utils; |
|
14 | var utils = IPython.utils; | |
15 |
|
15 | |||
16 | var Notebook = function (selector) { |
|
16 | var Notebook = function (selector) { | |
|
17 | this.read_only = IPython.read_only; | |||
17 | this.element = $(selector); |
|
18 | this.element = $(selector); | |
18 | this.element.scroll(); |
|
19 | this.element.scroll(); | |
19 | this.element.data("notebook", this); |
|
20 | this.element.data("notebook", this); | |
@@ -42,6 +43,7 var IPython = (function (IPython) { | |||||
42 | var that = this; |
|
43 | var that = this; | |
43 | var end_space = $('<div class="end_space"></div>').height(150); |
|
44 | var end_space = $('<div class="end_space"></div>').height(150); | |
44 | end_space.dblclick(function (e) { |
|
45 | end_space.dblclick(function (e) { | |
|
46 | if (that.read_only) return; | |||
45 | var ncells = that.ncells(); |
|
47 | var ncells = that.ncells(); | |
46 | that.insert_code_cell_below(ncells-1); |
|
48 | that.insert_code_cell_below(ncells-1); | |
47 | }); |
|
49 | }); | |
@@ -54,6 +56,7 var IPython = (function (IPython) { | |||||
54 | var that = this; |
|
56 | var that = this; | |
55 | $(document).keydown(function (event) { |
|
57 | $(document).keydown(function (event) { | |
56 | // console.log(event); |
|
58 | // console.log(event); | |
|
59 | if (that.read_only) return; | |||
57 | if (event.which === 38) { |
|
60 | if (event.which === 38) { | |
58 | var cell = that.selected_cell(); |
|
61 | var cell = that.selected_cell(); | |
59 | if (cell.at_top()) { |
|
62 | if (cell.at_top()) { | |
@@ -185,11 +188,11 var IPython = (function (IPython) { | |||||
185 | }); |
|
188 | }); | |
186 |
|
189 | |||
187 | $(window).bind('beforeunload', function () { |
|
190 | $(window).bind('beforeunload', function () { | |
188 |
var kill_kernel = $('#kill_kernel').prop('checked'); |
|
191 | var kill_kernel = $('#kill_kernel').prop('checked'); | |
189 | if (kill_kernel) { |
|
192 | if (kill_kernel) { | |
190 | that.kernel.kill(); |
|
193 | that.kernel.kill(); | |
191 | } |
|
194 | } | |
192 | if (that.dirty) { |
|
195 | if (that.dirty && ! that.read_only) { | |
193 | return "You have unsaved changes that will be lost if you leave this page."; |
|
196 | return "You have unsaved changes that will be lost if you leave this page."; | |
194 | }; |
|
197 | }; | |
195 | }); |
|
198 | }); | |
@@ -975,14 +978,17 var IPython = (function (IPython) { | |||||
975 |
|
978 | |||
976 |
|
979 | |||
977 | Notebook.prototype.notebook_loaded = function (data, status, xhr) { |
|
980 | Notebook.prototype.notebook_loaded = function (data, status, xhr) { | |
|
981 | var allowed = xhr.getResponseHeader('Allow'); | |||
978 | this.fromJSON(data); |
|
982 | this.fromJSON(data); | |
979 | if (this.ncells() === 0) { |
|
983 | if (this.ncells() === 0) { | |
980 | this.insert_code_cell_below(); |
|
984 | this.insert_code_cell_below(); | |
981 | }; |
|
985 | }; | |
982 | IPython.save_widget.status_save(); |
|
986 | IPython.save_widget.status_save(); | |
983 | IPython.save_widget.set_notebook_name(data.metadata.name); |
|
987 | IPython.save_widget.set_notebook_name(data.metadata.name); | |
984 | this.start_kernel(); |
|
|||
985 | this.dirty = false; |
|
988 | this.dirty = false; | |
|
989 | if (! this.read_only) { | |||
|
990 | this.start_kernel(); | |||
|
991 | } | |||
986 | // fromJSON always selects the last cell inserted. We need to wait |
|
992 | // fromJSON always selects the last cell inserted. We need to wait | |
987 | // until that is done before scrolling to the top. |
|
993 | // until that is done before scrolling to the top. | |
988 | setTimeout(function () { |
|
994 | setTimeout(function () { | |
@@ -991,7 +997,6 var IPython = (function (IPython) { | |||||
991 | }, 50); |
|
997 | }, 50); | |
992 | }; |
|
998 | }; | |
993 |
|
999 | |||
994 |
|
||||
995 | IPython.Notebook = Notebook; |
|
1000 | IPython.Notebook = Notebook; | |
996 |
|
1001 | |||
997 |
|
1002 |
@@ -80,7 +80,10 var IPython = (function (IPython) { | |||||
80 | var nbname = data[i].name; |
|
80 | var nbname = data[i].name; | |
81 | var item = this.new_notebook_item(i); |
|
81 | var item = this.new_notebook_item(i); | |
82 | this.add_link(notebook_id, nbname, item); |
|
82 | this.add_link(notebook_id, nbname, item); | |
83 | this.add_delete_button(item); |
|
83 | if (!IPython.read_only){ | |
|
84 | // hide delete buttons when readonly | |||
|
85 | this.add_delete_button(item); | |||
|
86 | } | |||
84 | }; |
|
87 | }; | |
85 | }; |
|
88 | }; | |
86 |
|
89 |
@@ -23,6 +23,7 $(document).ready(function () { | |||||
23 | } |
|
23 | } | |
24 | }); |
|
24 | }); | |
25 | IPython.markdown_converter = new Markdown.Converter(); |
|
25 | IPython.markdown_converter = new Markdown.Converter(); | |
|
26 | IPython.read_only = $('meta[name=read_only]').attr("content") == 'True'; | |||
26 |
|
27 | |||
27 | $('div#header').addClass('border-box-sizing'); |
|
28 | $('div#header').addClass('border-box-sizing'); | |
28 | $('div#main_app').addClass('border-box-sizing ui-widget ui-widget-content'); |
|
29 | $('div#main_app').addClass('border-box-sizing ui-widget ui-widget-content'); | |
@@ -33,6 +34,7 $(document).ready(function () { | |||||
33 | IPython.left_panel = new IPython.LeftPanel('div#left_panel', 'div#left_panel_splitter'); |
|
34 | IPython.left_panel = new IPython.LeftPanel('div#left_panel', 'div#left_panel_splitter'); | |
34 | IPython.save_widget = new IPython.SaveWidget('span#save_widget'); |
|
35 | IPython.save_widget = new IPython.SaveWidget('span#save_widget'); | |
35 | IPython.quick_help = new IPython.QuickHelp('span#quick_help_area'); |
|
36 | IPython.quick_help = new IPython.QuickHelp('span#quick_help_area'); | |
|
37 | IPython.login_widget = new IPython.LoginWidget('span#login_widget'); | |||
36 | IPython.print_widget = new IPython.PrintWidget('span#print_widget'); |
|
38 | IPython.print_widget = new IPython.PrintWidget('span#print_widget'); | |
37 | IPython.notebook = new IPython.Notebook('div#notebook'); |
|
39 | IPython.notebook = new IPython.Notebook('div#notebook'); | |
38 | IPython.kernel_status_widget = new IPython.KernelStatusWidget('#kernel_status'); |
|
40 | IPython.kernel_status_widget = new IPython.KernelStatusWidget('#kernel_status'); | |
@@ -42,6 +44,21 $(document).ready(function () { | |||||
42 |
|
44 | |||
43 | // These have display: none in the css file and are made visible here to prevent FLOUC. |
|
45 | // These have display: none in the css file and are made visible here to prevent FLOUC. | |
44 | $('div#header').css('display','block'); |
|
46 | $('div#header').css('display','block'); | |
|
47 | ||||
|
48 | if(IPython.read_only){ | |||
|
49 | // hide various elements from read-only view | |||
|
50 | IPython.save_widget.element.find('button#save_notebook').addClass('hidden'); | |||
|
51 | IPython.quick_help.element.addClass('hidden'); // shortcuts are disabled in read_only | |||
|
52 | $('button#new_notebook').addClass('hidden'); | |||
|
53 | $('div#cell_section').addClass('hidden'); | |||
|
54 | $('div#kernel_section').addClass('hidden'); | |||
|
55 | $('span#login_widget').removeClass('hidden'); | |||
|
56 | // left panel starts collapsed, but the collapse must happen after | |||
|
57 | // elements start drawing. Don't draw contents of the panel until | |||
|
58 | // after they are collapsed | |||
|
59 | IPython.left_panel.left_panel_element.css('visibility', 'hidden'); | |||
|
60 | } | |||
|
61 | ||||
45 | $('div#main_app').css('display','block'); |
|
62 | $('div#main_app').css('display','block'); | |
46 |
|
63 | |||
47 | // Perform these actions after the notebook has been loaded. |
|
64 | // Perform these actions after the notebook has been loaded. | |
@@ -52,6 +69,14 $(document).ready(function () { | |||||
52 | IPython.save_widget.update_url(); |
|
69 | IPython.save_widget.update_url(); | |
53 | IPython.layout_manager.do_resize(); |
|
70 | IPython.layout_manager.do_resize(); | |
54 | IPython.pager.collapse(); |
|
71 | IPython.pager.collapse(); | |
|
72 | if(IPython.read_only){ | |||
|
73 | // collapse the left panel on read-only | |||
|
74 | IPython.left_panel.collapse(); | |||
|
75 | // and finally unhide the panel contents after collapse | |||
|
76 | setTimeout(function(){ | |||
|
77 | IPython.left_panel.left_panel_element.css('visibility', 'visible'); | |||
|
78 | }, 200) | |||
|
79 | } | |||
55 | },100); |
|
80 | },100); | |
56 | }); |
|
81 | }); | |
57 |
|
82 |
@@ -27,7 +27,16 $(document).ready(function () { | |||||
27 | $('div#left_panel').addClass('box-flex'); |
|
27 | $('div#left_panel').addClass('box-flex'); | |
28 | $('div#right_panel').addClass('box-flex'); |
|
28 | $('div#right_panel').addClass('box-flex'); | |
29 |
|
29 | |||
|
30 | IPython.read_only = $('meta[name=read_only]').attr("content") == 'True'; | |||
|
31 | ||||
30 | IPython.notebook_list = new IPython.NotebookList('div#notebook_list'); |
|
32 | IPython.notebook_list = new IPython.NotebookList('div#notebook_list'); | |
|
33 | IPython.login_widget = new IPython.LoginWidget('span#login_widget'); | |||
|
34 | ||||
|
35 | if (IPython.read_only){ | |||
|
36 | $('#new_notebook').addClass('hidden'); | |||
|
37 | // unhide login button if it's relevant | |||
|
38 | $('span#login_widget').removeClass('hidden'); | |||
|
39 | } | |||
31 | IPython.notebook_list.load_list(); |
|
40 | IPython.notebook_list.load_list(); | |
32 |
|
41 | |||
33 | // These have display: none in the css file and are made visible here to prevent FLOUC. |
|
42 | // These have display: none in the css file and are made visible here to prevent FLOUC. |
@@ -33,7 +33,8 var IPython = (function (IPython) { | |||||
33 | indentUnit : 4, |
|
33 | indentUnit : 4, | |
34 | mode: this.code_mirror_mode, |
|
34 | mode: this.code_mirror_mode, | |
35 | theme: 'default', |
|
35 | theme: 'default', | |
36 | value: this.placeholder |
|
36 | value: this.placeholder, | |
|
37 | readOnly: this.read_only, | |||
37 | }); |
|
38 | }); | |
38 | // The tabindex=-1 makes this div focusable. |
|
39 | // The tabindex=-1 makes this div focusable. | |
39 | var render_area = $('<div/>').addClass('text_cell_render'). |
|
40 | var render_area = $('<div/>').addClass('text_cell_render'). | |
@@ -65,6 +66,7 var IPython = (function (IPython) { | |||||
65 |
|
66 | |||
66 |
|
67 | |||
67 | TextCell.prototype.edit = function () { |
|
68 | TextCell.prototype.edit = function () { | |
|
69 | if ( this.read_only ) return; | |||
68 | if (this.rendered === true) { |
|
70 | if (this.rendered === true) { | |
69 | var text_cell = this.element; |
|
71 | var text_cell = this.element; | |
70 | var output = text_cell.find("div.text_cell_render"); |
|
72 | var output = text_cell.find("div.text_cell_render"); |
@@ -11,6 +11,8 | |||||
11 | <link rel="stylesheet" href="static/css/layout.css" type="text/css" /> |
|
11 | <link rel="stylesheet" href="static/css/layout.css" type="text/css" /> | |
12 | <link rel="stylesheet" href="static/css/base.css" type="text/css" /> |
|
12 | <link rel="stylesheet" href="static/css/base.css" type="text/css" /> | |
13 |
|
13 | |||
|
14 | <meta name="read_only" content="{{read_only}}"/> | |||
|
15 | ||||
14 | </head> |
|
16 | </head> | |
15 |
|
17 | |||
16 | <body> |
|
18 | <body> |
@@ -40,7 +40,8 | |||||
40 | <link rel="stylesheet" href="static/css/base.css" type="text/css" /> |
|
40 | <link rel="stylesheet" href="static/css/base.css" type="text/css" /> | |
41 | <link rel="stylesheet" href="static/css/notebook.css" type="text/css" /> |
|
41 | <link rel="stylesheet" href="static/css/notebook.css" type="text/css" /> | |
42 | <link rel="stylesheet" href="static/css/renderedhtml.css" type="text/css" /> |
|
42 | <link rel="stylesheet" href="static/css/renderedhtml.css" type="text/css" /> | |
43 |
|
43 | |||
|
44 | <meta name="read_only" content="{{read_only}}"/> | |||
44 |
|
45 | |||
45 | </head> |
|
46 | </head> | |
46 |
|
47 | |||
@@ -57,7 +58,10 | |||||
57 | </span> |
|
58 | </span> | |
58 | <span id="quick_help_area"> |
|
59 | <span id="quick_help_area"> | |
59 | <button id="quick_help">Quick<u>H</u>elp</button> |
|
60 | <button id="quick_help">Quick<u>H</u>elp</button> | |
60 |
|
|
61 | </span> | |
|
62 | <span id="login_widget" class="hidden"> | |||
|
63 | <button id="login">Login</button> | |||
|
64 | </span> | |||
61 | <span id="kernel_status">Idle</span> |
|
65 | <span id="kernel_status">Idle</span> | |
62 | </div> |
|
66 | </div> | |
63 |
|
67 | |||
@@ -278,6 +282,7 | |||||
278 | <script src="static/js/layout.js" type="text/javascript" charset="utf-8"></script> |
|
282 | <script src="static/js/layout.js" type="text/javascript" charset="utf-8"></script> | |
279 | <script src="static/js/savewidget.js" type="text/javascript" charset="utf-8"></script> |
|
283 | <script src="static/js/savewidget.js" type="text/javascript" charset="utf-8"></script> | |
280 | <script src="static/js/quickhelp.js" type="text/javascript" charset="utf-8"></script> |
|
284 | <script src="static/js/quickhelp.js" type="text/javascript" charset="utf-8"></script> | |
|
285 | <script src="static/js/loginwidget.js" type="text/javascript" charset="utf-8"></script> | |||
281 | <script src="static/js/pager.js" type="text/javascript" charset="utf-8"></script> |
|
286 | <script src="static/js/pager.js" type="text/javascript" charset="utf-8"></script> | |
282 | <script src="static/js/panelsection.js" type="text/javascript" charset="utf-8"></script> |
|
287 | <script src="static/js/panelsection.js" type="text/javascript" charset="utf-8"></script> | |
283 | <script src="static/js/printwidget.js" type="text/javascript" charset="utf-8"></script> |
|
288 | <script src="static/js/printwidget.js" type="text/javascript" charset="utf-8"></script> |
@@ -12,6 +12,8 | |||||
12 | <link rel="stylesheet" href="static/css/base.css" type="text/css" /> |
|
12 | <link rel="stylesheet" href="static/css/base.css" type="text/css" /> | |
13 | <link rel="stylesheet" href="static/css/projectdashboard.css" type="text/css" /> |
|
13 | <link rel="stylesheet" href="static/css/projectdashboard.css" type="text/css" /> | |
14 |
|
14 | |||
|
15 | <meta name="read_only" content="{{read_only}}"/> | |||
|
16 | ||||
15 | </head> |
|
17 | </head> | |
16 |
|
18 | |||
17 | <body data-project={{project}} data-base-project-url={{base_project_url}} |
|
19 | <body data-project={{project}} data-base-project-url={{base_project_url}} | |
@@ -19,6 +21,9 | |||||
19 |
|
21 | |||
20 | <div id="header"> |
|
22 | <div id="header"> | |
21 | <span id="ipython_notebook"><h1>IPython Notebook</h1></span> |
|
23 | <span id="ipython_notebook"><h1>IPython Notebook</h1></span> | |
|
24 | <span id="login_widget" class="hidden"> | |||
|
25 | <button id="login">Login</button> | |||
|
26 | </span> | |||
22 | </div> |
|
27 | </div> | |
23 |
|
28 | |||
24 | <div id="header_border"></div> |
|
29 | <div id="header_border"></div> | |
@@ -54,6 +59,7 | |||||
54 | <script src="static/jquery/js/jquery-ui-1.8.14.custom.min.js" type="text/javascript" charset="utf-8"></script> |
|
59 | <script src="static/jquery/js/jquery-ui-1.8.14.custom.min.js" type="text/javascript" charset="utf-8"></script> | |
55 | <script src="static/js/namespace.js" type="text/javascript" charset="utf-8"></script> |
|
60 | <script src="static/js/namespace.js" type="text/javascript" charset="utf-8"></script> | |
56 | <script src="static/js/notebooklist.js" type="text/javascript" charset="utf-8"></script> |
|
61 | <script src="static/js/notebooklist.js" type="text/javascript" charset="utf-8"></script> | |
|
62 | <script src="static/js/loginwidget.js" type="text/javascript" charset="utf-8"></script> | |||
57 | <script src="static/js/projectdashboardmain.js" type="text/javascript" charset="utf-8"></script> |
|
63 | <script src="static/js/projectdashboardmain.js" type="text/javascript" charset="utf-8"></script> | |
58 |
|
64 | |||
59 | </body> |
|
65 | </body> |
General Comments 0
You need to be logged in to leave comments.
Login now