Annotation of kupu/plone/html2captioned.py, revision 1.1.1.1
1.1 dwinter 1: # Portal transform for images with captions
2: #
3: # We want to be able to support captions in images.
4: # The easiest way to do this is to define a Portal Transform which is
5: # applied to the HTML body text on output.
6: #
7: # The transform finds all the embedded images, and replaces them with
8: # an appropriate chunk of HTML to include the caption.
9: #
10: from Products.CMFCore.utils import getToolByName
11: from Products.PortalTransforms.interfaces import itransform
12: from DocumentTemplate.DT_Util import html_quote
13: from DocumentTemplate.DT_Var import newline_to_br
14: import re
15:
16: __revision__ = '$Id$'
17:
18: # IMAGE_PATTERN matches an image tag on its own, or an image tag
19: # enclosed in a simple <p> or <div>. In the latter case we strip out
20: # the enclosing tag since we are going to insert our own.
21: PATIMG = '\\<img[^>]+class=[^=>]*captioned[^>]+\\>'
22: PATA = '(?:\\<a[^>]*\\>'+PATIMG+'\\</a\\>)' + '|' + PATIMG
23: PAT0 = '('+PATA+')'
24: PAT1 = '<(?:p|div)[^>]*>'+PAT0 + '</(?:p|div)>' + '|' + PAT0
25: IMAGE_PATTERN = re.compile(PAT1, re.IGNORECASE)
26:
27: # Regex to match stupid IE attributes. In IE generated HTML an
28: # attribute may not be enclosed by quotes if it doesn't contain
29: # certain punctuation.
30: ATTR_VALUE = '=(?:"?)(?P<%s>(?<=")[^"]*|[^ \/>]*)'
31: ATTR_CLASS = ATTR_VALUE % 'class'
32: ATTR_WIDTH = ATTR_VALUE % 'width'
33:
34: ATTR_PATTERN = re.compile('''
35: (?P<tag>\<
36: ( class%s
37: | src="resolveuid/(?P<src>([^/"#? ]*))
38: | width%s
39: | .
40: )*\>
41: )''' % (ATTR_CLASS, ATTR_WIDTH), re.VERBOSE)
42:
43: CLASS_PATTERN = re.compile('\s*class=("[^"]*captioned[^"]*"|[^" \/>]+)')
44: IMAGE_TEMPLATE = '''\
45: <div class="%(class)s" style="width:%(width)spx;">
46: <div style="width:%(width)spx;">
47: %(tag)s
48: </div>
49: <div class="image-caption">
50: %(caption)s
51: </div>
52: </div>
53: '''
54:
55: UID_PATTERN = re.compile('(?P<tag><(?:a|img) [^>]*(?:src|href)=")(?P<url>[^"]*resolveuid/(?P<uid>[^"#? ]*))')
56:
57: class HTMLToCaptioned:
58: """Transform which adds captions to images embedded in HTML"""
59: __implements__ = itransform
60: __name__ = "html_to_captioned"
61: inputs = ('text/html',)
62: output = "text/x-html-captioned"
63:
64: def __init__(self, name=None):
65: self.config_metadata = {
66: 'inputs' : ('list', 'Inputs', 'Input(s) MIME type. Change with care.'),
67: }
68: if name:
69: self.__name__ = name
70:
71: def name(self):
72: return self.__name__
73:
74: def __getattr__(self, attr):
75: if attr == 'inputs':
76: return self.config['inputs']
77: if attr == 'output':
78: return self.config['output']
79: raise AttributeError(attr)
80:
81: def convert(self, data, idata, filename=None, **kwargs):
82: """convert the data, store the result in idata and return that
83: optional argument filename may give the original file name of received data
84: additional arguments given to engine's convert, convertTo or __call__ are
85: passed back to the transform
86:
87: The object on which the translation was invoked is available as context
88: (default: None)
89: """
90: context = kwargs.get('context', None)
91: if context:
92: at_tool = context.archetype_tool
93:
94: if context and at_tool:
95: def replaceImage(match):
96: tag = match.group(1) or match.group(2)
97: attrs = ATTR_PATTERN.match(tag)
98: src = attrs.group('src')
99: klass = attrs.group('class')
100: width = attrs.group('width')
101: if src:
102: d = attrs.groupdict()
103: target = at_tool.reference_catalog.lookupObject(src)
104: if target:
105: d['caption'] = newline_to_br(target.Description())
106: d['tag'] = CLASS_PATTERN.sub('', d['tag'])
107: if not width:
108: d['width'] = target.getWidth()
109:
110: return IMAGE_TEMPLATE % d
111: return match.group(0) # No change
112:
113: html = IMAGE_PATTERN.sub(replaceImage, data)
114:
115: # Replace urls that use UIDs with human friendly urls.
116: def replaceUids(match):
117: tag = match.group('tag')
118: uid = match.group('uid')
119: target = at_tool.reference_catalog.lookupObject(uid)
120: if target:
121: return tag + target.absolute_url()
122: return match.group(0)
123:
124: html = UID_PATTERN.sub(replaceUids, html)
125:
126: idata.setData(html)
127: return idata
128:
129: # No context to use for replacements, so don't bother trying.
130: return data
131:
132: def register():
133: return HTMLToCaptioned()
134:
135: def initialize():
136: engine = getToolByName(portal, 'portal_transforms')
137: engine.registerTransform(register())
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>