Annotation of kupu/plone/html2captioned.py, revision 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>