2012-12-12 [長年日記]

ちょっとここらできれいにしておく

前回作ったプラグインのおさらい。

  1. 適切な setup.py を作って、python setup.py egg_info を実行すると、tracが認識するモジュールになる。
  2. tracを起動して、管理画面の plugins で チェックを入れると、プラグインが有効になる。
  3. プラグインをつくるには、Component を拡張したクラスで、拡張ポイントを implements して、拡張ポイントが規定するメソッドを実装してやる。
  4. 特定のURLに反応するには、IRequestHandler 拡張ポイントを使う。
  5. ナビメニューを追加するには、INavigationContributor 拡張ポイントを使う。
  6. ページにJavaScriptを仕込むには、ITemplateStreamFilter 拡張ポイントが使える。
  7. JavaScriptのような静的コンテンツを返すには、ITemplateProvider 拡張ポイントで格納場所を教えてやる。
で、作ったのがこんな感じ:

QueryStatusHelperPlugin/setup.py:

from setuptools import setup
    
setup(
    name='QueryStatusHelperPlugin',
    entry_points = {
        'trac.plugins': [
            'QueryStatusHelperPlugin = query.doubleclick',
        ],
    },
)
QueryStatusHelperPlugin/query/__init__.py:
from query import *
QueryStatusHelperPlugin/query/doubleclick.py:
from trac.core import Component, implements
from trac.web.api import ITemplateStreamFilter
from trac.web.chrome import add_script, ITemplateProvider
import pkg_resources
    
class Checkbox(Component):
    implements(ITemplateProvider, ITemplateStreamFilter)
    
    #ITemplateStreamFilter methods
    def filter_stream(self, req, method, filename, stream, data):
        add_script(req, 'querystatushelper/js/enabler.js')
        return stream
    
    # ITemplateProvider methods
    def get_htdocs_dirs(self):
        return [('querystatushelper', pkg_resources.resource_filename('query', 'htdocs'))]
    
    def get_templates_dirs(self):
        return []
QueryStatusHelperPlugin/query/htdocs/js/enabler.js:
jQuery(document).ready(function() {
    jQuery('#label_0_status').dblclick(function() {
        jQuery('input[name="0_status"]').each(function() {
            checked = $(this).attr("checked")
            $(this).attr("checked",!checked)
        })
    })
});
おさらいは以上。

きになるところ

  1. どんなページでもやみくもに add_script してる。ほかのページに迷惑かかってるかも。
  2. #label_0_statusinput[name="0_status"] というリテラルが埋め込んである。ほかのフィールドに対応してない。
  3. ライセンス表明がない。
  4. ドキュメントがない。
  5. テストがない。

さて、どれから手をつけようか。

どんなページでもやみくもに add_script してる → add_script するページを限定しよう

add_script の前に if文を入れて、必要なとき、つまりクエリページにだけ add_script するようにする。
条件は……。「クエリページだけ」とは? さっそくブレークポイントを張って、使えそうな変数を探す:

  1. self: Checkbox:
  2. req: RequestWithSession:
  3. method: str: xhtml
  4. filename: str: query.html
  5. streamStream: <!DOCTYPE html PUBLIC ...
  6. data: dict: { 'authname': ... , 'chrome': { いろいろ }, 'href': ..., 'project': {いろいろ}, ... }
Developer Plugin 経由でAPIドキュメントを見ると、こう書いてある:
filter_stream(req, method, filename, stream, data)
Return a filtered Genshi event stream, or the original unfilteredstream if no match.
`req` is the current request object, `method` is the Genshi rendermethod (xml, xhtml or text), `filename` is the filename of the templateto be rendered, `stream` is the event stream and `data` is the data forthe current template.
やりたいことは「適切なチェックボックスにdblclickハンドラを追加したい」ので、その「適切なチェックボックス」を生成しているやつを特定したい。テンプレートである query.html をみると:

${prjectloc}/python/System Libs/site-packages/trac/ticket/templates/query.html(104):

    <py:when test="field.type == 'radio'">
      <py:for each="option in field.options">
        <input type="checkbox" id="_${n_field_name}_$option" name="${n_field_name}"
          value="$option"
          checked="${((constraint['mode'] == '') == (option in constraint['values'])) or None}" />
        <label for="_${n_field_name}_$option" class="control">${option or 'none'}</label>
      </py:for>
    </py:when>
……ビンゴ。if(filename=='query.html'): でラップしてやればいい。


«前の日記(2012-12-11) 最新 次の日記(2012-12-13)»