From e693ce1cbc5777ab85d852122d5c28f63025ec5a Mon Sep 17 00:00:00 2001 From: Mike Naberezny Date: Sun, 5 Apr 2009 04:06:47 +0000 Subject: Added a new anchor keyword argument to model_url(). --- CHANGES.txt | 8 ++++++++ repoze/bfg/tests/test_url.py | 42 ++++++++++++++++++++++++++++++++++++++++++ repoze/bfg/url.py | 29 ++++++++++++++++++++++++++--- 3 files changed, 76 insertions(+), 3 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 5c556eaec..8763ce038 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -30,6 +30,14 @@ Features - Make it possible to have ``testing.DummyTemplateRenderer`` return some nondefault string representation. +- Added a new ``anchor`` keyword argument to ``model_url``. If + ``anchor`` is present, its string representation will be used + as a named anchor in the generated URL (e.g. if ``anchor`` is + passed as ``foo`` and the model URL is + ``http://example.com/model/url``, the generated URL will be + ``http://example.com/model/url#foo``). + + 0.6.9 (2009-02-16) ================== diff --git a/repoze/bfg/tests/test_url.py b/repoze/bfg/tests/test_url.py index b9733f802..fc89e6c0d 100644 --- a/repoze/bfg/tests/test_url.py +++ b/repoze/bfg/tests/test_url.py @@ -77,6 +77,48 @@ class ModelURLTests(unittest.TestCase): self.assertEqual(result, 'http://example.com/context/a?a=hi+there&b=La+Pe%C3%B1a') + def test_anchor_is_after_root_when_no_elements(self): + self._registerContextURL() + context = DummyContext() + request = DummyRequest() + result = self._callFUT(context, request, anchor='a') + self.assertEqual(result, + 'http://example.com/context/#a') + + def test_anchor_is_after_elements_when_no_qs(self): + self._registerContextURL() + context = DummyContext() + request = DummyRequest() + result = self._callFUT(context, request, 'a', anchor='b') + self.assertEqual(result, + 'http://example.com/context/a#b') + + def test_anchor_is_after_qs_when_qs_is_present(self): + self._registerContextURL() + context = DummyContext() + request = DummyRequest() + result = self._callFUT(context, request, 'a', + query={'b':'c'}, anchor='d') + self.assertEqual(result, + 'http://example.com/context/a?b=c#d') + + def test_anchor_is_encoded_utf8_if_unicode(self): + self._registerContextURL() + context = DummyContext() + request = DummyRequest() + uc = unicode('La Pe\xc3\xb1a', 'utf-8') + result = self._callFUT(context, request, anchor=uc) + self.assertEqual(result, + 'http://example.com/context/#La Pe\xc3\xb1a') + + def test_anchor_is_not_urlencoded(self): + self._registerContextURL() + context = DummyContext() + request = DummyRequest() + result = self._callFUT(context, request, anchor=' /#') + self.assertEqual(result, + 'http://example.com/context/# /#') + def test_no_IContextURL_registered(self): # falls back to TraversalContextURL root = DummyContext() diff --git a/repoze/bfg/url.py b/repoze/bfg/url.py index 802dfca89..528d83ae9 100644 --- a/repoze/bfg/url.py +++ b/repoze/bfg/url.py @@ -55,6 +55,22 @@ def model_url(model, request, *elements, **kw): ``True``. This means that sequences can be passed as values, and a k=v pair will be placed into the query string for each value. + + If a keyword argument ``anchor`` is present, its string + representation will be used as a named anchor in the generated URL + (e.g. if ``anchor`` is passed as ``foo`` and the model URL is + ``http://example.com/model/url``, the resulting generated URL will + be ``http://example.com/model/url#foo``). + + .. note:: If ``anchor`` is passed as a string, it should be UTF-8 + encoded. If ``anchor`` is passed as a Unicode object, it + will be converted to UTF-8 before being appended to the + URL. The anchor value is not quoted in any way before + being appended to the generated URL. + + If both ``anchor`` and ``query`` are specified, the anchor element + will always follow the query element, + e.g. ``http://example.com?foo=1#bar``. """ context_url = queryMultiAdapter((model, request), IContextURL) @@ -63,17 +79,24 @@ def model_url(model, request, *elements, **kw): context_url = TraversalContextURL(model, request) model_url = context_url() + qs = '' + anchor = '' + if 'query' in kw: qs = '?' + urlencode(kw['query'], doseq=True) - else: - qs = '' + + if 'anchor' in kw: + anchor = kw['anchor'] + if isinstance(anchor, unicode): + anchor = anchor.encode('utf-8') + anchor = '#' + anchor if elements: suffix = '/'.join([quote_path_segment(s) for s in elements]) else: suffix = '' - return model_url + suffix + qs + return model_url + suffix + qs + anchor def urlencode(query, doseq=False): """ -- cgit v1.2.3