タグ別アーカイブ: html

jQueryテンプレートエンジンを改良してみた

こないだ作ったjquery.jsontpl.jsを改良してみた。

プレースホルダーとして<var class="Foo"></var>などと記述すると変数Fooの値で置換される。または、class=".Foo.jsontpl-var"な任意の要素のinnerHTMLに変数Fooの値が設定される。みたいな仕様。

index.html

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja">
<head>
    <title>jQuery Template</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <meta http-equiv="Content-Script-Type" content="text/javascript" />
    <script src="./common/js/jquery.1.5.js" type="text/javascript"></script>
    <script src="./common/js/jquery.jsontpl.js" type="text/javascript"></script>
    <script type="text/javascript">
    //<![CDATA[
        $(document).ready(function(){
            // set global params
            jQuery.jsontpl.setParams({classPrefix:'jsontpl'});

            // jQueryエレメントをテンプレートとして使用
            $.jsontpl.parse($('#templates tr'),'./data.json').appendTo('.movie');

            // jQueryエレメントをテンプレートとして使用(別パターン)
            $.jsontpl('#templates tr').parse('./data.json').appendTo('.movie');

            // テンプレートとJSONをサーバーから取得
            $.jsontpl.parse('./tpl.html','./data.json').appendTo('.movie');

            // テンプレートのみサーバーから取得
            var json = {
                "Name": "test1",
                "ReleaseYear": "test2",
                "Director": "test3"
            };
            $.jsontpl.parse('./tpl.html', json).appendTo('.movie');

            // テンプレートとJSONをサーバーから取得
            $.jsontpl.getTpl('./tpl.html').parse('./data.json').appendTo('.movie');
        });
    //]]>
    </script>
</head>

<body>
    <div id="templates" style="display:none;">
        <table>
            <tr><!-- template -->
                <th class="Name jsontpl-var"></th>
                <td class="ReleaseYear jsontpl-var"></td>
                <td class="Director jsontpl-var"></td>
                <td class="conbination">
                    <!-- placeholer not required -->
                    <var class="Name"></var>
                    <var class="ReleaseYear"></var>
                </td>
            </tr>
        </table>
    </div>
    <table class="movie" summary="summary">
    </table>
</body>
</html>

data.json

[
{ "Name": "The Red Violin", "ReleaseYear": "1998", "Director": "Francois Girard" },
{ "Name": "Eyes Wide Shut", "ReleaseYear": "1999", "Director": "Stanley Kubrick" },
{ "Name": "The Inheritance", "ReleaseYear": "1976", "Director": "Mauro Bolognini" }
]

結果

下記のようになります。

<table summary="summary" class="movie">
    <tbody><tr><!-- template -->
                <th class="Name">The Red Violin</th>
                <td class="ReleaseYear">1998</td>
                <td class="Director">Francois Girard</td>
                <td class="conbination">
                    <!-- placeholer not required -->
                    The Red Violin
                    1998
                </td>
            </tr><tr><!-- template -->
                <th class="Name">Eyes Wide Shut</th>
                <td class="ReleaseYear">1999</td>
                <td class="Director">Stanley Kubrick</td>
                <td class="conbination">
                    <!-- placeholer not required -->
                    Eyes Wide Shut
                    1999
                </td>
            </tr><tr><!-- template -->
                <th class="Name">The Inheritance</th>
                <td class="ReleaseYear">1976</td>
                <td class="Director">Mauro Bolognini</td>
                <td class="conbination">
                    <!-- placeholer not required -->
                    The Inheritance
                    1976
                </td>
            </tr><tr><!-- template -->
                <th class="Name">The Red Violin</th>
                <td class="ReleaseYear">1998</td>
                <td class="Director">Francois Girard</td>
                <td class="conbination">
                    <!-- placeholer not required -->
                    The Red Violin
                    1998
                </td>
            </tr><tr><!-- template -->
                <th class="Name">Eyes Wide Shut</th>
                <td class="ReleaseYear">1999</td>
                <td class="Director">Stanley Kubrick</td>
                <td class="conbination">
                    <!-- placeholer not required -->
                    Eyes Wide Shut
                    1999
                </td>
            </tr><tr><!-- template -->
                <th class="Name">The Inheritance</th>
                <td class="ReleaseYear">1976</td>
                <td class="Director">Mauro Bolognini</td>
                <td class="conbination">
                    <!-- placeholer not required -->
                    The Inheritance
                    1976
                </td>
            </tr><tr>
    <th class="Name">The Red Violin</th>
    <td class="ReleaseYear">1998</td>
    <td class="Director">Francois Girard</td>
    <td class="conbination">
        <!-- placeholer not required -->
        The Red Violin
        1998
    </td>
</tr><tr>
    <th class="Name">Eyes Wide Shut</th>
    <td class="ReleaseYear">1999</td>
    <td class="Director">Stanley Kubrick</td>
    <td class="conbination">
        <!-- placeholer not required -->
        Eyes Wide Shut
        1999
    </td>
</tr><tr>
    <th class="Name">The Inheritance</th>
    <td class="ReleaseYear">1976</td>
    <td class="Director">Mauro Bolognini</td>
    <td class="conbination">
        <!-- placeholer not required -->
        The Inheritance
        1976
    </td>
</tr><tr>
    <th class="Name">test1</th>
    <td class="ReleaseYear">test2</td>
    <td class="Director">test3</td>
    <td class="conbination">
        <!-- placeholer not required -->
        test1
        test2
    </td>
</tr><tr>
    <th class="Name">The Red Violin</th>
    <td class="ReleaseYear">1998</td>
    <td class="Director">Francois Girard</td>
    <td class="conbination">
        <!-- placeholer not required -->
        The Red Violin
        1998
    </td>
</tr><tr>
    <th class="Name">Eyes Wide Shut</th>
    <td class="ReleaseYear">1999</td>
    <td class="Director">Stanley Kubrick</td>
    <td class="conbination">
        <!-- placeholer not required -->
        Eyes Wide Shut
        1999
    </td>
</tr><tr>
    <th class="Name">The Inheritance</th>
    <td class="ReleaseYear">1976</td>
    <td class="Director">Mauro Bolognini</td>
    <td class="conbination">
        <!-- placeholer not required -->
        The Inheritance
        1976
    </td>
</tr></tbody></table>

jquery.jsontpl.js

/*!
 * jquery.jsontpl - client side template engine powered by jQuery
 *
 * @requires jQuery version 1.5 or higher
 * @version 0.0.2
 */
(function ($) {

    $.jsontpl = $.subclass();

    /**
     * debug console for plugin develop
     */
    var console = {
        log : (window.console) ? window.console.log : function () {}
    };

    /**
     * default params
     */
    $.jsontpl.params = {
        classPrefix : 'jsontpl',
        __trailing__: null
    };

    /**
     * Override params
     *
     * @param obj {object}
     * @returns {jQuery.jsontpl}
     */
    $.jsontpl.setParams = function (params) {
        $.extend($.jsontpl.params, params);
        return this;
    };

    /**
     * ajax cache {url : data}
     */
    var cache = {};

    /**
     * modified $.ajax for cache mechanism
     *
     * @param params {object}
     * @returns {XMLHttpRequest | empty object}
     */
    $.jsontpl.ajax = function (params) {
        if (cache[params.url]) {
            params.success(cache[params.url]);
            return {};
        }
        params.success = (function() {
            var url = params.url;
            var orgSuccess = params.success;
            return function(a) {
                cache[url] = a;
                orgSuccess(a);
            }
        })();
        return $.ajax(params);
    };

    /**
     * $.ajax wrapper for template get
     *
     * @param url {string}
     * @returns {jQuery.jsontpl}
     */
    $.jsontpl.getTpl = function (url) {
        var ret;
        $.jsontpl.ajax({
            type: "GET",
            url: url,
            cache: true,
            async: false,
            error: function (error) {
                console.log(error.statusText + " at " + url);
            },
            success: function (tpl) {
                ret = $.jsontpl(tpl);
            }
        });
        return ret;
    };

    /**
     * $.ajax wrapper for JSON get
     *
     * @param url {string}
     * @returns {jQuery.jsontpl}
     */
    $.jsontpl.getJSON = function (url) {
        var ret;
        $.jsontpl.ajax({
            type: "GET",
            url: url,
            cache: true,
            async: false,
            dataType: 'json',
            error: function (error) {
                console.log(error.statusText + " at " + url);
            },
            success: function (json) {
                ret = json;
            }
        });
        return ret;
    };

    /**
     * $.ajax wrapper for getting tpl & json
     *
     * @param tpl {string} template filename
     * @param json {string} json filename
     * @returns {jQuery.jsontpl} template & json
     */
    $.jsontpl.get = function (tpl, json) {
        return {
            tpl  : $.jsontpl.getTpl(tpl),
            json : $.jsontpl.getJSON(json)
        };
    };

    /**
     * Parse template
     *
     * @param tpl {jQuery element | string} jQuery element or filename
     * @param json {object | string} object or filename
     * @returns {jQuery element}
     */
    var _parse =  function (tpl, json) {
        if (typeof tpl === 'string') {
            tpl = $.jsontpl.getTpl(tpl);
        }
        if (typeof json === 'string') {
            json = $.jsontpl.getJSON(json);
        } else if ((json.constructor !== Array)) {
            json = [json];
        }
        var ret = $('<div></div>');
        for (var obj in json) {
            var a = tpl.clone();
            for (var tplvar in json[obj]) {

                // replace <var>
                a.find("var." + tplvar).after(json[obj][tplvar]).remove();

                // replace innerHTML of class *.placeholder
                var placeholder = $.jsontpl.params.classPrefix + '-var';
                a.find("." + placeholder + "." + tplvar)
                    .html(json[obj][tplvar])
                    .removeClass(placeholder);
            }
            ret.append(a);
        }
        return $.jsontpl(ret.html());
    };

    /**
     * Parse template
     *
     * @param tpl {jQuery element | string} jQuery element or filename
     * @param json {object | string} object or filename
     * @returns {jQuery element}
     */
    $.jsontpl.parse = _parse;

    /**
     * Parse template
     *
     * @param json {object | string} object or filename
     * @returns {jQuery.jsontpl element}
     */
    $.jsontpl.fn.parse = function (json) {
        return _parse(this, json);
    };
})(jQuery);

 

javascriptとcssを全自動で連結&圧縮する

橋の上から
Creative Commons License photo credit: amadeusrecord

ウェブサイト作るときに、最近は膨大な数のjqueryのプラグインなんかをロードしなくちゃいけない。ロードするファイルが増えるとページのパフォーマ ンスにも影響するのでソースを1ファイルにまとめて、さらに圧縮するのが効果的なんだけど、これを手作業でするのは骨が折れる。特に開発段階では頻繁にソースへの修正が入るので、効率が悪い。そういう訳で自動化した。

こうなる

無数のjsやcssを個別に開発し、HTMLにはcat.phpのパラメータとして各ファイル名を+区切りで記述する。ファイルはdir/a.jsなどとディレクトリを切っても構わない。

<script type="text/javascript" src="./js/cat.php?jquery.1.4.2.js+a.js+b.js"></script>

<link rel="stylesheet" href="./css/cat.php?dir/a.css+dir/b.css" type="text/css" />

これだけで、全てのファイルが連結され、改行やコメント、先頭のCSS以外のcharsetが削除される。また、gzip対応ブラウザにはgzipを出力し、Etagなどのキャッシュ関連のヘッダもいい感じに世話してくれる。ファイルの更新日を常に判定しているので、ファイルに変更が加わればキャッシュはクリアされる(はず)。そういう訳で、一度セットアップしてしまえば、圧縮うんぬんのことは忘れてしまって、どんどんファイルを増やそう。

方法

ライブラリとして下記をダウンロードする。

下記のように配置する。PHPのライブラリは任意の場所で構わないが、cat.phpの先頭のset_include_pathを合わせる必要がある。

[DIR]commons
├[DIR]php
│├[DIR]Minify
││├[DIR]CSS
│││└Compressor.php
│││└UriRewriter.php
││├CommentPreserver.php
││└CSS.php
│└JSMin.php
├[DIR]js
│├[DIR]cache
│├jquery.1.4.2.js
│├a.js
│├b.js
│└cat.php
└[DIR]css
  ├[DIR]cache
  ├a.css
  ├b.css
  └cat.php

※cat.phpに実行権限、cacheディレクトリに書き込み権限が必要。

Google Page Speedつながりで、次回は全自動で画像最適化のネタを書きたい。

よくあるエンコード/デコード関係のウェブツールを使いやすくした

Wasatch Forest
Creative Commons License photo credit: nichcollins

エンコードマニアってサイトがありますが、アレ系のツールをもっと使いやすくしようと思ってできたのが下記。

http://webtools.jamadam.com/

一つの入力文字列に対して下記の出力を生成します。

各種文字コードによるURLエンコード/デコード、HTMLエスケープ(調整中)、MD5、SHA1、punycode変換/逆変換、base64エンコード/デコード、crypt(3)

すべてクライアントサイドのJavascriptで処理している点が特徴です。なので、送信ボタンはありません。入力欄に文字を打つと、インクリメンタルに全項目を生成します。サーバーにデータを送信しないので、パスワード生成とかも安心かもしれません。

各出力の右側の「FW」ボタンを押すと、その文字列が再入力されるので、可逆性の確認や、二重エンコードもスムーズ。

あと、最近デザイナー的な仕事ばかりしていて、段組の幅の計算が面倒だったので、マルチカラム計算機もついてます。

ライブラリは下記を使わせて頂いています。

URLエンコード: http://nurucom-archives.hp.infoseek.co.jp/digital/escape-codec-library.html

base64: http://coderepos.org/share/browser/lang/javascript/Base64/trunk

MD5: http://labs.cybozu.co.jp/blog/mitsunari/2007/07/md5js_1.html

SHA1: http://labs.cybozu.co.jp/blog/mitsunari/2007/07/sha1_1.html

crypt(3): http://whereswalden.com/tech/internet/javacrypt/

punycode: http://orera.g.hatena.ne.jp/misttrap/20080518/p1