2010年12月22日水曜日

ブックマークレットでpukiwikiのtracker_listを並べ替え可能にする

ブックマークレットでpukiwikiのtracker_listを並べ替え可能にする

ブックマークレットでpukiwkiの編集中のDiffをとるサンプルを先日示したが、同様に表題のようなサンプルを作成してみた。前回同様、EUC/utf-8、PukiWiki/PukiWikiPlusなどのターゲットの環境を選ばないようにしています。

このブックマークレットでできること

  • pukiwiki及びPlusなどの派生版で、tracker_list、bugtrack_listで表示される表を、ExtJSのGridPanelで置き換えます
  • 置き換えられたGridPanelは、ヘッダ部をクリックすることにより、サーバと通信することなくソート可能です
  • 同じくヘッダ部を操作することにより、列の表示/非表示切り替え、列幅の調整、列の表示位置変更等が可能です
  • 「ページ名」というヘッダを持つ列は、単に文字列によるソートでなく、ページ名に現れる番号を意識して並べ替えられるので、「BugTrack1/100」は「BugTrack1/22」や「BugTrack1/9」よりも後に表示されます((並べ替えの際、スラッシュで区切られる文字列が数字のみである場合、5ケタになるよう前ゼロを付けたのちに比較されます。「BugTrack1/22」は「BugTrack1/00022」に、「ほげ/2/3」は「ほげ/00002/00003」に、比較時に内部的に変換されます))
サンプルの使い方
  • 1.まず下記のURLをブックマーク(IEはお気に入り)に登録します。名前はなんでもいいです。(たとえば「pukiwiki Table」)
javascript:(function(){var%20e=document.createElement('script');e.charset='utf-8';e.src='http://www123.ddo.jp/tools/tracker00.js';document.body.appendChild(e);})()
  • 2.いつも使っているpukiwikiのサイトのBugTrackの画面等を開き、登録したブックマーク(お気に入り)を選びます。
  • 3.すると、上記のようにテーブルがExtJSのgridに変換され、ソートなどの操作ができるようになります

ブックマークレットとスクリプトの解説

上記のブックマークは改行とインデントを入れ読みやすくすると
 javascript:(
     function(){
         var e=document.createElement('script');
         e.charset='utf-8';
         e.src='http://www123.ddo.jp/tools/tracker00.js';
         document.body.appendChild(e);
     }
 )()
見ての通り、これでwww123.ddo.jpからtracker00.jsというスクリプトを読み込んで実行しているわけです。

読み込んだtracker00.jsは下記のような動作をします。

  • ExtJS 3.3.1を動かすために必要なライブラリやスタイルシートを読み込む
  • 最初のtrの要素がtdでなくすべてthであるtableタグについて下記を行います
  •  ヘッダー部の解析とデータストアの作成
  • データの読み込みとGridPanelの描画

下記ページにて確認をしています
セキュリティについて
 
edit00.jsと同様なセキュリティのリスクがあります。理解したうえでお試しください。 

tracker00.jsソースコード 


    // tracker.js v 00 -- pukiwikiのTrackerの機能アップ
    // Bookmarklet example
    //   javascript:(function(){var%20e=document.createElement('script');e.charset='utf-8';e.src='http://www123.ddo.jp/tools/tracker00.js?';document.body.appendChild(e);})()
    // Copyright(c) 2010 mashiki
    // License: GPL version 3
    (function(){
        var cf='http://extjs.cachefly.net/ext-3.3.1/';
        addEl('style', {type:'text/css',innerHTML:'td {background-color:transparent}'});
        addEl('link',{rel:'stylesheet',type:'text/css',href:cf+'resources/css/ext-all.css'});
        addEl('script',{src:cf+'adapter/ext/ext-base.js'});
        addEl('script',{src:cf+'ext-all.js'});
        addEl('script',{src:cf+'examples/ux/TableGrid.js'});
       
        function addEl(tag, cfg) {
            var e=document.createElement(tag);
            for (var key in cfg) e[key]=cfg[key];
            document.body.appendChild(e);
        }
        var id=setInterval(function(){

            if(window.Ext && Ext.MessageBox){
                clearInterval(id);

                var ce = Ext.select('table');
                ce.each(function(tbl){
                    var tr0 = tbl.select('tr', true).first();
                    var hdrs = tr0.query('th');
                   
                    if (hdrs.length>0 && tr0.query("td").length===0 ) {
                        convertToGrid(tbl, hdrs);
                    }
                },true);
            }
        },100);

        function convertToGrid(tbl, hdrs) {
            var ct = tbl.insertSibling(),
                flds = [{name:'no'}],
                cols = [];

            for (var i=0, h; h=hdrs[i]; ++i) {
                var text = h.innerHTML.replace(/]+>(.+?)<\/a>/gi,'$1')
                                    .replace(/\s*(:?↑|↓)\([\d]+\)/,''),
                    name = 'tcol-' + i;
                var fld = {
                    name: name,
                    mapping: 'td:nth('+ (i+1) +')/@innerHTML'
                };
                if (text==='ページ名') {
                    fld.sortType = function(val) {
                        var parts = val.replace(/]+>(.+?)<\/a>/gi,'$1').split("/");
                        for (var i=0,p; p=parts[i];++i) {
                            if (p.match(/^[\d]+$/)) {
                                parts[i]=String.leftPad(p, 5, '0')
                            }
                        }
                        return parts.join('/');
                    }
                }
                flds.push(fld);

                cols.push({
                    header: text,
                    dataIndex: name,
                    width: h.offsetWidth,
                    tooltip: h.title,
                    align: 'left',
                    sortable: true
                });
            }

            var ds = new Ext.data.Store({
                reader: new Ext.data.XmlReader({
                    record: 'tbody tr'
                }, flds)
            });

            ds.loadData(tbl.dom);
            var r = ds.getAt(0);
            if (!(r.get(0))) ds.remove(r);
            i = 0;
            ds.each(function(r){r.set('no',++i)});
            ds.commitChanges();

            ct.setWidth(tbl.getWidth());

            tbl.remove();

            var grid = new Ext.grid.GridPanel({
                stripeRows: true,
                'ds': ds,
                'cm': new Ext.grid.ColumnModel(cols),
                'sm': new Ext.grid.RowSelectionModel(),
                autoHeight: true,
                autoWidth: false,
                renderTo:ct
            });
        }

    })();


0 件のコメント:

コメントを投稿