¶ MoinMoin插件hacking

2010-07-30 15:00

1. 需求

GraphVizForMoin 插件部署到MoinMoin 中之后,很爽直!

参考: 在维基中使用 Graphviz~ 啄木鸟中的效果

可以说,解决了在维基中无法快速表达思维导图的问题:

  • 以往都是使用 FreeMind 绘制后截屏附件上来
  • 或是使用插件 ParserMarket/FreeMind - MoinMoin 将文件使用Flash 控件就地发布出来~中文一直是个问题

    但是,使用 Graphviz 的dot 图形脚本在维基中书写图谱一直以来残念的问题是无法输出可点击的有热区的导图!

1.1. Hacking

思路:
  • hacked MoinGraphViz 令其使用-Tcmapx -o **.mp命令,输出热区定义
  • hacked MoinMoin 相关脚本令输出到HTML 的图片认识可能的热区定义
fxied:
  • path/2/moin运行实例/data/plugin/parser/MoinGraphViz/main.py 是插件的主体
  • 很直白,快速就定位了具体代码进行了修订

diff:


Index: tasks/wiki.KUP/MoinMoin/parser/MoinGraphViz/main.py
===================================================================
--- tasks/wiki.KUP/MoinMoin/parser/MoinGraphViz/main.py (revision 16946)
+++ tasks/wiki.KUP/MoinMoin/parser/MoinGraphViz/main.py (revision 16975)
@@ -56,4 +56,5 @@
         p = request.formatter.page
         self.renderer = Renderer(tool, targetdir=p.getPagePath('attachments'), encoding=config.charset)
+        self.attapath = p.getPagePath('attachments')

     def format(self, formatter):
@@ -61,5 +62,10 @@
         ##w('<div style="border:3px ridge gray; padding:5px; width:95%; overflow:auto">')
         s = self.renderer.render(self.raw)
+        imgname = os.path.basename(s)
+        #s = wiki2html(self.request, '{{attachment:%s}}' % os.path.basename(s))
         s = wiki2html(self.request, '{{attachment:%s}}' % os.path.basename(s))
+        #   100728 Zoom.Quiet fixed for include URL hotarea map define
+        pfImgMap = "%s/%s.map"%(self.attapath,imgname)
+        s += fread(pfImgMap)
         print '[TRACE] attachment URL:', s
         w(s)
@@ -182,5 +193,7 @@

 def renderGraphImage(tool, format, imagefilename, dotfilename):
-    cmd = '%(tool)s -T%(format)s -o"%(imagefilename)s" "%(dotfilename)s"' % locals()
+    #100728 Zoom.Quiet fixed for export URL hotarea map export
+    cmd = '%(tool)s -T%(format)s -o"%(imagefilename)s" -Tcmapx -o "%(imagefilename)s.map" "%(dotfilename)s"' % locals()
+    #cmd = '%(tool)s -T%(format)s -o"%(imagefilename)s" "%(dotfilename)s"' % locals()
     print '[TRACE] executing:', cmd
     os.system(cmd

html 输出:


<img alt="graphviz-hostLegendG-a58ce04d28b92b59230a72964c27a9f8fc867de5.png" 
class="attachment" 
src="/moin/KupHostsMapping/MapLegend?action=AttachFile&amp;do=get&amp;target=graphviz-hostLegendG-a58ce04d28b92b59230a72964c27a9f8fc867de5.png" 
title="graphviz-hostLegendG-a58ce04d28b92b59230a72964c27a9f8fc867de5.png" /> 
<map id="hostLegendG" name="hostLegendG">
<area shape="rect" href="http://wiki.s.kingsoft.net/moin/KupHosts" title="普配主机" alt="" coords="101,36,173,63"/>
<area shape="rect" href="http://wiki.s.kingsoft.net/moin/KupHosts" title="高配主机" alt="" coords="197,36,269,63"/>
</map>

注意: 发现,插件是直接使用{{attachment:导图图片名}} 标准的图片附件形式来发布的!
  • 然而,HTML 中要想啓用热区图,至少要有专用属性的对应:
    <img usemap="#俺的ImgMap" src="..."/>
    <map id="俺的ImgMap" name="俺的ImgMap">
    <area shape="rect" href="..." title="普配主机" alt="" coords="101,36,173,63"/>
    ...
    </map>
    
    • 在dot 输出的map 数据中,id/name 就是``digraph G { `` 第一行的那个G,可以任意命名,当然最好是E文
  • 所以,就得找到方法来让 MoinMoin 对附件图片追加usemap属性

    找哈找,幸好有 ack-grep 快速从一堆脚本中定位到靠谱的代码段:
path/2/python2.5/site-packages/MoinMoin/formatter/text_html.py
...
    def attachment_image(self, url, **kw):
        ...
        if exists:
            ...
            if not 'alt' in kw:
                kw['alt'] = kw['title']
            #   100729 Zoom.Quiet fixed for support imagemap for Graphviz
            kw['usemap'] = "#%s"%kw['alt']
            return self.image(**kw)
        ...

追加一行就好...

1.2. jQuery

虽然目标完成了,但是心里总感觉不好:

  • MoinMoin 本身的脚本被hacking 了,就等于,以后升級,迁移时,都要维护这一hacking
  • 很不 Pythonic 哪...

    怎么样脱离 MoinMoin 系统本身来给附件图片追加usemap 属性?
  • 答案,自然是的 Ajax 哪
  • jQuery 就是为这类快速夹塞儿式行为诞生的哪...
部署jQuery:
  • 这是样式的事儿,所以:

    path/2/moin实例/
    +-- data
        +-- plugin
            +-- theme
                +-- 你的样式定义脚本
                +-- woodpecker.py ~ 俺用的
            def footer(self, d, **keywords):
                ... # 追加
                u'<!-- Finally, to loading jQuery Ajax Lib. -->',
                u'<script src="/wiki/common/js/jquery-1.4.2.min.js" type="text/javascript"></script>',
                u'<script src="/wiki/common/js/jquery-graphviz-map.js" type="text/javascript"></script>',
    
    +-- htdoc
        +-- common
            +-- js
                +-- jquery-1.4.2.min.js ~ 官方运营用压缩版本
                +-- jquery-graphviz-map.js  ~ 动态行为定义用
    
使用jQuery:
  • 看看文档,就两行搞定..
    
    $(document).ready(function() {
    	$("img[class='attachment']").each(function(){
    	    $(this).attr("usemap","#"+$(this).attr("alt"));
        });
    });
    
    • 特别的:得考虑一页多个导图时的情况,所以是要进行 each() 循环处置
  • 当然的,需要 MoinGraphViz/main.py插件的配合,以便从附图的 alt 中获得正确的图片热区ID

    
    Index: tasks/wiki.KUP/MoinMoin/parser/MoinGraphViz/main.py
    ===================================================================
    --- tasks/wiki.KUP/MoinMoin/parser/MoinGraphViz/main.py (revision 17010)
    +++ tasks/wiki.KUP/MoinMoin/parser/MoinGraphViz/main.py (revision 17013)
    @@ -65,5 +65,8 @@
             fImgName = os.path.basename(s)
             pfImgMap = "%s/%s.map"%(self.attapath,fImgName)
    -        s = wiki2html(self.request, '{{attachment:%s}}' % os.path.basename(s))
    +        #s = wiki2html(self.request, '{{attachment:%s}}' % os.path.basename(s))
    +        s = wiki2html(self.request, '{{attachment:%s|%s}}' % (os.path.basename(s)
    +                        ,fImgName.split("-")[1])
    +                    )
             #   100728 Zoom.Quiet appended <map> data
             if os.path.exists(pfImgMap):
    

1.3. 编码问题

一切表现良好,无意间发现凡是有URL包含的 dot 图谱,被其它页面包含时就出错!

囧rz...:
  • 尝试各种编码,未果
  • 嘗試各种<map>的包装形式:
    1. 使用 <pre>
    2. 使用 <textarea>
  • 都在 Include 时,可怜的出错了...
  • 实在是因为 MoinMoin 不想处理正常的 HTML 标签属性的其它编码内容
  • 好吧,俺就不给出无用的中文内容!
  • path/2/moin运行实例/data/plugin/parser/MoinGraphViz/main.py 追加一小段正则表达式替换

    def format(self, formatter):
        w = self.request.write
        #...
        #   100728 Zoom.Quiet appended <map> data
        if os.path.exists(pfImgMap):
            import re
            p=re.compile( 'title=\".+?\"')
            s += p.sub("title=\"\"",fread(pfImgMap))
            #s += fread(pfImgMap)

HTML 输出:


<img alt="graphviz-hostLegendG-a58ce04d28b92b59230a72964c27a9f8fc867de5.png" 
class="attachment" 
src="/moin/KupHostsMapping/MapLegend?action=AttachFile&amp;do=get&amp;target=graphviz-hostLegendG-a58ce04d28b92b59230a72964c27a9f8fc867de5.png" 
title="graphviz-hostLegendG-a58ce04d28b92b59230a72964c27a9f8fc867de5.png" /> 
<map id="hostLegendG" name="hostLegendG">
<area shape="rect" href="http://wiki.s.kingsoft.net/moin/KupHosts" title="" alt="" coords="101,36,173,63"/>
<area shape="rect" href="http://wiki.s.kingsoft.net/moin/KupHosts" title="" alt="" coords="197,36,269,63"/>
</map>

一切安定了...

2. 小结

  • 思路不乱的情况下,主要问题就是定位代码段!以及测试!
    • 面对一运行中的MoinMoin 进行测试开发时
    • 使用sshfs 可以快速挂接远程服务器的任意目录,非常方便!
    • 使用沙箱页面进行修订插件的测试,可以避免正常文章页面的中间调试失常..
    • 在调试中,直接输出预想数据到 HTML 里看,比看系统日志,使用print 要方便
    • MoinMoin 有完备的缓冲机制,要及时看到修订效果,得重启HTTPD
  • jQuery 真的很好用,也好学!
下载:
diff: MoinMoin_parser_MoinGraphViz_main.py-from-r16946-to-r17013.diff

2.1. 时间清单

  1. 00:05 定目标
  2. 00:15 准备环境
  3. 01:30 探查运行环境,明确修订目标脚本
  4. 01:45 插件修订完成
  5. 00:15 图片应用map jQuery 嘗試
  6. 00:35 图片插入系统修订完成
  7. 01:00 正则表达式+jQuery 解决 Incldue() 时的编码问题
  8. 00:45 整理代码,发布到Blog
  9. 00:35 整理代码,反馈到MoinMoin.in
  10. 00:40 8次中断,回到工作场景的心理浪费

总计: ~ 6小时


  • t2t渲染:: 2010-10-09 02:21:37
  • 动力源自::txt2tags

§ 写于: Fri, 30 Jul 2010 | 永久链接;源文: rdf ,rss ,raw | 分类: /utility/py4web/MoinMoin §
[MailMe] [Print] Creative Commons License

作品Zoom.Quiet创作,采用知识共享署名-相同方式共享 2.5 中国大陆许可协议进行许可。 基于zoomquiet.org上的作品创作。