Skip to content

Commit 77f5b92

Browse files
committed
Enhance plugin to support HTML and CSS path rewriting.
1 parent f159a1c commit 77f5b92

3 files changed

Lines changed: 118 additions & 38 deletions

File tree

mkdocs_webcontext_plugin/plugin.py

Lines changed: 59 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -19,18 +19,30 @@ class Webcontext(BasePlugin):
1919
config_scheme = (
2020
('context', config_options.Type(str, default='/')),
2121
)
22-
23-
md_link = re.compile(r'''(\[[^]]*]\()(/[^)]*)(\))|(\[[^]]*]:\s)(/[^\n\r)]*)''', re.DOTALL | re.UNICODE)
22+
md_link = re.compile(r'''(?P<full>(?P<prefix>!?\[[^\]]*\]\()(?P<url>/[^)]+)(?P<suffix>\)))|(?P<refprefix>\[[^\]]+\]:\s)(?P<refurl>/[^\s]+)''',re.DOTALL | re.UNICODE)
23+
html_src = re.compile(r'''(<img[^>]+src=["'])(/[^"'>]+)(["'])''', re.IGNORECASE)
24+
css_url_pattern = re.compile(r'''url\((["'])(/[^"')]+)(["'])\)''', re.IGNORECASE)
2425

2526
def __init__(self):
2627
self.enabled = True
2728
self.total_time = 0
2829

2930
def on_page_markdown(self, markdown, page, config, files):
3031
context = self.config['context']
31-
new_md = self._absolute_to_webcontext(markdown, context)
32-
return new_md
33-
32+
updated_md = self._rewrite_html_src(markdown, context)
33+
updated_md = self._absolute_to_webcontext(updated_md, context)
34+
return updated_md
35+
36+
def _rewrite_html_src(self, html: str, context: str):
37+
def replace_src(match):
38+
prefix, path, suffix = match.groups()
39+
new_path = '/' + context.rstrip('/') + '/' + path.lstrip('/')
40+
new_path = new_path.replace("\\", "/")
41+
LOGGER.debug('webcontext: replace HTML src %s with %s', path, new_path)
42+
return f"{prefix}{new_path}{suffix}"
43+
44+
return re.sub(self.html_src, replace_src, html)
45+
3446
def _absolute_to_webcontext(self, markdown, context: str):
3547
LOGGER.debug('webcontext: using defined context = %s', context)
3648

@@ -42,23 +54,49 @@ def _check_link(link: str, context: str):
4254

4355
return link
4456

45-
def _to_webcontext(context:str):
46-
def re_write_link(matchobj):
47-
group1 = matchobj.group(1) # front stuff
48-
group2 = matchobj.group(2) # the actual link
49-
group3 = matchobj.group(3) # closing tag
57+
def _to_webcontext(context: str):
58+
def re_write_link(match):
59+
if match.group('full'):
60+
prefix = match.group('prefix')
61+
url = match.group('url')
62+
suffix = match.group('suffix')
63+
new_url = _check_link(url, context)
64+
return f"{prefix}{new_url}{suffix}"
65+
elif match.group('refprefix') and match.group('refurl'):
66+
refprefix = match.group('refprefix')
67+
refurl = match.group('refurl')
68+
new_url = _check_link(refurl, context)
69+
return f"{refprefix}{new_url}"
70+
return match.group(0)
71+
return re_write_link
5072

51-
if group1 and group2 and group3:
52-
link = _check_link(group2, context)
53-
return "{}{}{}".format(group1, link, group3)
73+
file_data = re.sub(self.md_link, _to_webcontext(context), markdown)
74+
return file_data
5475

55-
group4 = matchobj.group(4) # front stuff
56-
group5 = matchobj.group(5) # the actual link
57-
if group4 and group5:
58-
link = _check_link(group5, context)
59-
return "{}{}".format(group4, link)
76+
def _process_css_file(self, file_path: Path, context: str):
77+
try:
78+
content = file_path.read_text(encoding="utf-8")
6079

61-
return re_write_link
80+
def replace_url(match):
81+
quote1, path, quote2 = match.groups()
82+
new_path = '/' + context.strip('/') + '/' + path.lstrip('/')
83+
new_path = new_path.replace("\\", "/")
84+
LOGGER.debug("webcontext: replace CSS url %s with %s", path, new_path)
85+
return f"url({quote1}{new_path}{quote2})"
6286

63-
file_data = re.sub(self.md_link, _to_webcontext(context), markdown)
64-
return file_data
87+
updated = re.sub(self.css_url_pattern, replace_url, content)
88+
89+
if content != updated:
90+
file_path.write_text(updated, encoding="utf-8")
91+
LOGGER.info("webcontext: updated CSS file: %s", file_path)
92+
93+
except Exception as e:
94+
LOGGER.error("webcontext: failed to process %s: %s", file_path, e)
95+
96+
97+
def on_post_build(self, config):
98+
context = self.config['context']
99+
site_dir = Path(config['site_dir'])
100+
101+
for css_file in site_dir.rglob("*.css"):
102+
self._process_css_file(css_file, context)

readme.md

Lines changed: 58 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,75 @@
1-
# Webcontext link converter plugin for mkdocs
1+
# Webcontext link converter plugin for MkDocs
22

3-
MkDocs allows absulute paths assuming that the site is deployed to the root of the hosted website like "http://localhost/". When using the following absolute path "/assets/image1.jpg" it is actually using "http://localhost/assets/image1.jpg" which is correct if the MkDocs is deployed to the site root.
3+
MkDocs assumes absolute paths start from the root of the hosted website, like `http://localhost/`. For example, an absolute path like `/assets/image1.jpg` becomes `http://localhost/assets/image1.jpg`, which is correct if MkDocs is hosted at the root.
44

5-
When the server root is not the same as the MkDocs root, the webcontext plugin can be used to define a webcontext to use instead of the defined root. The webcontext path which can be anyting like "/projectname/documents" is used where "/" is defined.
5+
When the server root is not the same as the MkDocs root, this plugin lets you define a `webcontext` to prepend to these absolute paths. The `webcontext` path (e.g., `/projectname/documents`) replaces the default root (`/`).
66

7-
Some examples of site urls before and after using the webcontext plugin:
8-
Site Url | Context | Image before | Image after
9-
---------|----------|--------------|------------
10-
http://example.com/ | / | /images/img1.jpg | /images/img1.jpg
11-
http://example.com/foo | /foo | /images/img1.jpg | /foo/images/img1.jpg
12-
http://example.com/foo/bar | /foo/bar | /images/img1.jpg | /foo/bar/images/img1.jpg
13-
http://127.0.0.1:8000 | / | /images/img1.jpg | /images/img1.jpg
14-
http://127.0.0.1:8000/foo | /foo | /images/img1.jpg | /foo/images/img1.jpg
7+
## Features
158

9+
* Converts absolute image paths in Markdown to be relative to a specified web context.
10+
* Converts image `src` attributes in HTML embedded in Markdown.
11+
* Converts `url("/path")` references inside CSS files.
12+
* Supports Markdown reference-style image and link syntax.
13+
* Debug and info logging of replacements.
1614

17-
## Quick start
15+
### Examples
1816

19-
1. Install the module using pip: `pip install mkdocs-webcontext-plugin`
20-
1. Or for the new school kids: `poetry add mkdocs-webcontext-plugin`
17+
| Site URL | Context | Image Path Before | Image Path After |
18+
| -------------------------------------------------------- | -------- | ----------------- | ------------------------ |
19+
| [http://example.com/](http://example.com/) | / | /images/img1.jpg | /images/img1.jpg |
20+
| [http://example.com/foo](http://example.com/foo) | /foo | /images/img1.jpg | /foo/images/img1.jpg |
21+
| [http://example.com/foo/bar](http://example.com/foo/bar) | /foo/bar | /images/img1.jpg | /foo/bar/images/img1.jpg |
22+
| [http://127.0.0.1:8000](http://127.0.0.1:8000) | / | /images/img1.jpg | /images/img1.jpg |
23+
| [http://127.0.0.1:8000/foo](http://127.0.0.1:8000/foo) | /foo | /images/img1.jpg | /foo/images/img1.jpg |
2124

22-
2. In your project, add a plugin configuration to `mkdocs.yml`:
25+
## Quick Start
26+
27+
1. Install the plugin:
28+
29+
```bash
30+
pip install mkdocs-webcontext-plugin
31+
```
32+
33+
Or using Poetry:
34+
35+
```bash
36+
poetry add mkdocs-webcontext-plugin
37+
```
38+
39+
2. Enable the plugin in your `mkdocs.yml`:
2340

2441
```yaml
2542
plugins:
2643
- webcontext:
2744
context: foo/bar
2845
```
2946
30-
Special thanks to the following repositories for guidance:
47+
## Supported Link Types
48+
49+
The plugin modifies the following path formats:
50+
51+
* Markdown links: `[title](/path/image.png)`
52+
* Markdown reference links:
53+
54+
```markdown
55+
[logo]: /assets/logo.png
56+
```
57+
* HTML image tags: `<img src="/assets/img.png">`
58+
* CSS `url()` paths: `url("/assets/bg.jpg")`
59+
60+
These paths will be rewritten to start with your defined `context`.
61+
62+
## CSS Support
63+
64+
After your site is built, the plugin will scan all `.css` files in the output directory and rewrite any `url("/...")` references to use the defined `context`.
65+
66+
## Logging
67+
68+
Rewrites are logged at the `DEBUG` level. Updated CSS files are logged at the `INFO` level.
69+
70+
## Special Thanks
71+
72+
This plugin was inspired by and built with guidance from:
3173

3274
* [byrnereese/mkdocs-plugin-template](https://github.com/byrnereese/mkdocs-plugin-template)
3375
* [sander76/mkdocs-abs-rel-plugin](https://github.com/sander76/mkdocs-abs-rel-plugin)

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
setup(
1010
name="mkdocs-webcontext-plugin",
11-
version="0.1.0",
11+
version="0.1.1",
1212
packages=["mkdocs_webcontext_plugin"],
1313
url="https://github.com/darrelk/mkdocs-webcontext-plugin",
1414
license="MIT",

0 commit comments

Comments
 (0)