# HG changeset patch # User Paul Boddie # Date 1534173007 -7200 # Node ID d5b2b71a486df9168f01264178bcd5356b758300 # Parent 3e6af8be4b676e1828dab82854effda3eaaad0a5 Improved link translation, handling the root page as a special case, employing resolved link targets instead of reusing target details in HTML links. This should fix certain kinds of links which behave rather differently in Moin, such as those employing the "." notation. diff -r 3e6af8be4b67 -r d5b2b71a486d moinformat/links/__init__.py --- a/moinformat/links/__init__.py Mon Aug 13 15:53:53 2018 +0200 +++ b/moinformat/links/__init__.py Mon Aug 13 17:10:07 2018 +0200 @@ -32,17 +32,17 @@ return linkers.get(name) -def make_linker(name, pagename, mapping=None): +def make_linker(name, pagename, mapping=None, parameters=None): """ Return a linking scheme handler with the given 'name' and using the given - 'pagename' and interwiki 'mapping'. + 'pagename', interwiki 'mapping' and 'parameters'. """ linker_cls = get_linker(name) if not linker_cls: return None - return linker_cls(pagename, mapping) + return linker_cls(pagename, mapping, parameters) # vim: tabstop=4 expandtab shiftwidth=4 diff -r 3e6af8be4b67 -r d5b2b71a486d moinformat/links/common.py --- a/moinformat/links/common.py Mon Aug 13 15:53:53 2018 +0200 +++ b/moinformat/links/common.py Mon Aug 13 17:10:07 2018 +0200 @@ -23,14 +23,64 @@ "Translate Moin links into other forms." - def __init__(self, pagename, mapping=None): + def __init__(self, pagename, mapping=None, parameters=None): """ - Initialise the linker with the 'pagename' and optional interwiki - 'mapping'. + Initialise the linker with the 'pagename', optional interwiki 'mapping' + and 'parameters'. """ self.pagename = pagename self.mapping = mapping or {} + self.parameters = parameters or {} + + self.root_pagename = self.parameters.get("root_pagename") or "FrontPage" + +def resolve(path, pagename, root_pagename): + + "Resolve 'path' relative to 'pagename'." + + # Omit the root pagename from the resolved path components. + + if pagename == root_pagename: + parts = [] + else: + parts = pagename.rstrip("/").split("/") + + t = path.split("/") + + first = True + + for p in t: + + # Handle replacement of the page with another. + + if p == ".": + parts = [] + + # Handle ascent in the page hierarchy. + + elif p == "..": + if parts: + parts.pop() + + # Any non-navigation element replaces the path at the start. + # Otherwise, the path is extended. + # Omit the root pagename from the resolved path components if it would + # appear at the start. + + elif p: + if first: + if p == root_pagename: + parts = [] + else: + parts = [p] + else: + if parts or p != root_pagename: + parts.append(p) + + first = False + + return "/".join(parts) # vim: tabstop=4 expandtab shiftwidth=4 diff -r 3e6af8be4b67 -r d5b2b71a486d moinformat/links/html.py --- a/moinformat/links/html.py Mon Aug 13 15:53:53 2018 +0200 +++ b/moinformat/links/html.py Mon Aug 13 17:10:07 2018 +0200 @@ -19,7 +19,7 @@ this program. If not, see . """ -from moinformat.links.common import Linker +from moinformat.links.common import Linker, resolve from urllib import quote, quote_plus from urlparse import urlparse @@ -33,7 +33,14 @@ "Return a relative link to the top level." - levels = self.pagename.count("/") + # The root page is at the top level already. + + if self.pagename == self.root_pagename: + return "" + + # Siblings of the root page are actually one level below. + + levels = self.pagename.count("/") + 1 return "/".join([".."] * levels) def is_url(self, target): @@ -65,13 +72,13 @@ # Sub-pages. Remove the leading slash for the label. - elif target.startswith("/"): - return self.translate_subpage(target), target.lstrip("/") + if target.startswith("/"): + return self.translate_pagename(target), target.lstrip("/") # Sibling (of ancestor) pages. if target.startswith("../"): - return self.translate_relative(target), None + return self.translate_pagename(target), None # Attachment or interwiki link. @@ -87,8 +94,30 @@ # Top-level pages. + return self.translate_pagename(target), None + + def translate_pagename(self, target): + + "Translate the pagename in 'target'." + + # Obtain the target pagename and the fragment. + # Split the pagename into path components. + + t = target.split("#", 1) + p = t[0].rstrip("/").split("/") + + # Determine the actual pagename referenced. + # Replace the root pagename if it appears. + + resolved = resolve(t[0], self.pagename, self.root_pagename) + + # Rewrite the target using a relative link to the top level and then the + # resolved pagename. + top_level = self.get_top_level() - return self.quote("%s%s" % (top_level and "%s/" % top_level or "", target)), None + t[0] = "%s%s" % (top_level and "%s/" % top_level or "", resolved) + + return self.quote("#".join(t)) def translate_qualified_link(self, target): @@ -132,18 +161,6 @@ return "%s%s" % (self.normalise(url), self.quote(target)) - def translate_relative(self, target): - - "Return a translation of the given relative 'target'." - - return self.quote(target) - - def translate_subpage(self, target): - - "Return a translation of the given subpage 'target'." - - return self.quote(".%s" % target) - # Path encoding. def quote(self, s):