サイトマップ

JavaScriptコードスニペット:Webページを丸ごと1ファイルにする

JavaScriptからHTMLにアクセスするには、普通はdocumentオブジェクトを使うのですが、これで取得できるHTMLは既に他のJavaScriptによって汚されてしまったものである可能性があり、ブラウザが正規化してしまった結果であったりします。たとえばHTMLの文法チェックを行いたいと思っても、これでは無意味です。

そこで、ajax的に現在のページのHTMLソースを取ってきたらどうかと思いついて、簡単なスクリプトを作ってみました。それは造作なくできたんですが、これって画像とかの外部ファイルも同一サーバにあれば取ってきて埋め込めば、1ファイル化できるのではないかと考えました。で、できるできないでいえば、概ねできるんですけど、あんまり意味ないですねぇ。

※注意 IEで実行するとハングアップしてしまうので実行しないでください。

[サンプルの実行]←クリックするとこのページの内容をひとまとめにしたソースを別ウインドウに表示します。
(function() {
    var getdata = function(url, binaryflag) {
        var xmlhttp;
        try { xmlhttp = new ActiveXObject("Msxml2.XMLHTTP"); } catch (e) {
            try { xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); } catch (err) {
                xmlhttp = null;
            };
        };
        if(!xmlhttp && typeof XMLHttpRequest != "undefined"){
            xmlhttp = new XMLHttpRequest();
        }
        xmlhttp.open("GET", url, false);
        if (binaryflag)
            xmlhttp.overrideMimeType("text/plain; charset=x-user-defined");
        xmlhttp.send(null);
        return xmlhttp;
    }
    var base64 = function(data, binaryflag) {
        var seed = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
        if (data == null)
            return "====";
        var result = "";
        var arr = getbytes(data, binaryflag);
        var c = 0;
        for (var i = 0; i < arr.length; i++) {
            switch(i % 3) {
            case 0: result += seed.charAt((arr[i]>>2)&0x3f);
                    c = (arr[i]&0x03)<<4;
                    break;
            case 1: result += seed.charAt(c | ((arr[i]>>4)&0x0f));
                    c = (arr[i]&0x0f)<<2;
                    break;
            case 2: result += seed.charAt(c | ((arr[i]>>6)&0x0f));
                    result += seed.charAt(arr[i]&0x3f);
                    c = 0;
                    break;
            }
        }
        if (arr.length % 3 == 1) {
            result += seed.charAt(c);
            result += "==";
        } else if (arr.length % 3 == 2) {
            result += seed.charAt(c);
            result += "=";
        }
        return result;
    }
    var getbytes = function(data, binaryflag) {
        var result = [];
        if (!binaryflag) {
            for (var i = 0; i < data.length; i++) {
                var c = data.charCodeAt(i);
                if (c <= 0x7f) {
                    result.push(c);
                } else if (c <= 0x07ff) {
                    result.push(((c >> 6) & 0x1F) | 0xC0);
                    result.push((c & 0x3F) | 0x80);
                } else {
                    result.push(((c >> 12) & 0x0F) | 0xE0);
                    result.push(((c >> 6) & 0x3F) | 0x80);
                    result.push((c & 0x3F) | 0x80);
                }
            }
        } else {
            for (var i = 0; i < data.length; i++) {
                result.push(data.charCodeAt(i) & 0xff);
            }
        }
        return result;
    };
 
    var checkself = function(url) {
        if (url.match(/^https?:\/\/([^\/]+).*/) && RegExp.$1 != location.host) {
            return false;
        } else {
            return true;
        }
    };
 
    var html = getdata(location.href).responseText;
    html = html.replace(/<link[^>]*>/g, function() {
        if (arguments[0].match(/rel="stylesheet"/i)) {
            return arguments[0].replace(/(href=")([^"]*)(")/i, function() {
                if (!checkself(arguments[2]))
                    return arguments[1] + arguments[2] + arguments[3];
                var result = getdata(arguments[2]);
                return arguments[1] + "data:" + result.getResponseHeader('content-type')
                    + ";base64," + base64(result.responseText) + arguments[3];
            });
        } else if (arguments[0].match(/rel="shortcut icon"/i)) {
            return arguments[0].replace(/(href=")([^"]*)(")/i, function() {
                if (!checkself(arguments[2]))
                    return arguments[1] + arguments[2] + arguments[3];
                var result = getdata(arguments[2], true);
                return arguments[1] + "data:" + result.getResponseHeader('content-type')
                    + ";base64," + base64(result.responseText, true) + arguments[3];
            });
        } else {
            return arguments[0];
        }
    });
 
    /* scriptは属性データに埋め込むとハングアップしてしまってマズいので、インラインにCDATAで埋め込む */
    html = html.replace(/<script[^>]*>/g, function() {
        if (arguments[0].match(/(src=")([^"]*)(")/i)) {
            if (!checkself(RegExp.$2))
                    return arguments[0];
            var result = getdata(RegExp.$2);
            return arguments[0].replace(/src="[^"]*"/, '')
                + "<!--//--><![CDATA[//><!--\n"
                + result.responseText
                + "//--><!]]>";
        } else {
            return arguments[0];
        }
    });
 
    html = html.replace(/<img[^>]*>/g, function() {
        return arguments[0].replace(/(src=")([^"]*)(")/i, function() {
            var u = RegExp.$2;
            if (!checkself(u))
                    return arguments[0];
            var result = getdata(arguments[2], true);
            return arguments[1] + "data:" + result.getResponseHeader('content-type')
                + ";base64," + base64(result.responseText, true) + arguments[3];
        });
    });
 
    var win = window.open("", "_blank");
    if (win) {
        win.document.write('<textarea id="textarea" style="border:none;width:100%;height:100%;"></textarea>');
        win.document.close();
        win.document.body.style.margin = 0;
        win.document.body.style.overflow = 'hidden';
        win.document.getElementById('textarea').value = html;
    } else {
        alert("ポップアップウインドウを許可する設定にしてください。");
    }
})();

更新履歴

  • 2012-04-24 同一ホスト上のコンテンツのみを差し替えるように変更しました。

関連コンテンツ

参照

 
research/1309832567.txt · 最終更新: 2012/04/24 12:13 by Kazuyuki Matsuda
特に明示されていない限り、本サイトの内容は次のライセンスに従います:Copyright(C) 2011 Shorindo, Inc. All Rights Reserved
Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki