forked from jupyterlab/jupyterlab-module-federation
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy paththemes_handler.py
86 lines (66 loc) · 2.99 KB
/
themes_handler.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
"""Tornado handlers for dynamic theme loading."""
# Copyright (c) Jupyter Development Team.
# Distributed under the terms of the Modified BSD License.
from glob import glob
from os import path as osp
import os
import re
from urllib.parse import urlparse
from jupyterlab_server.server import FileFindHandler, url_path_join as ujoin
class ThemesHandler(FileFindHandler):
"""A file handler that mangles local urls in CSS files."""
def initialize(self, path, default_filename=None,
no_cache_paths=None, themes_url=None, labextensions_path=None):
# Get all of the available theme paths in order
labextensions_path = labextensions_path or []
ext_paths = []
for ext_dir in labextensions_path:
theme_pattern = ext_dir + '/**/themes'
ext_paths.extend([path for path in glob(theme_pattern, recursive=True)])
# Add the core theme path last
if not isinstance(path, list):
path = [path]
path = ext_paths + path
FileFindHandler.initialize(self, path,
default_filename=default_filename,
no_cache_paths=no_cache_paths)
self.themes_url = themes_url
def get_content(self, abspath, start=None, end=None):
"""Retrieve the content of the requested resource which is located
at the given absolute path.
This method should either return a byte string or an iterator
of byte strings.
"""
base, ext = osp.splitext(abspath)
if ext != '.css':
return FileFindHandler.get_content(abspath, start, end)
return self._get_css()
def get_content_size(self):
"""Retrieve the total size of the resource at the given path."""
base, ext = osp.splitext(self.absolute_path)
if ext != '.css':
return FileFindHandler.get_content_size(self)
else:
return len(self._get_css())
def _get_css(self):
"""Get the mangled css file contents."""
with open(self.absolute_path, 'rb') as fid:
data = fid.read().decode('utf-8')
basedir = osp.dirname(self.path).replace(os.sep, '/')
basepath = ujoin(self.themes_url, basedir)
# Replace local paths with mangled paths.
# We only match strings that are local urls,
# e.g. `url('../foo.css')`, `url('images/foo.png')`
pattern = (r"url\('(.*)'\)|"
r'url\("(.*)"\)')
def replacer(m):
"""Replace the matched relative url with the mangled url."""
group = m.group()
# Get the part that matched
part = [g for g in m.groups() if g][0]
# Ignore urls that start with `/` or have a protocol like `http`.
parsed = urlparse(part)
if part.startswith('/') or parsed.scheme:
return group
return group.replace(part, ujoin(basepath, part))
return re.sub(pattern, replacer, data).encode('utf-8')