クロスブラウザライブラリ - DXBL

 

DXBL(Diaspar Cross Browser Layer)は、 JavaScript を使用してブラウザのスクリプトエンジンの振る舞いを W3C 勧告に近づけます。 現在、このような処理が必要なブラウザとして IE (Internet Explorer) があります。

DXBL は JavaScript アプリケーションに対して透過的に設計されています (図1)。

JavaScript アプリケーション
Firefox Opera
DXBL.ie
IE (Internet Explorer)
図1 DXBL の位置付け

DXBL を使用しているサンプルについては、次のリンクを参照してください。

このサンプルは、Firefox, Opera, Swift(Safari系) などの IE 以外のブラウザで動くように作成したものですが、 DXBL を読み込むことにより IE でも動くようにしてあります。

Download

クロスブラウザ化の内容

表内のリンクをクリックすると、W3C 勧告の日本語訳ページを表示します。 (XMLHttpRequest のみ英文です。)

オブジェクト メソッド・プロパティ 種別 DXBL 備考
element addEventListener() method 0.1.0 *2
element dispatchEvent() method 0.1.0 *3
element getElementsByTagName() method 0.4.0 *4
element removeEventListener() method 0.1.0 *2
element.style opacity property 0.3.0
event target property 0.1.0
event currentTarget property 0.1.0
event preventDefault() method 0.1.0
event stopPropagation() method 0.1.0
event initMouseEvent() method 0.1.0 *3
window XMLHttpRequest() method 0.1.1
document getElementById() method 0.3.0 *1
document createEvent() method 0.1.0 *3

*1  :  getElementById() は IE に実装されていますが、 DXBL ではこのメソッドを修正することにより、 クロスブラウザ化の大半を実現しています。
*2  :  IE の場合、第3引数には false のみ指定できます。
*3  :  現在のバージョンでは試験的な実装です。 恐らく将来もこのままです、、、
*4  :  クロスブラウザ化された要素を返します。 ただし、クロスブラウザ化されるのは、id または class のどちらかが 設定されている要素に限ります。

DXBLの使い方

HTMLの記述

DXBL を使用するには、HTML に次のように記述します。 [if IE] により、DXBL の適用を IE のみに制限 します。

<!--[if IE]>
<script type="text/javascript" src="dxbl.js"></script>
<![endif]-->

API

クロスブラウザ化の処理はライブラリ内部で完結するため、 ライブラリを呼び出すための API は存在しません。

制限事項

DXBL バージョン 0.4.x は、ページの読み込み完了の待ち合わせに window.onload を使用しています。 DXBL を利用するアプリケーションは、window.onload の代わりに window.addEventListener("load", ・・・) を使用する必要があります。

ソースコード

dxbl.js
/*  DXBL - Diaspar Cross Browser Layer, version 0.4.1
 *  http://diaspar.jp/node/51
 *  2007-02-23
 */

var DXBL    = {}        // for Diaspar Cross Browser Layer
DXBL.ie     = {}        // for Internet Explorer
DXBL.ie.w3c = {}        // W3C 互換メソッドの定義

DXBL.ie.w3c.addEventListener = function(elm, lsns) {
    return function(type, listener, useCapture) {
        if (useCapture) { return; }
        var wrapper = function(evt) {
            DXBL.ie.event(evt, elm);
            listener(evt);
        }
        lsns.push({ type: type, listener: listener, wrapper: wrapper});
        elm.attachEvent("on" + type, wrapper);
    }
}

DXBL.ie.w3c.createEvent = function() {
    return function(eventType) {
        var evt = document.createEventObject();
        evt.initMouseEvent = function(type) {
            this.type = type;
        }
        return evt;
    }
}

DXBL.ie.w3c.dispatchEvent = function(elm) {
    return function(evt) {
        elm.fireEvent("on" + evt.type);
    }
}

DXBL.ie.w3c.getElementById = function() {
    var orgmethod = document.getElementById;
    return function(id) {
        return DXBL.ie.element(orgmethod(id));
    }
}

DXBL.ie.w3c.getElementsByTagName = function(elm) {
    var orgmethod = elm.getElementsByTagName;
    return function(tagname) {
        var elms = orgmethod(tagname);
        for (var i = 0; i < elms.length; ++i) {
            if (elms[i].id || elms[i].className) {
                DXBL.ie.element(elms[i]);
            }
        }
        return elms;
    }
}

DXBL.ie.w3c.removeEventListener = function(elm, lsns) {
    return function(type, listener, useCapture) {
        if (useCapture) { return; }
        for (var i in lsns) {
            if (lsns[i].type == type && lsns[i].listener == listener) {
                elm.detachEvent("on" + lsns[i].type, lsns[i].wrapper);
                lsns.splice(i, 1);
                break;
            }
        }
    }
}

DXBL.ie.w3c.XMLHttpRequest = function() {
    try {
        new ActiveXObject("Msxml2.XMLHTTP");
        return function() {
            return new ActiveXObject("Msxml2.XMLHTTP");
        }
    }
    catch (e) {
        try {
            new ActiveXObject("Microsoft.XMLHTTP");
            return function() {
                return new ActiveXObject("Microsoft.XMLHTTP");
            }
        }
        catch (e) {
            throw e;
        }
    }
}

DXBL.ie.element = function(elm) {
    if (typeof elm.addEventListener == "function") {
        return elm;     // 処理済み
    }
    var listeners = [];
    elm.addEventListener     = DXBL.ie.w3c.addEventListener(elm, listeners);
    elm.dispatchEvent        = DXBL.ie.w3c.dispatchEvent(elm);
    elm.getElementsByTagName = DXBL.ie.w3c.getElementsByTagName(elm);
    elm.removeEventListener  = DXBL.ie.w3c.removeEventListener(elm, listeners);
    elm.attachEvent("onpropertychange", DXBL.ie.property);
    return elm;
}

DXBL.ie.event = function(evt, elm) {
    evt.target          = evt.srcElement;
    evt.currentTarget   = elm;
    evt.preventDefault  = function() { evt.returnValue = false; }
    evt.stopPropagation = function() { evt.cancelBubble = true; }
}

DXBL.ie.property = function(evt) {
    var elm = evt.srcElement;
    switch (evt.propertyName) {
    case "style.opacity":
        var value = elm.style.opacity;
        elm.style.filter = "Alpha(opacity=" + (value * 100) + ")";
        break;
    default:
        break;
    }
}

DXBL.ie.element(window);

window.onload = function() {
    if (typeof window.XMLHttpRequest == "undefined") {          // IE6
        window.XMLHttpRequest = DXBL.ie.w3c.XMLHttpRequest();
    }
    DXBL.ie.element(document);
    document.createEvent    = DXBL.ie.w3c.createEvent();
    document.getElementById = DXBL.ie.w3c.getElementById();
    document.getElementsByTagName("*");     // ページが構築されてから実行
}

解説

クロージャ

DXBL バージョン 0.4.x では意識的かつ積極的にクロージャ(Closure)を活用しています。 クロージャの使用目的は、Activation(Call)オブジェクトのプロパティである 「引数」と「ローカル変数」を、関数の実行終了後にも関数オブジェクト(戻り値)に縛り付けておくことです。 こうすることにより、スクリプトエンジンの環境を荒らさずに状態を保持することができます。

例えば、addEventListener と removeEventListener が共用しているリスナの管理領域を 「引数」上に保持しておくことができます。 また、ライブラリ側にさえも(明示的な)リスナの管理領域を持たないので、 HTML要素が追加や削除により動的に変化したとしても気にする必要がありません (管理コードを書く必要がありません)。

クロージャ関連の記事へのリンクは 「JavaScript とクロージャ」 へ移動しました。

2009-02-25

更新履歴

日付 版数 記述
2007-02-23 0.4.1 タイプミスを修正(動作・機能に変更無し)。
2007-02-22 0.4.0 クロージャを活用してコードをスッキリさせた。 getElementsByTagName をサポートした。 英語表記を Library から Layer に改めた。
2006-09-11 0.3.1 スクロールについて、IE7 と IE6 では同じ振る舞いをすることが分った。 調査資料⇒「ブラウザのスクロール量を取得するには?」 これに伴い、スクロール関連のクロスブラウザ化は不要になったため廃止した。
2006-07-07 0.3.0 クロスブラウザ化の処理をライブラリ内部で完結するように修正した。 これに伴い、DXBL.Element()は不要になったため廃止した。  0.3.0 ( dxbl.js, scroll.htc )
2006-06-11 0.2.0 イベントオブジェクトのクロスブラウザ化を、 すべてaddEventListenerメソッド内のラッパー関数に任せるように修正した。 これに伴い、DXBL.Event()は不要になったため廃止した。
2006-05-28 0.1.1 XMLHttpRequestをサポート。 調査資料⇒「XMLHttpRequestオブジェクトを取得するには?
2006-05-25 0.1.0 0.05版をベースにDXBLオブジェクトを導入して、使い勝手の向上を図った。