Files
cms-SiteForge/app/preview_rewrite.py
浅念 8cea7dee20 chore: baseline V8.10.0-dev.1 with v8_workflows type-mapping fix and trade-pro spec
- SiteForge Enterprise V8.10.0-dev.1 upstream source (210 tests)
- Fix: v8_workflows._mapped_input now reads both 类型/分类 columns so WXR
  imports keep post/product types instead of collapsing to page
- Docs: trade-pro theme port spec (R3) and implementation plan

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-22 16:49:25 +08:00

45 lines
1.8 KiB
Python

"""Rewrite root-relative links only in the HTTP preview response.
The published ZIP / immutable build files are never modified. Source element
markup is preserved so that e.g. canonical links and SEO headers are not
rewritten or reformatted by an HTML serializer.
"""
import re
from html.parser import HTMLParser
_ATTR = re.compile(r'''(?P<name>\b(?:href|src|action|poster))(?P<eq>\s*=\s*)(?P<q>["'])(?P<value>.*?)(?P=q)''', re.I | re.S)
class _PreviewHTMLParser(HTMLParser):
def __init__(self, prefix):
super().__init__(convert_charrefs=False)
self.prefix=prefix
self.out=[]
def _start(self):
raw=self.get_starttag_text()
def replace(match):
url=match.group('value')
if url.startswith('/') and not url.startswith('//') and not url.startswith(self.prefix):
url=self.prefix + url.lstrip('/')
return match.group('name')+match.group('eq')+match.group('q')+url+match.group('q')
self.out.append(_ATTR.sub(replace,raw))
def handle_starttag(self,tag,attrs): self._start()
def handle_startendtag(self,tag,attrs): self._start()
def handle_endtag(self,tag): self.out.append(f'</{tag}>')
def handle_data(self,data): self.out.append(data)
def handle_comment(self,data): self.out.append(f'<!--{data}-->')
def handle_decl(self,decl): self.out.append(f'<!{decl}>')
def handle_entityref(self,name): self.out.append(f'&{name};')
def handle_charref(self,name): self.out.append(f'&#{name};')
def handle_pi(self,data): self.out.append(f'<?{data}>')
def unknown_decl(self,data): self.out.append(f'<![{data}]>')
def rewrite_preview_html(document: str, site_id: str, build_id: str) -> str:
prefix=f'/preview/{site_id}/{build_id}/'
parser=_PreviewHTMLParser(prefix)
parser.feed(document)
parser.close()
return ''.join(parser.out)