##// END OF EJS Templates
remove trailing whitespace
Matthias BUSSONNIER -
Show More
@@ -1,654 +1,654 b''
1 1 # coding: utf-8
2 2 """A tornado based IPython notebook server.
3 3
4 4 Authors:
5 5
6 6 * Brian Granger
7 7 """
8 8 #-----------------------------------------------------------------------------
9 9 # Copyright (C) 2008-2011 The IPython Development Team
10 10 #
11 11 # Distributed under the terms of the BSD License. The full license is in
12 12 # the file COPYING, distributed as part of this software.
13 13 #-----------------------------------------------------------------------------
14 14
15 15 #-----------------------------------------------------------------------------
16 16 # Imports
17 17 #-----------------------------------------------------------------------------
18 18
19 19 # stdlib
20 20 import errno
21 21 import logging
22 22 import os
23 23 import random
24 24 import re
25 25 import select
26 26 import signal
27 27 import socket
28 28 import sys
29 29 import threading
30 30 import time
31 31 import uuid
32 32 import webbrowser
33 33
34 34 # Third party
35 35 import zmq
36 36 from jinja2 import Environment, FileSystemLoader
37 37
38 38 # Install the pyzmq ioloop. This has to be done before anything else from
39 39 # tornado is imported.
40 40 from zmq.eventloop import ioloop
41 41 ioloop.install()
42 42
43 43 from tornado import httpserver
44 44 from tornado import web
45 45
46 46 # Our own libraries
47 47 from .kernelmanager import MappingKernelManager
48 48 from .handlers import (LoginHandler, LogoutHandler,
49 49 ProjectDashboardHandler, NewHandler, NamedNotebookHandler,
50 50 MainKernelHandler, KernelHandler, KernelActionHandler, IOPubHandler,
51 51 ShellHandler, NotebookRootHandler, NotebookHandler, NotebookCopyHandler,
52 52 RSTHandler, AuthenticatedFileHandler, PrintNotebookHandler,
53 53 MainClusterHandler, ClusterProfileHandler, ClusterActionHandler,
54 54 FileFindHandler,
55 55 )
56 56 from .nbmanager import NotebookManager
57 57 from .filenbmanager import FileNotebookManager
58 58 from .clustermanager import ClusterManager
59 59
60 60 from IPython.config.application import catch_config_error, boolean_flag
61 61 from IPython.core.application import BaseIPythonApplication
62 62 from IPython.core.profiledir import ProfileDir
63 63 from IPython.frontend.consoleapp import IPythonConsoleApp
64 64 from IPython.lib.kernel import swallow_argv
65 65 from IPython.zmq.session import Session, default_secure
66 66 from IPython.zmq.zmqshell import ZMQInteractiveShell
67 67 from IPython.zmq.ipkernel import (
68 68 flags as ipkernel_flags,
69 69 aliases as ipkernel_aliases,
70 70 IPKernelApp
71 71 )
72 72 from IPython.utils.importstring import import_item
73 73 from IPython.utils.traitlets import (
74 74 Dict, Unicode, Integer, List, Enum, Bool,
75 75 DottedObjectName
76 76 )
77 77 from IPython.utils import py3compat
78 78 from IPython.utils.path import filefind
79 79
80 80 #-----------------------------------------------------------------------------
81 81 # Module globals
82 82 #-----------------------------------------------------------------------------
83 83
84 84 _kernel_id_regex = r"(?P<kernel_id>\w+-\w+-\w+-\w+-\w+)"
85 85 _kernel_action_regex = r"(?P<action>restart|interrupt)"
86 86 _notebook_id_regex = r"(?P<notebook_id>\w+-\w+-\w+-\w+-\w+)"
87 87 _profile_regex = r"(?P<profile>[^\/]+)" # there is almost no text that is invalid
88 88 _cluster_action_regex = r"(?P<action>start|stop)"
89 89
90 90
91 91 LOCALHOST = '127.0.0.1'
92 92
93 93 _examples = """
94 94 ipython notebook # start the notebook
95 95 ipython notebook --profile=sympy # use the sympy profile
96 96 ipython notebook --pylab=inline # pylab in inline plotting mode
97 97 ipython notebook --certfile=mycert.pem # use SSL/TLS certificate
98 98 ipython notebook --port=5555 --ip=* # Listen on port 5555, all interfaces
99 99 """
100 100
101 101 #-----------------------------------------------------------------------------
102 102 # Helper functions
103 103 #-----------------------------------------------------------------------------
104 104
105 105 def url_path_join(a,b):
106 106 if a.endswith('/') and b.startswith('/'):
107 107 return a[:-1]+b
108 108 else:
109 109 return a+b
110 110
111 111 def random_ports(port, n):
112 112 """Generate a list of n random ports near the given port.
113 113
114 114 The first 5 ports will be sequential, and the remaining n-5 will be
115 115 randomly selected in the range [port-2*n, port+2*n].
116 116 """
117 117 for i in range(min(5, n)):
118 118 yield port + i
119 119 for i in range(n-5):
120 120 yield port + random.randint(-2*n, 2*n)
121 121
122 122 #-----------------------------------------------------------------------------
123 123 # The Tornado web application
124 124 #-----------------------------------------------------------------------------
125 125
126 126 class NotebookWebApplication(web.Application):
127 127
128 def __init__(self, ipython_app, kernel_manager, notebook_manager,
128 def __init__(self, ipython_app, kernel_manager, notebook_manager,
129 129 cluster_manager, log,
130 130 base_project_url, settings_overrides):
131 131 handlers = [
132 132 (r"/", ProjectDashboardHandler),
133 133 (r"/login", LoginHandler),
134 134 (r"/logout", LogoutHandler),
135 135 (r"/new", NewHandler),
136 136 (r"/%s" % _notebook_id_regex, NamedNotebookHandler),
137 137 (r"/%s/copy" % _notebook_id_regex, NotebookCopyHandler),
138 138 (r"/%s/print" % _notebook_id_regex, PrintNotebookHandler),
139 139 (r"/kernels", MainKernelHandler),
140 140 (r"/kernels/%s" % _kernel_id_regex, KernelHandler),
141 141 (r"/kernels/%s/%s" % (_kernel_id_regex, _kernel_action_regex), KernelActionHandler),
142 142 (r"/kernels/%s/iopub" % _kernel_id_regex, IOPubHandler),
143 143 (r"/kernels/%s/shell" % _kernel_id_regex, ShellHandler),
144 144 (r"/notebooks", NotebookRootHandler),
145 145 (r"/notebooks/%s" % _notebook_id_regex, NotebookHandler),
146 146 (r"/rstservice/render", RSTHandler),
147 147 (r"/files/(.*)", AuthenticatedFileHandler, {'path' : notebook_manager.notebook_dir}),
148 148 (r"/clusters", MainClusterHandler),
149 149 (r"/clusters/%s/%s" % (_profile_regex, _cluster_action_regex), ClusterActionHandler),
150 150 (r"/clusters/%s" % _profile_regex, ClusterProfileHandler),
151 151 ]
152 152
153 153 # Python < 2.6.5 doesn't accept unicode keys in f(**kwargs), and
154 154 # base_project_url will always be unicode, which will in turn
155 155 # make the patterns unicode, and ultimately result in unicode
156 156 # keys in kwargs to handler._execute(**kwargs) in tornado.
157 157 # This enforces that base_project_url be ascii in that situation.
158 158 #
159 159 # Note that the URLs these patterns check against are escaped,
160 160 # and thus guaranteed to be ASCII: 'héllo' is really 'h%C3%A9llo'.
161 161 base_project_url = py3compat.unicode_to_str(base_project_url, 'ascii')
162 162
163 163 settings = dict(
164 164 template_path=os.path.join(os.path.dirname(__file__), "templates"),
165 165 static_path=ipython_app.static_file_path,
166 166 static_handler_class = FileFindHandler,
167 167 static_url_prefix = url_path_join(base_project_url,'/static/'),
168 168 cookie_secret=os.urandom(1024),
169 169 login_url=url_path_join(base_project_url,'/login'),
170 170 cookie_name='username-%s' % uuid.uuid4(),
171 171 )
172 172
173 173 # allow custom overrides for the tornado web app.
174 174 settings.update(settings_overrides)
175 175
176 176 # prepend base_project_url onto the patterns that we match
177 177 new_handlers = []
178 178 for handler in handlers:
179 179 pattern = url_path_join(base_project_url, handler[0])
180 180 new_handler = tuple([pattern]+list(handler[1:]))
181 181 new_handlers.append( new_handler )
182 182
183 183 super(NotebookWebApplication, self).__init__(new_handlers, **settings)
184 184
185 185 self.kernel_manager = kernel_manager
186 186 self.notebook_manager = notebook_manager
187 187 self.cluster_manager = cluster_manager
188 188 self.ipython_app = ipython_app
189 189 self.read_only = self.ipython_app.read_only
190 190 self.config = self.ipython_app.config
191 191 self.use_less = self.ipython_app.use_less
192 192 self.log = log
193 193 self.jinja2_env = Environment(loader=FileSystemLoader(os.path.join(os.path.dirname(__file__), "templates")))
194 194
195 195
196 196
197 197 #-----------------------------------------------------------------------------
198 198 # Aliases and Flags
199 199 #-----------------------------------------------------------------------------
200 200
201 201 flags = dict(ipkernel_flags)
202 202 flags['no-browser']=(
203 203 {'NotebookApp' : {'open_browser' : False}},
204 204 "Don't open the notebook in a browser after startup."
205 205 )
206 206 flags['no-mathjax']=(
207 207 {'NotebookApp' : {'enable_mathjax' : False}},
208 208 """Disable MathJax
209 209
210 210 MathJax is the javascript library IPython uses to render math/LaTeX. It is
211 211 very large, so you may want to disable it if you have a slow internet
212 212 connection, or for offline use of the notebook.
213 213
214 214 When disabled, equations etc. will appear as their untransformed TeX source.
215 215 """
216 216 )
217 217 flags['read-only'] = (
218 218 {'NotebookApp' : {'read_only' : True}},
219 219 """Allow read-only access to notebooks.
220 220
221 221 When using a password to protect the notebook server, this flag
222 222 allows unauthenticated clients to view the notebook list, and
223 223 individual notebooks, but not edit them, start kernels, or run
224 224 code.
225 225
226 226 If no password is set, the server will be entirely read-only.
227 227 """
228 228 )
229 229
230 230 # Add notebook manager flags
231 231 flags.update(boolean_flag('script', 'FileNotebookManager.save_script',
232 232 'Auto-save a .py script everytime the .ipynb notebook is saved',
233 233 'Do not auto-save .py scripts for every notebook'))
234 234
235 235 # the flags that are specific to the frontend
236 236 # these must be scrubbed before being passed to the kernel,
237 237 # or it will raise an error on unrecognized flags
238 238 notebook_flags = ['no-browser', 'no-mathjax', 'read-only', 'script', 'no-script']
239 239
240 240 aliases = dict(ipkernel_aliases)
241 241
242 242 aliases.update({
243 243 'ip': 'NotebookApp.ip',
244 244 'port': 'NotebookApp.port',
245 245 'port-retries': 'NotebookApp.port_retries',
246 246 'transport': 'KernelManager.transport',
247 247 'keyfile': 'NotebookApp.keyfile',
248 248 'certfile': 'NotebookApp.certfile',
249 249 'notebook-dir': 'NotebookManager.notebook_dir',
250 250 'browser': 'NotebookApp.browser',
251 251 })
252 252
253 253 # remove ipkernel flags that are singletons, and don't make sense in
254 254 # multi-kernel evironment:
255 255 aliases.pop('f', None)
256 256
257 257 notebook_aliases = [u'port', u'port-retries', u'ip', u'keyfile', u'certfile',
258 258 u'notebook-dir']
259 259
260 260 #-----------------------------------------------------------------------------
261 261 # NotebookApp
262 262 #-----------------------------------------------------------------------------
263 263
264 264 class NotebookApp(BaseIPythonApplication):
265 265
266 266 name = 'ipython-notebook'
267 267 default_config_file_name='ipython_notebook_config.py'
268 268
269 269 description = """
270 270 The IPython HTML Notebook.
271 271
272 272 This launches a Tornado based HTML Notebook Server that serves up an
273 273 HTML5/Javascript Notebook client.
274 274 """
275 275 examples = _examples
276 276
277 277 classes = IPythonConsoleApp.classes + [MappingKernelManager, NotebookManager,
278 278 FileNotebookManager]
279 279 flags = Dict(flags)
280 280 aliases = Dict(aliases)
281 281
282 282 kernel_argv = List(Unicode)
283 283
284 284 log_level = Enum((0,10,20,30,40,50,'DEBUG','INFO','WARN','ERROR','CRITICAL'),
285 285 default_value=logging.INFO,
286 286 config=True,
287 287 help="Set the log level by value or name.")
288 288
289 289 # create requested profiles by default, if they don't exist:
290 290 auto_create = Bool(True)
291 291
292 292 # file to be opened in the notebook server
293 293 file_to_run = Unicode('')
294 294
295 295 # Network related information.
296 296
297 297 ip = Unicode(LOCALHOST, config=True,
298 298 help="The IP address the notebook server will listen on."
299 299 )
300 300
301 301 def _ip_changed(self, name, old, new):
302 302 if new == u'*': self.ip = u''
303 303
304 304 port = Integer(8888, config=True,
305 305 help="The port the notebook server will listen on."
306 306 )
307 307 port_retries = Integer(50, config=True,
308 308 help="The number of additional ports to try if the specified port is not available."
309 309 )
310 310
311 311 certfile = Unicode(u'', config=True,
312 312 help="""The full path to an SSL/TLS certificate file."""
313 313 )
314 314
315 315 keyfile = Unicode(u'', config=True,
316 316 help="""The full path to a private key file for usage with SSL/TLS."""
317 317 )
318 318
319 319 password = Unicode(u'', config=True,
320 320 help="""Hashed password to use for web authentication.
321 321
322 322 To generate, type in a python/IPython shell:
323 323
324 324 from IPython.lib import passwd; passwd()
325 325
326 326 The string should be of the form type:salt:hashed-password.
327 327 """
328 328 )
329 329
330 330 open_browser = Bool(True, config=True,
331 331 help="""Whether to open in a browser after starting.
332 332 The specific browser used is platform dependent and
333 333 determined by the python standard library `webbrowser`
334 334 module, unless it is overridden using the --browser
335 335 (NotebookApp.browser) configuration option.
336 336 """)
337 337
338 338 browser = Unicode(u'', config=True,
339 339 help="""Specify what command to use to invoke a web
340 340 browser when opening the notebook. If not specified, the
341 341 default browser will be determined by the `webbrowser`
342 342 standard library module, which allows setting of the
343 343 BROWSER environment variable to override it.
344 344 """)
345 345
346 346 read_only = Bool(False, config=True,
347 347 help="Whether to prevent editing/execution of notebooks."
348 348 )
349 349
350 use_less = Bool(False, config=True,
350 use_less = Bool(False, config=True,
351 351 help="""Wether to use Browser Side less-css parsing
352 instead of compiled css version in templates that allows
353 it. This is mainly convenient when working on the less
352 instead of compiled css version in templates that allows
353 it. This is mainly convenient when working on the less
354 354 file to avoid a build step, or if user want to overwrite
355 355 some of the less variables without having to recompile
356 356 everything.""")
357
357
358 358 webapp_settings = Dict(config=True,
359 359 help="Supply overrides for the tornado.web.Application that the "
360 360 "IPython notebook uses.")
361 361
362 362 enable_mathjax = Bool(True, config=True,
363 363 help="""Whether to enable MathJax for typesetting math/TeX
364 364
365 365 MathJax is the javascript library IPython uses to render math/LaTeX. It is
366 366 very large, so you may want to disable it if you have a slow internet
367 367 connection, or for offline use of the notebook.
368 368
369 369 When disabled, equations etc. will appear as their untransformed TeX source.
370 370 """
371 371 )
372 372 def _enable_mathjax_changed(self, name, old, new):
373 373 """set mathjax url to empty if mathjax is disabled"""
374 374 if not new:
375 375 self.mathjax_url = u''
376 376
377 377 base_project_url = Unicode('/', config=True,
378 378 help='''The base URL for the notebook server.
379 379
380 380 Leading and trailing slashes can be omitted,
381 381 and will automatically be added.
382 382 ''')
383 383 def _base_project_url_changed(self, name, old, new):
384 384 if not new.startswith('/'):
385 385 self.base_project_url = '/'+new
386 386 elif not new.endswith('/'):
387 387 self.base_project_url = new+'/'
388 388
389 389 base_kernel_url = Unicode('/', config=True,
390 390 help='''The base URL for the kernel server
391 391
392 392 Leading and trailing slashes can be omitted,
393 393 and will automatically be added.
394 394 ''')
395 395 def _base_kernel_url_changed(self, name, old, new):
396 396 if not new.startswith('/'):
397 397 self.base_kernel_url = '/'+new
398 398 elif not new.endswith('/'):
399 399 self.base_kernel_url = new+'/'
400 400
401 401 websocket_host = Unicode("", config=True,
402 402 help="""The hostname for the websocket server."""
403 403 )
404 404
405 405 extra_static_paths = List(Unicode, config=True,
406 406 help="""Extra paths to search for serving static files.
407 407
408 408 This allows adding javascript/css to be available from the notebook server machine,
409 409 or overriding individual files in the IPython"""
410 410 )
411 411 def _extra_static_paths_default(self):
412 412 return [os.path.join(self.profile_dir.location, 'static')]
413 413
414 414 @property
415 415 def static_file_path(self):
416 416 """return extra paths + the default location"""
417 417 return self.extra_static_paths + [os.path.join(os.path.dirname(__file__), "static")]
418 418
419 419 mathjax_url = Unicode("", config=True,
420 420 help="""The url for MathJax.js."""
421 421 )
422 422 def _mathjax_url_default(self):
423 423 if not self.enable_mathjax:
424 424 return u''
425 425 static_url_prefix = self.webapp_settings.get("static_url_prefix",
426 426 "/static/")
427 427 try:
428 428 mathjax = filefind(os.path.join('mathjax', 'MathJax.js'), self.static_file_path)
429 429 except IOError:
430 430 if self.certfile:
431 431 # HTTPS: load from Rackspace CDN, because SSL certificate requires it
432 432 base = u"https://c328740.ssl.cf1.rackcdn.com"
433 433 else:
434 434 base = u"http://cdn.mathjax.org"
435 435
436 436 url = base + u"/mathjax/latest/MathJax.js"
437 437 self.log.info("Using MathJax from CDN: %s", url)
438 438 return url
439 439 else:
440 440 self.log.info("Using local MathJax from %s" % mathjax)
441 441 return static_url_prefix+u"mathjax/MathJax.js"
442 442
443 443 def _mathjax_url_changed(self, name, old, new):
444 444 if new and not self.enable_mathjax:
445 445 # enable_mathjax=False overrides mathjax_url
446 446 self.mathjax_url = u''
447 447 else:
448 448 self.log.info("Using MathJax: %s", new)
449 449
450 450 notebook_manager_class = DottedObjectName('IPython.frontend.html.notebook.filenbmanager.FileNotebookManager',
451 451 config=True,
452 452 help='The notebook manager class to use.')
453 453
454 454 def parse_command_line(self, argv=None):
455 455 super(NotebookApp, self).parse_command_line(argv)
456 456 if argv is None:
457 457 argv = sys.argv[1:]
458 458
459 459 # Scrub frontend-specific flags
460 460 self.kernel_argv = swallow_argv(argv, notebook_aliases, notebook_flags)
461 461 # Kernel should inherit default config file from frontend
462 462 self.kernel_argv.append("--KernelApp.parent_appname='%s'"%self.name)
463 463
464 464 if self.extra_args:
465 465 f = os.path.abspath(self.extra_args[0])
466 466 if os.path.isdir(f):
467 467 nbdir = f
468 468 else:
469 469 self.file_to_run = f
470 470 nbdir = os.path.dirname(f)
471 471 self.config.NotebookManager.notebook_dir = nbdir
472 472
473 473 def init_configurables(self):
474 474 # force Session default to be secure
475 475 default_secure(self.config)
476 476 self.kernel_manager = MappingKernelManager(
477 477 config=self.config, log=self.log, kernel_argv=self.kernel_argv,
478 478 connection_dir = self.profile_dir.security_dir,
479 479 )
480 480 kls = import_item(self.notebook_manager_class)
481 481 self.notebook_manager = kls(config=self.config, log=self.log)
482 482 self.notebook_manager.log_info()
483 483 self.notebook_manager.load_notebook_names()
484 484 self.cluster_manager = ClusterManager(config=self.config, log=self.log)
485 485 self.cluster_manager.update_profiles()
486 486
487 487 def init_logging(self):
488 488 # This prevents double log messages because tornado use a root logger that
489 489 # self.log is a child of. The logging module dipatches log messages to a log
490 490 # and all of its ancenstors until propagate is set to False.
491 491 self.log.propagate = False
492 492
493 493 def init_webapp(self):
494 494 """initialize tornado webapp and httpserver"""
495 495 self.web_app = NotebookWebApplication(
496 496 self, self.kernel_manager, self.notebook_manager,
497 497 self.cluster_manager, self.log,
498 498 self.base_project_url, self.webapp_settings
499 499 )
500 500 if self.certfile:
501 501 ssl_options = dict(certfile=self.certfile)
502 502 if self.keyfile:
503 503 ssl_options['keyfile'] = self.keyfile
504 504 else:
505 505 ssl_options = None
506 506 self.web_app.password = self.password
507 507 self.http_server = httpserver.HTTPServer(self.web_app, ssl_options=ssl_options)
508 508 if not self.ip:
509 509 warning = "WARNING: The notebook server is listening on all IP addresses"
510 510 if ssl_options is None:
511 511 self.log.critical(warning + " and not using encryption. This"
512 512 "is not recommended.")
513 513 if not self.password and not self.read_only:
514 514 self.log.critical(warning + "and not using authentication."
515 515 "This is highly insecure and not recommended.")
516 516 success = None
517 517 for port in random_ports(self.port, self.port_retries+1):
518 518 try:
519 519 self.http_server.listen(port, self.ip)
520 520 except socket.error as e:
521 521 if e.errno != errno.EADDRINUSE:
522 522 raise
523 523 self.log.info('The port %i is already in use, trying another random port.' % port)
524 524 else:
525 525 self.port = port
526 526 success = True
527 527 break
528 528 if not success:
529 529 self.log.critical('ERROR: the notebook server could not be started because '
530 530 'no available port could be found.')
531 531 self.exit(1)
532 532
533 533 def init_signal(self):
534 534 # FIXME: remove this check when pyzmq dependency is >= 2.1.11
535 535 # safely extract zmq version info:
536 536 try:
537 537 zmq_v = zmq.pyzmq_version_info()
538 538 except AttributeError:
539 539 zmq_v = [ int(n) for n in re.findall(r'\d+', zmq.__version__) ]
540 540 if 'dev' in zmq.__version__:
541 541 zmq_v.append(999)
542 542 zmq_v = tuple(zmq_v)
543 543 if zmq_v >= (2,1,9) and not sys.platform.startswith('win'):
544 544 # This won't work with 2.1.7 and
545 545 # 2.1.9-10 will log ugly 'Interrupted system call' messages,
546 546 # but it will work
547 547 signal.signal(signal.SIGINT, self._handle_sigint)
548 548 signal.signal(signal.SIGTERM, self._signal_stop)
549 549
550 550 def _handle_sigint(self, sig, frame):
551 551 """SIGINT handler spawns confirmation dialog"""
552 552 # register more forceful signal handler for ^C^C case
553 553 signal.signal(signal.SIGINT, self._signal_stop)
554 554 # request confirmation dialog in bg thread, to avoid
555 555 # blocking the App
556 556 thread = threading.Thread(target=self._confirm_exit)
557 557 thread.daemon = True
558 558 thread.start()
559 559
560 560 def _restore_sigint_handler(self):
561 561 """callback for restoring original SIGINT handler"""
562 562 signal.signal(signal.SIGINT, self._handle_sigint)
563 563
564 564 def _confirm_exit(self):
565 565 """confirm shutdown on ^C
566 566
567 567 A second ^C, or answering 'y' within 5s will cause shutdown,
568 568 otherwise original SIGINT handler will be restored.
569 569
570 570 This doesn't work on Windows.
571 571 """
572 572 # FIXME: remove this delay when pyzmq dependency is >= 2.1.11
573 573 time.sleep(0.1)
574 574 sys.stdout.write("Shutdown Notebook Server (y/[n])? ")
575 575 sys.stdout.flush()
576 576 r,w,x = select.select([sys.stdin], [], [], 5)
577 577 if r:
578 578 line = sys.stdin.readline()
579 579 if line.lower().startswith('y'):
580 580 self.log.critical("Shutdown confirmed")
581 581 ioloop.IOLoop.instance().stop()
582 582 return
583 583 else:
584 584 print "No answer for 5s:",
585 585 print "resuming operation..."
586 586 # no answer, or answer is no:
587 587 # set it back to original SIGINT handler
588 588 # use IOLoop.add_callback because signal.signal must be called
589 589 # from main thread
590 590 ioloop.IOLoop.instance().add_callback(self._restore_sigint_handler)
591 591
592 592 def _signal_stop(self, sig, frame):
593 593 self.log.critical("received signal %s, stopping", sig)
594 594 ioloop.IOLoop.instance().stop()
595 595
596 596 @catch_config_error
597 597 def initialize(self, argv=None):
598 598 self.init_logging()
599 599 super(NotebookApp, self).initialize(argv)
600 600 self.init_configurables()
601 601 self.init_webapp()
602 602 self.init_signal()
603 603
604 604 def cleanup_kernels(self):
605 605 """Shutdown all kernels.
606 606
607 607 The kernels will shutdown themselves when this process no longer exists,
608 608 but explicit shutdown allows the KernelManagers to cleanup the connection files.
609 609 """
610 610 self.log.info('Shutting down kernels')
611 611 self.kernel_manager.shutdown_all()
612 612
613 613 def start(self):
614 614 ip = self.ip if self.ip else '[all ip addresses on your system]'
615 615 proto = 'https' if self.certfile else 'http'
616 616 info = self.log.info
617 617 info("The IPython Notebook is running at: %s://%s:%i%s" %
618 618 (proto, ip, self.port,self.base_project_url) )
619 619 info("Use Control-C to stop this server and shut down all kernels.")
620 620
621 621 if self.open_browser or self.file_to_run:
622 622 ip = self.ip or '127.0.0.1'
623 623 try:
624 624 browser = webbrowser.get(self.browser or None)
625 625 except webbrowser.Error as e:
626 626 self.log.warn('No web browser found: %s.' % e)
627 627 browser = None
628 628
629 629 if self.file_to_run:
630 630 name, _ = os.path.splitext(os.path.basename(self.file_to_run))
631 631 url = self.notebook_manager.rev_mapping.get(name, '')
632 632 else:
633 633 url = ''
634 634 if browser:
635 635 b = lambda : browser.open("%s://%s:%i%s%s" % (proto, ip,
636 636 self.port, self.base_project_url, url), new=2)
637 637 threading.Thread(target=b).start()
638 638 try:
639 639 ioloop.IOLoop.instance().start()
640 640 except KeyboardInterrupt:
641 641 info("Interrupted...")
642 642 finally:
643 643 self.cleanup_kernels()
644 644
645 645
646 646 #-----------------------------------------------------------------------------
647 647 # Main entry point
648 648 #-----------------------------------------------------------------------------
649 649
650 650 def launch_new_instance():
651 651 app = NotebookApp.instance()
652 652 app.initialize()
653 653 app.start()
654 654
@@ -1,7 +1,7 b''
1 1 Js files in this fomder from Tag 1.3.1 sha:68297d7e3850b5eedac825a202eb64f9c80ce183
2 from
2 from
3 3 https://github.com/cloudhead/less.js
4 4
5 5 /dists/less-1.3.1.js
6 6 /dists/less-1.3.1.min.js
7 7
@@ -1,97 +1,97 b''
1 1
2 2 /* Flexible box model classes */
3 3 /* Taken from Alex Russell http://infrequently.org/2009/08/css-3-progress/ */
4
4
5 5 .hbox {
6 6 display: -webkit-box;
7 7 -webkit-box-orient: horizontal;
8 8 -webkit-box-align: stretch;
9
9
10 10 display: -moz-box;
11 11 -moz-box-orient: horizontal;
12 12 -moz-box-align: stretch;
13
13
14 14 display: box;
15 15 box-orient: horizontal;
16 16 box-align: stretch;
17 17 }
18
18
19 19 .hbox > * {
20 20 -webkit-box-flex: 0;
21 21 -moz-box-flex: 0;
22 22 box-flex: 0;
23 23 }
24
24
25 25 .vbox {
26 26 display: -webkit-box;
27 27 -webkit-box-orient: vertical;
28 28 -webkit-box-align: stretch;
29
29
30 30 display: -moz-box;
31 31 -moz-box-orient: vertical;
32 32 -moz-box-align: stretch;
33
33
34 34 display: box;
35 35 box-orient: vertical;
36 36 box-align: stretch;
37 37 }
38
38
39 39 .vbox > * {
40 40 -webkit-box-flex: 0;
41 41 -moz-box-flex: 0;
42 42 box-flex: 0;
43 43 }
44
44
45 45 .reverse {
46 46 -webkit-box-direction: reverse;
47 47 -moz-box-direction: reverse;
48 48 box-direction: reverse;
49 49 }
50
50
51 51 .box-flex0 {
52 52 -webkit-box-flex: 0;
53 53 -moz-box-flex: 0;
54 54 box-flex: 0;
55 55 }
56
56
57 57 .box-flex1, .box-flex {
58 58 -webkit-box-flex: 1;
59 59 -moz-box-flex: 1;
60 60 box-flex: 1;
61 61 }
62
62
63 63 .box-flex2 {
64 64 -webkit-box-flex: 2;
65 65 -moz-box-flex: 2;
66 66 box-flex: 2;
67 67 }
68
68
69 69 .box-group1 {
70 70 -webkit-box-flex-group: 1;
71 71 -moz-box-flex-group: 1;
72 72 box-flex-group: 1;
73 73 }
74
74
75 75 .box-group2 {
76 76 -webkit-box-flex-group: 2;
77 77 -moz-box-flex-group: 2;
78 78 box-flex-group: 2;
79 79 }
80
80
81 81 .start {
82 82 -webkit-box-pack: start;
83 83 -moz-box-pack: start;
84 84 box-pack: start;
85 85 }
86
86
87 87 .end {
88 88 -webkit-box-pack: end;
89 89 -moz-box-pack: end;
90 90 box-pack: end;
91 91 }
92
92
93 93 .center {
94 94 -webkit-box-pack: center;
95 95 -moz-box-pack: center;
96 96 box-pack: center;
97 97 }
@@ -1,455 +1,455 b''
1 1 /**
2 2 * Primary styles
3 3 *
4 4 * Author: IPython Development Team
5 5 */
6 6
7 7 @import "variables.less";
8 8
9 9 body {
10 10 overflow: hidden;
11 11 background-color:@notebook_background;
12 12 }
13 13
14 14 blockquote {
15 15 border-left: 4px solid #DDD;
16 16 padding: 0 15px;
17 17 color: #777;
18 18 }
19 19
20 20 span#save_widget {
21 21 padding: 5px;
22 22 margin: 0px 0px 0px 300px;
23 23 display:inline-block;
24 24 }
25 25
26 26 span#notebook_name {
27 27 height: 1em;
28 28 line-height: 1em;
29 29 padding: 3px;
30 30 border: none;
31 31 font-size: 146.5%;
32 32 }
33 33
34 34
35 35 .ui-menubar-item .ui-button .ui-button-text {
36 36 padding: 0.4em 1.0em;
37 37 font-size: 100%;
38 38 }
39 39
40 40 .ui-menu {
41 41 -moz-box-shadow: 0px 6px 10px -1px #adadad;
42 42 -webkit-box-shadow: 0px 6px 10px -1px #adadad;
43 43 box-shadow: 0px 6px 10px -1px #adadad;
44 44 }
45 45
46 46 .ui-menu .ui-menu-item a {
47 47 border: 1px solid transparent;
48 48 padding: 2px 1.6em;
49 49 }
50 50
51 51 .ui-menu .ui-menu-item a.ui-state-focus {
52 52 margin: 0;
53 53 }
54 54
55 55 .ui-menu hr {
56 56 margin: 0.3em 0;
57 57 }
58 58
59 59 #menubar_container {
60 60 position: relative;
61 61 }
62 62
63 63 #notification_area {
64 64 position: absolute;
65 65 right: 0px;
66 66 top: 0px;
67 67 height: 25px;
68 68 padding: 3px 0px;
69 69 padding-right: 3px;
70 70 z-index: 10;
71 71 }
72 72
73 73 .notification_widget{
74 74 float : right;
75 75 right: 0px;
76 76 top: 1px;
77 77 height: 25px;
78 78 padding: 3px 6px;
79 79 z-index: 10;
80 80 }
81 81
82 82 .toolbar {
83 83 padding: 3px 15px;
84 84 border-bottom: @borderwidth @border_color solid;
85 85 }
86 86
87 87 #maintoolbar > select, #maintoolbar label {
88 88 height : 23px;
89 89 vertical-align: top;
90 90 margin-right:2px;
91 91 margin-bottom:0;
92 92 display: inline;
93 93 }
94 94
95 95 #cell_type {
96 96 font-size: 85%;
97 97 margin-left:0.3em;
98 98 margin-right:0.3em;
99 99
100 100 }
101 101
102 102
103 103 #ipython-main-app {
104 104 width: 100%;
105 105 position: relative;
106 106 }
107 107
108 108 span#quick_help_area {
109 109 position: static;
110 110 padding: 5px 0px;
111 111 margin: 0px 0px 0px 0px;
112 112 }
113 113
114 114 .help_string {
115 115 float: right;
116 116 width: 170px;
117 117 padding: 0px 5px;
118 118 text-align: left;
119 119 font-size: 85%;
120 120 }
121 121
122 122 .help_string_label {
123 123 float: right;
124 124 font-size: 85%;
125 125 }
126 126
127 127 div#notebook_panel {
128 128 margin: 0px 0px 0px 0px;
129 129 padding: 0px;
130 130 }
131 131
132 132 div#notebook {
133 133 overflow-y: scroll;
134 134 overflow-x: auto;
135 135 width: 100%;
136 136 /* This spaces the cell away from the edge of the notebook area */
137 137 padding: 5px 5px 15px 5px;
138 138 margin: 0px;
139 139 }
140 140
141 141 div#pager_splitter {
142 142 height: 8px;
143 143 }
144 144
145 145 #pager_container {
146 146 position : relative;
147 147 }
148 148
149 149 div#pager {
150 150 padding: 15px;
151 151 overflow: auto;
152 152 display: none;
153 153 }
154 154
155 155 div.ui-widget-content {
156 156 border: 1px solid @border_color;
157 157 outline: none;
158 158 }
159 159
160 160 .cell {
161 161 border: 1px solid transparent;
162 162
163 163 &.selected {
164 164 .corner-all;
165 165 background-color:@cell_selected_background;
166 166 border : thin @border_color solid;
167 167 }
168 168 }
169 169
170 170 div.cell {
171 171 width: 100%;
172 172 padding: 5px 5px 5px 0px;
173 173 /* This acts as a spacer between cells, that is outside the border */
174 174 margin: 2px 0px 2px 0px;
175 175 outline: none;
176 176 }
177 177
178 178 div.code_cell {
179 179 }
180 180
181 181 /* any special styling for code cells that are currently running goes here */
182 182 div.code_cell.running {
183 183 }
184 184
185 185 div.prompt {
186 186 /* This needs to be wide enough for 3 digit prompt numbers: In[100]: */
187 187 width: 11ex;
188 188 /* This 0.4em is tuned to match the padding on the CodeMirror editor. */
189 189 padding: 0.4em;
190 190 margin: 0px;
191 191 font-family: monospace;
192 192 text-align: right;
193 193 /* This has to match that of the the CodeMirror class line-height below */
194 194 line-height: 1.231;
195 195 }
196 196
197 197 div.input {
198 198 page-break-inside: avoid;
199 199 }
200 200
201 201 /* input_area and input_prompt must match in top border and margin for alignment */
202 202 div.input_area {
203 203 /*color: @fontBaseColor;*/
204 204 border: 1px solid @border_color;
205 205 .corner-all;
206 206 background: @cell_background;
207 207 }
208 208
209 209 div.input_prompt {
210 210 color: navy;
211 211 border-top: 1px solid transparent;
212 212 }
213 213
214 214 div.output_wrapper {
215 215 /* This is a spacer between the input and output of each cell */
216 216 margin-top: 5px;
217 217 margin-left: 5px;
218 218 /* FF needs explicit width to stretch */
219 219 width: 100%;
220 220 /* this position must be relative to enable descendents to be absolute within it */
221 221 position: relative;
222 222 }
223 223
224 224 /* class for the output area when it should be height-limited */
225 225 div.output_scroll {
226 226 /* ideally, this would be max-height, but FF barfs all over that */
227 227 height: 24em;
228 228 /* FF needs this *and the wrapper* to specify full width, or it will shrinkwrap */
229 229 width: 100%;
230
230
231 231 overflow: auto;
232 232 .corner-all;
233 233 box-shadow: inset 0 2px 8px rgba(0, 0, 0, .8);
234 234 }
235 235
236 236 /* output div while it is collapsed */
237 237 div.output_collapsed {
238 238 margin-right: 5px;
239 239 }
240 240
241 241 div.out_prompt_overlay {
242 242 height: 100%;
243 243 padding: 0px;
244 244 position: absolute;
245 245 .corner-all;
246 246 }
247 247
248 248 div.out_prompt_overlay:hover {
249 249 /* use inner shadow to get border that is computed the same on WebKit/FF */
250 250 box-shadow: inset 0 0 1px #000;
251 251 background: rgba(240, 240, 240, 0.5);
252 252 }
253 253
254 254 div.output_prompt {
255 255 color: darkred;
256 256 /* 5px right shift to account for margin in parent container */
257 257 margin: 0 5px 0 -5px;
258 258 }
259 259
260 260 /* This class is the outer container of all output sections. */
261 261 div.output_area {
262 262 padding: 0px;
263 263 page-break-inside: avoid;
264 264 }
265 265
266 266
267 267 /* This is needed to protect the pre formating from global settings such
268 268 as that of bootstrap */
269 269 div.output_area pre {
270 270 font-family: monospace;
271 271 margin: 0;
272 272 padding: 0;
273 273 border: 0;
274 274 font-size: 100%;
275 275 font: inherit;
276 276 vertical-align: baseline;
277 277 color: black;
278 278 background-color: white;
279 279 }
280 280
281 281 /* This class is for the output subarea inside the output_area and after
282 282 the prompt div. */
283 283 div.output_subarea {
284 284 padding: 0.44em 0.4em 0.4em 1px;
285 285 }
286 286
287 287 /* The rest of the output_* classes are for special styling of the different
288 288 output types */
289 289
290 290 /* all text output has this class: */
291 291 div.output_text {
292 292 text-align: left;
293 293 color: @fontBaseColor;
294 294 font-family: monospace;
295 295 /* This has to match that of the the CodeMirror class line-height below */
296 296 line-height: 1.231;
297 297 }
298 298
299 299 /* stdout/stderr are 'text' as well as 'stream', but pyout/pyerr are *not* streams */
300 300 div.output_stream {
301 301 padding-top: 0.0em;
302 302 padding-bottom: 0.0em;
303 303 }
304 304 div.output_stdout {
305 305 }
306 306 div.output_stderr {
307 307 background: #fdd; /* very light red background for stderr */
308 308 }
309 309
310 310 div.output_latex {
311 311 text-align: left;
312 312 }
313 313
314 314 div.output_html {
315 315 }
316 316
317 317 div.output_png {
318 318 }
319 319
320 320 div.output_jpeg {
321 321 }
322 322
323 323 div.text_cell {
324 324 padding: 5px 5px 5px 5px;
325 325 }
326 326
327 327 div.text_cell_input {
328 328 color: @fontBaseColor;
329 329 border: 1px solid @border_color;
330 330 .corner-all;
331 331 background: @cell_background;
332 332 }
333 333
334 334 div.text_cell_render {
335 335 /*font-family: "Helvetica Neue", Arial, Helvetica, Geneva, sans-serif;*/
336 336 outline: none;
337 337 resize: none;
338 338 width: inherit;
339 339 border-style: none;
340 340 padding: 5px;
341 341 color: @fontBaseColor;
342 342 }
343 343
344 344 /* The following gets added to the <head> if it is detected that the user has a
345 345 * monospace font with inconsistent normal/bold/italic height. See
346 346 * notebookmain.js. Such fonts will have keywords vertically offset with
347 * respect to the rest of the text. The user should select a better font.
347 * respect to the rest of the text. The user should select a better font.
348 348 * See: https://github.com/ipython/ipython/issues/1503
349 349 *
350 350 * .CodeMirror span {
351 351 * vertical-align: bottom;
352 352 * }
353 353 */
354 354
355 355 .CodeMirror {
356 356 line-height: 1.231; /* Changed from 1em to our global default */
357 357 }
358 358
359 359 .CodeMirror-scroll {
360 360 height: auto; /* Changed to auto to autogrow */
361 361 /* The CodeMirror docs are a bit fuzzy on if overflow-y should be hidden or visible.*/
362 362 /* We have found that if it is visible, vertical scrollbars appear with font size changes.*/
363 363 overflow-y: hidden;
364 364 overflow-x: auto; /* Changed from auto to remove scrollbar */
365 365 }
366 366
367 367 /* CSS font colors for translated ANSI colors. */
368 368
369 369
370 370 .ansiblack {color: @fontBaseColor;}
371 371 .ansired {color: darkred;}
372 372 .ansigreen {color: darkgreen;}
373 373 .ansiyellow {color: brown;}
374 374 .ansiblue {color: darkblue;}
375 375 .ansipurple {color: darkviolet;}
376 376 .ansicyan {color: steelblue;}
377 377 .ansigrey {color: grey;}
378 378 .ansibold {font-weight: bold;}
379 379
380 380 .completions {
381 381 position: absolute;
382 382 z-index: 10;
383 383 overflow: hidden;
384 384 border: 1px solid @border_color;
385 385 }
386 386
387 387 .completions select {
388 388 background: white;
389 389 outline: none;
390 390 border: none;
391 391 padding: 0px;
392 392 margin: 0px;
393 393 overflow: auto;
394 394 font-family: monospace;
395 395 }
396 396
397 397 option.context {
398 398 background-color: #DEF7FF;
399 399 }
400 400 option.introspection {
401 401 background-color: #EBF4EB;
402 402 }
403 403
404 404 /*fixed part of the completion*/
405 405 .completions p b {
406 406 font-weight:bold;
407 407 }
408 408
409 409 .completions p {
410 410 background: #DDF;
411 411 /*outline: none;
412 412 padding: 0px;*/
413 413 border-bottom: black solid 1px;
414 414 padding: 1px;
415 415 font-family: monospace;
416 416 }
417 417
418 418 pre.dialog {
419 419 background-color: @cell_background;
420 420 border: 1px solid #ddd;
421 421 .corner-all;
422 422 padding: 0.4em;
423 423 padding-left: 2em;
424 424 }
425 425
426 426 p.dialog {
427 427 padding : 0.2em;
428 428 }
429 429
430 430 .shortcut_key {
431 431 display: inline-block;
432 432 width: 15ex;
433 433 text-align: right;
434 434 font-family: monospace;
435 435 }
436 436
437 437 .shortcut_descr {
438 438 }
439 439
440 440 /* Word-wrap output correctly. This is the CSS3 spelling, though Firefox seems
441 441 to not honor it correctly. Webkit browsers (Chrome, rekonq, Safari) do.
442 442 */
443 443 pre, code, kbd, samp { white-space: pre-wrap; }
444 444
445 445 #fonttest {
446 446 font-family: monospace;
447 447 }
448 448
449 449 .js-error {
450 450 color: darkred;
451 451 }
452 452
453 453
454 454
455 455
@@ -1,68 +1,68 b''
1 1 .rendered_html {color: black;}
2 2 .rendered_html em {font-style: italic;}
3 3 .rendered_html strong {font-weight: bold;}
4 4 .rendered_html u {text-decoration: underline;}
5 5 .rendered_html :link { text-decoration: underline }
6 6 .rendered_html :visited { text-decoration: underline }
7 7 .rendered_html h1 {font-size: 197%; margin: .65em 0; font-weight: bold;}
8 8 .rendered_html h2 {font-size: 153.9%; margin: .75em 0; font-weight: bold;}
9 9 .rendered_html h3 {font-size: 123.1%; margin: .85em 0; font-weight: bold;}
10 10 .rendered_html h4 {font-size: 100% margin: 0.95em 0; font-weight: bold;}
11 11 .rendered_html h5 {font-size: 85%; margin: 1.5em 0; font-weight: bold;}
12 12 .rendered_html h6 {font-size: 77%; margin: 1.65em 0; font-weight: bold;}
13 13 .rendered_html ul {list-style:disc; margin: 1em 2em;}
14 14 .rendered_html ul ul {list-style:square; margin: 0em 2em;}
15 15 .rendered_html ul ul ul {list-style:circle; margin-left: 0em 2em;}
16 16 .rendered_html ol {list-style:decimal; margin: 1em 2em;}
17 17 .rendered_html ol ol {list-style:upper-alpha; margin: 0em 2em;}
18 18 .rendered_html ol ol ol {list-style:lower-alpha; margin: 0em 2em;}
19 19 .rendered_html ol ol ol ol {list-style:lower-roman; margin: 0em 2em;}
20 20 /* any extras will just be numbers: */
21 21 .rendered_html ol ol ol ol ol {list-style:decimal; margin: 0em 2em;}
22 22
23 23 .rendered_html hr {
24 24 color: black;
25 25 background-color: black;
26 26 }
27 27
28 28 .rendered_html pre {
29 29 margin: 1em 2em;
30 30 }
31 31
32 32 .rendered_html blockquote {
33 33 margin: 1em 2em;
34 34 }
35 35
36 36 .rendered_html table {
37 37 border: 1px solid black;
38 38 border-collapse: collapse;
39 39 margin: 1em 2em;
40 40 }
41 41
42 42 .rendered_html td {
43 43 border: 1px solid black;
44 44 text-align: left;
45 45 vertical-align: middle;
46 46 padding: 4px;
47 47 }
48 48
49 49 .rendered_html th {
50 50 border: 1px solid black;
51 51 text-align: left;
52 52 vertical-align: middle;
53 53 padding: 4px;
54 54 font-weight: bold;
55 55 }
56 56
57 57 .rendered_html tr {
58 58 border: 1px solid black;
59 }
59 }
60 60
61 61 .rendered_html p {
62 62 text-align: justify;
63 63 }
64 64
65 65 .rendered_html p + p {
66 66 margin-top: 1em;
67 67 }
68 68
@@ -1,159 +1,159 b''
1 1 /**
2 2 * Primary styles
3 3 *
4 4 * Author: IPython Development Team
5 5 */
6 6
7 7 /** WARNING IF YOU ARE EDITTING THIS FILE, if this is a .css file, It has a lot
8 8 * of chance of beeing generated from the ../less/[samename].less file, you can
9 9 * try to get back the less file by reverting somme commit in history
10 10 **/
11 11
12 12 /*
13 13 * We'll try to get something pretty, so we
14 14 * have some strange css to have the scroll bar on
15 15 * the left with fix button on the top right of the tooltip
16 16 */
17 17
18 18 // double slash comment are remove by less compilation
19 19 // **
20 20 // * Less mixins
21 21 // **/
22 22
23 23 // Four color of the background
24 24 @import "variables" ;
25 25
26 26 .dropshadow(){
27 27 -moz-box-shadow: 0px 6px 10px -1px #adadad;
28 28 -webkit-box-shadow: 0px 6px 10px -1px #adadad;
29 29 box-shadow: 0px 6px 10px -1px #adadad;
30 30 }
31 31
32 32 // smoth height adaptation
33 33 .smoothheight(@t:1s) {
34 34 -webkit-transition-property: height;
35 35 -webkit-transition-duration: 1s;
36 36 -moz-transition-property: height;
37 37 -moz-transition-duration: 1s;
38 38 transition-property: height;
39 39 transition-duration: 1s;
40 40 }
41 41
42 42 @-moz-keyframes fadeOut {
43 43 from {opacity:1;}
44 44 to {opacity:0;}
45 45 }
46 46
47 47 @-webkit-keyframes fadeOut {
48 48 from {opacity:1;}
49 49 to {opacity:0;}
50 50 }
51 51
52 52 //@keyframes fadeOut {
53 53 // from {opacity:1;}
54 54 // to {opacity:0;}
55 55 //}
56 56
57 57 @-moz-keyframes fadeIn {
58 58 from {opacity:0;}
59 59 to {opacity:1;}
60 60 }
61 61
62 62 @-webkit-keyframes fadeIn {
63 63 from {opacity:0;}
64 64 to {opacity:1;}
65 65 }
66 66
67 67 //@keyframes fadeIn {
68 68 // from {opacity:0;}
69 69 // to {opacity:1;}
70 70 //}
71 71
72 72 /*properties of tooltip after "expand"*/
73 73 .bigtooltip {
74 74 overflow: auto;
75 75 height: 200px;
76 76 .smoothheight();
77 77 }
78 78
79 79 /*properties of tooltip before "expand"*/
80 80 .smalltooltip{
81 81 .smoothheight();
82 82 text-overflow: ellipsis;
83 83 overflow: hidden;
84 84 height:80px;
85 85 }
86 86
87 87 .tooltipbuttons
88 88 {
89 89 position: absolute;
90 90 padding-right : 15px;
91 91 top : 0px;
92 92 right:0px;
93 93 }
94 94
95 95 .tooltiptext
96 {
96 {
97 97 /*avoid the button to overlap on some docstring*/
98 98 padding-right:30px
99 99 }
100 100
101 101 .ipython_tooltip {
102 102 max-width:700px;
103 103 /*fade-in animation when inserted*/
104 104 -webkit-animation: fadeOut 800ms;
105 105 -moz-animation: fadeOut 800ms;
106 106 animation: fadeOut 800ms;
107 107 -webkit-animation: fadeIn 800ms;
108 108 -moz-animation: fadeIn 800ms;
109 109 animation: fadeIn 800ms;
110 110 vertical-align: middle;
111 111 background-color: @cell_background;
112
112
113 113 overflow : visible;
114 114 border: @border_color @borderwidth solid;
115 115 outline: none;
116 116 padding: 3px;
117 117 margin: 0px;
118 118 padding-left:7px;
119 119 font-family: monospace;
120 120 min-height:50px;
121 121 position: absolute;
122 122
123 123 .dropshadow;
124 124 .corner-all;
125 125
126 126 a {
127 127 float:right;
128 128 }
129 129
130 130 }
131 131
132 132
133 133 .pretooltiparrow {
134 134 left: 0px;
135 135 margin: 0px;
136 136 top: -16px;
137 137 width: 40px;
138 138 height: 16px;
139 139 overflow: hidden;
140 140 position: absolute;
141 141
142 142 }
143 143
144 144 .pretooltiparrow:before {
145 145 background-color : @cell_background;
146 border : @borderwidth @border_color solid;
146 border : @borderwidth @border_color solid;
147 147 z-index:11;
148 148 content: "";
149 149 position: absolute;
150 150 left: 15px;
151 151 top: 10px;
152 152 width: 25px;
153 153 height: 25px;
154 154 @theta : 45deg;
155 155 -webkit-transform: rotate(@theta);
156 156 -moz-transform: rotate(@theta);
157 157 -ms-transform: rotate(@theta);
158 158 -o-transform: rotate(@theta);
159 159 }
@@ -1,17 +1,17 b''
1 1 @corner_radius: 3px;
2 2 @notebook_background : white;
3 3 @cell_selected_background: darken(@notebook_background, 2%);
4 4 @cell_background: darken(@notebook_background, 3.2%);
5 5 @border_color: darken(@cell_selected_background, 10%);
6 6 @borderwidth : 1px;
7 7 @fontBaseColor : black;
8 8
9 9
10 10
11 11
12 12
13 // utilities mixins
13 // utilities mixins
14 14
15 15 .corner-all {
16 16 border-radius:@corner_radius;
17 17 }
General Comments 0
You need to be logged in to leave comments. Login now