reportlab/platypus: add two way <a> tag
authorrgbecker
Mon, 29 Jan 2007 13:02:38 +0000
changeset 2744 9472eedb9702
parent 2742 8edd54153201
child 2745 0b44535fa1a5
reportlab/platypus: add two way <a> tag
reportlab/platypus/paragraph.py
reportlab/platypus/paraparser.py
reportlab/test/test_platypus_paragraphs.py
--- a/reportlab/platypus/paragraph.py	Fri Jan 26 12:46:22 2007 +0000
+++ b/reportlab/platypus/paragraph.py	Mon Jan 29 13:02:38 2007 +0000
@@ -109,10 +109,15 @@
     nSpaces = 0
     for f in words:
         if hasattr(f,'cbDefn'):
-            func = getattr(tx._canvas,f.cbDefn.name,None)
-            if not func:
-                raise AttributeError, "Missing %s callback attribute '%s'" % (f.cbDefn.kind,f.cbDefn.name)
-            func(tx._canvas,f.cbDefn.kind,f.cbDefn.label)
+            name = f.cbDefn.name
+            kind = f.cbDefn.kind
+            if kind=='anchor':
+                tx._canvas.bookmarkHorizontal(name,cur_x,tx._y+tx._leading)
+            else:
+                func = getattr(tx._canvas,name,None)
+                if not func:
+                    raise AttributeError, "Missing %s callback attribute '%s'" % (kind,name)
+                func(tx._canvas,kind,f.cbDefn.label)
             if f is words[-1]: tx._textOut('',1)
         else:
             cur_x_s = cur_x + nSpaces*ws
@@ -410,6 +415,9 @@
         if kind=='GoToR': link = parts[1]
         tx._canvas.linkURL(link, rect, relative=1, kind=kind)
     else:
+        if link[0]=='#':
+            link = link[1:]
+            scheme=''
         tx._canvas.linkRect("", scheme!='document' and link or parts[1], rect, relative=1)
 
 def _do_link_line(i, t_off, ws, tx):
--- a/reportlab/platypus/paraparser.py	Fri Jan 26 12:46:22 2007 +0000
+++ b/reportlab/platypus/paraparser.py	Mon Jan 29 13:02:38 2007 +0000
@@ -120,6 +120,15 @@
                 'target': ('link', None),
                 'href': ('link', None),
                 }
+_anchorAttrMap = {'fontSize': ('fontSize', _num),
+                'fontName': ('fontName', None),
+                'name': ('name', None),
+                'fg':   ('textColor', toColor),
+                'color':('textColor', toColor),
+                'backcolor':('backColor',toColor),
+                'bgcolor':('backColor',toColor),
+                'href': ('href', None),
+                }
 
 def _addAttributeNames(m):
     K = m.keys()
@@ -326,7 +335,14 @@
 #               fg/textColor/color=color
 #               backcolor/backColor/bgcolor=color
 #               dest/destination/target/href/link=target
-#       <a> alias for link
+#       <a>anchor text</link>
+#           attributes of anchors 
+#               fontSize=num
+#               fontName=name
+#               fg/textColor/color=color
+#               backcolor/backColor/bgcolor=color
+#               href=href
+#       <a name="anchorpoint"/>
 #       <unichar name="unicode character name"/>
 #       <unichar value="unicode code point"/>
 #       <greek> - </greek>
@@ -407,8 +423,34 @@
         del self._stack[-1]
         assert frag.link!=None
 
-    start_a = start_link
-    end_a = end_link
+    #### anchor
+    def start_a(self, attributes):
+        A = self.getAttributes(attributes,_anchorAttrMap)
+        if A.get('name',None):
+            if len(A)>1:
+                self._syntax_error('<a name="..."/> anchor variant only allows name attribute')
+                A = dict(name=A['name'])
+            A['_selfClosingTag'] = 'anchor'
+        elif not A.get('href',None):
+            self._syntax_error('<a> tag must have name or href attribute')
+        else:
+            A['link'] = A.pop('href')   #convert to our link form
+        self._push(**A)
+
+    def end_a(self):
+        frag = self._stack[-1]
+        sct = getattr(frag,'_selfClosingTag','')
+        if sct:
+            assert sct=='anchor' and frag.name,'Parser failure in <a/>'
+            defn = frag.cbDefn = ABag()
+            defn.label = defn.kind = 'anchor'
+            defn.name = frag.name
+            del frag.name, frag._selfClosingTag
+            self.handle_data('')
+            self._pop()
+        else:
+            del self._stack[-1]
+            assert frag.link!=None
 
     #### super script
     def start_super( self, attributes ):
--- a/reportlab/test/test_platypus_paragraphs.py	Fri Jan 26 12:46:22 2007 +0000
+++ b/reportlab/test/test_platypus_paragraphs.py	Mon Jan 29 13:02:38 2007 +0000
@@ -10,7 +10,7 @@
 from types import StringType, ListType
 
 from reportlab.test import unittest
-from reportlab.test.utils import makeSuiteForClasses, outputfile, printLocation, outputfile
+from reportlab.test.utils import makeSuiteForClasses, outputfile, printLocation
 
 from reportlab.pdfbase.pdfmetrics import stringWidth
 from reportlab.platypus.paraparser import ParaParser
@@ -250,6 +250,8 @@
 phonemic and morphological analysis.''']
         story =[]
         a = story.append
+        a(Paragraph("This should %lt;a href=\"#theEnd\" color=\"blue\"&gt;<a href=\"#theEnd\" color=\"blue\">jump</a>&lt;/a&gt; jump to the end!",style=normal))
+        a(Paragraph("This should %lt;a href=\"#thePenultimate\" color=\"blue\"&gt;<a href=\"#thePenultimate\" color=\"blue\">jump</a>&lt;/a&gt; jump to the penultimate page!",style=normal))
         for mode in (0,1):
             text0 = texts[0]
             text1 = texts[1]
@@ -259,11 +261,14 @@
             for t in ('u','strike'):
                 for n in xrange(6):
                     for s in (normal,normal_center,normal_right,normal_just,normal_indent, normal_indent_lv_2):
+                        if n==4 and s==normal_center and t=='strike':
+                            a(Paragraph("The second jump at the beginning should come here &lt;a name=\"thePenultimate\"/&gt;<a name=\"thePenultimate\"/>!",style=normal))
                         a(Paragraph('n=%d style=%s tag=%s'%(n,s.name,t),style=normal_sp))
                         a(Paragraph('%s<%s>%s</%s>. %s <%s>%s</%s>. %s' % (
                         (s==normal_indent_lv_2 and '<seq id="document" inc="no"/>.<seq id="document_lv_2"/>' or ''),
                         t,' '.join((n+1)*['A']),t,text0,t,' '.join((n+1)*['A']),t,text1),
                         style=s))
+        a(Paragraph("The jump at the beginning should come here &lt;a name=\"theEnd\"/&gt;<a name=\"theEnd\"/>!",style=normal))
         doc = MyDocTemplate(outputfile('test_platypus_paragraphs_ul.pdf'))
         doc.build(story)