Add the ImageMap parser, version 1.2.
authorMatthijs Kooijman <matthijs@stdio.flexvps.nl>
Sat, 25 Apr 2009 11:42:12 +0000 (13:42 +0200)
committerMatthijs Kooijman <matthijs@stdio.flexvps.nl>
Sat, 25 Apr 2009 11:42:12 +0000 (13:42 +0200)
plugin/parser/ImageMap.py [new file with mode: 0644]

diff --git a/plugin/parser/ImageMap.py b/plugin/parser/ImageMap.py
new file mode 100644 (file)
index 0000000..c4c33a8
--- /dev/null
@@ -0,0 +1,198 @@
+# -*- coding: iso-8859-1 -*-
+"""
+    MoinMoin - ImageMap Parser
+
+    This parser is used to create clickable image maps.
+    
+    Syntax:
+    
+    {{{#!ImageMap
+    picsrc[;width=".."][;height=".."][;alt=".."][;title=".."] 
+    link_area1;shape="rect|circle|poly";coords="..";alt=".."[;title=".."]
+    link_area2;shape="rect|circle|poly";coords="..";alt=".."[;title=".."]
+    }}}
+
+    For a detailed explanation of the syntax see:
+    http://moinmoin.wikiwikiweb.de/ParserMarket/ImageMap
+
+    Please note: Image maps are not accessible by blind people. Do also have a
+    look at the best-practise-examples for using image maps
+    on http://moinmoin.wikiwikiweb.de/ParserMarket/ImageMap.
+    
+    Example:
+
+    {{{#!ImageMap
+    picture.jpg;width="345";height="312";alt="Clickable Organizational Chart" 
+    FrontPage;shape="rect";coords="11,10,59,29";alt="Area1"
+    http://www.xyz.com/;shape="circle";coords="42,36,96";alt="Area2"
+    FrontPage/SubPage;shape="poly";coords="48,311,105,248,96,210";alt="Area3"
+    Another Site in This Wiki;shape="rect";coords="88,10,59,29";alt="Area4"
+    InterWiki:RemotePage;shape="rect";coords="181,120,59,29";alt="Area5"
+    }}}
+
+    ImageMap Parser is partly based on ImageLink Macro
+    ImageLink Macro
+    @copyright: 2001 by Jeff Kunce,
+                2004 by Marcin Zalewski,
+                2004-2006 by Reimar Bauer,
+                2006 by Thomas Waldmann
+    @license: GNU GPL, see COPYING for details.
+
+    ImageMap Parser
+    @copyright: 2006,2007 by Oliver Siemoneit
+    @license: GNU GPL, see COPYING for details.
+
+    Changes:
+
+    Version 1.1
+    * Made code PEP8 compatible.
+    * Parameter checking and stripping added to prevent inserting of malicious
+      code in html page via parser call.
+
+    Version 1.2
+    * Fixed ouput abstraction violations: on other formatters than html-formatter
+      just the specified image is output via formatter.image and map information
+      dropped.
+    * In case of missing alt texts: "alt" ist set to alt="" (for the whole map)
+      and to alt="area_url" (for the different clickable areas). 
+    * Now also "title" supported to generate tooltips for the map areas.
+    * Interwiki links can also be specified in "wiki:MoinMoin/Page" syntax now.
+    
+"""
+
+import os, random
+from MoinMoin import wikiutil, config
+from MoinMoin.action import AttachFile
+
+
+def _is_URL(text):
+    return '://' in text
+
+def _is_InterWiki(text):
+    return ':' in text
+
+def _is_allowed_Para(para, allowed_paras):
+    found = False
+    for p in allowed_paras:
+        if para.startswith(p):
+            found = True
+    return found
+
+def _strip_Para(para):
+    _para = wikiutil.escape(para)
+    if para.count('"') < 2:
+        return _para
+    shortend_para = _para[0:_para.find('"')+1]
+    cut_para = _para[_para.find('"')+1:len(_para)]
+    shortend_para += cut_para[0:cut_para.find('"')+1]
+    return shortend_para
+
+
+class Parser:
+
+    def __init__(self, raw, request, **kw):
+        self.raw = raw
+        self.request = request
+
+    def format(self, formatter):
+        request = self.request
+        _ = request.getText
+        row = self.raw.split('\n')
+               
+        # Produce <img ...> html-code stuff
+        paras = row[0].split(';')
+        image = wikiutil.escape(paras[0])
+        mapname = '%s_%s' % ([image, image[:15]][(len(image) > 14)], str(random.randint(1, 999999)))
+        
+        if _is_URL(image):
+            imgurl = image
+        elif _is_InterWiki(image):
+            if image.startswith('wiki:'):
+                image = image[5:]
+            wikitag, wikiurl, wikitail, err = wikiutil.resolve_wiki(request, image)
+            imgurl = wikiutil.join_wiki(wikiurl, wikitail)
+        else:
+            pagename, attname = AttachFile.absoluteName(image, formatter.page.page_name)
+            imgurl = AttachFile.getAttachUrl(pagename, attname, request)
+            attachment_fname = AttachFile.getFilename(request, pagename, attname)
+
+            if not os.path.exists(attachment_fname):
+                linktext = _('Upload new attachment "%(filename)s"')
+                output = wikiutil.link_tag(request,
+                                         ('%s?action=AttachFile&rename=%s' % (
+                                             wikiutil.quoteWikinameURL(pagename),
+                                             wikiutil.url_quote_plus(attname))),
+                                          text=linktext % {'filename': attname},
+                                          formatter=formatter)
+                request.write(output)
+                return
+        
+        html = '''
+<img src="%s"''' % imgurl
+        paras.pop(0)
+
+        kw = {}
+        kw['src'] = imgurl
+        for p in paras:
+            # Prevent attacks like: pic.png;height="10" onmouseover="ExecuteBadCode()";alt="..";
+            # and: pic.png;height="10&#34; onmouseover=&#34;ExecuteBadCode()";alt="..";
+            # and: pic.png;height=&#34;10&#34; onmouseover="ExecuteBadCode()";alt="..";
+            p = _strip_Para(p)
+            if _is_allowed_Para(p, ['width="', 'height="', 'alt="', 'title="']): 
+                html += ' %s' % p
+                # Prepare dict for formatter.image if formatter.rawHTML call fails
+                key, value = p.split('=', 1)
+                kw[str(key.lower())] = value.strip('"')
+
+        # If there is no alt provided, create one
+        if not 'alt' in kw:
+            kw['alt'] = image
+            html += ' alt=""'
+
+        html += ' usemap="#%s"> ' % mapname
+        row.pop(0)
+        
+        # Produce <map ..> html-code stuff
+        html += '''
+<map name="%s">''' % mapname
+
+        for p in row:
+            paras = p.split(';')
+            paras[0] = wikiutil.escape(paras[0])
+
+            if _is_URL(paras[0]):
+                area_url = paras[0]
+            elif _is_InterWiki(paras[0]):
+                if paras[0].startswith('wiki:'):
+                    paras[0] = paras[0][5:]
+                wikitag, wikiurl, wikitail, err = wikiutil.resolve_wiki(request, paras[0])
+                area_url = wikiutil.join_wiki(wikiurl, wikitail)
+            else:
+                area_url = wikiutil.quoteWikinameURL(paras[0])
+            paras.pop(0)
+            
+            html += '''
+    <area href="%s"''' % area_url
+
+            for i in paras:
+                # Prevent attacks like: FrontPage;shape="rect" onmouseover="ExecuteBadCode()";coords="..";
+                # and: FrontPage;shape="rect&#34; onmouseover=&#34;ExecuteBadCode()";coords="..";
+                # and: FrontPage;shape=&#34;rect&#34; onmouseover="ExecuteBadCode()";coords="..";
+                i = _strip_Para(i) 
+                if _is_allowed_Para(i, ['shape="', 'coords="', 'alt="', 'title="']): 
+                    html += ' %s' % i
+            # If there is no alt provided at all, set alt to area_url
+            if p.lower().find('alt="') == -1:
+                html += ' alt="%s"' % area_url
+
+            html += '>'
+
+        html += '''
+</map>
+'''
+        # If current formatter is a HTML formatter, output image map with formatter.rawHTML().
+        # Otherwise just output image with formatter.image()
+        try:
+            request.write(formatter.rawHTML(html))
+        except:
+            request.write(formatter.image(**kw))