LoginSignup
10
10

More than 5 years have passed since last update.

jQueryを使ったブックマークレットの作成方法

Posted at

ユーザが閲覧しているWebページに対してなんらかのアクションをとらせたい場合、ブックマークレットの提供が選択肢になります。たとえば、Catchboxでもブックマークレットを提供しています

ブックマークレットは、JavaScriptのコードをブックマークバーに追加することで実装しますが、実現したい処理自体をブックマークとして登録させてしまうと、アップデートを行うことができなくなります。

そこで、サーバサイドに処理内容を記述したJavaScriptファイルを配置し、そのJavaScriptファイルを、閲覧しているWebページのbody部の最後に追加する処理を、ブックマークレットとしてユーザに登録させます。

これは、ユーザがブックマークバーに追加する処理です。(分かりやすいよう改行とコメントを加えていますが、実際には1行に圧縮して提供します)

javascript:(function(){
    // サーバに配置したJSのドメイン
    // 変数名は、元のページのJavaScriptの変数と競合しないようにプレフィックスをつけます
    BML_D='playcatchbox.com';

    // サーバに配置したJSを読み込むためのscriptタグ
    BML_SCRIPT=document.createElement('script');
    BML_SCRIPT.type='text/javascript';
    BML_SCRIPT.src='//'+BML_D+'/b/b.js';

    // body部の最後にscriptタグを追加
    document.getElementsByTagName('body')[0].appendChild(BML_SCRIPT)
})();

これで、閲覧中のページにサーバ側に配置したJavaScriptを読み込ませる処理ができました。
次に、サーバ側に配置したJavaScriptです。

以下のようなフォルダ構成でファイルを用意します。

htdocs
    ・ b < JavaScriptを格納するフォルダ >
        ・ b.js <処理内容が記述されたJavaScriptファイル>
        ・ lib.all.js
        ・ lib.js

lib.all.jsには jQueryの最新版jQuery postMessage の両方を記述します。
lib.jsには jQuery postMessageのみを記述します。

その際、jQuery postMessageに、jQuery 1.9系以降で廃止になった $.browser 関数が使われているため、これを置き換えます。

lib.js
    // has_postMessage = window[postMessage] && !$.browser.opera;
    has_postMessage = window[postMessage] && !window.opera;

ブックマークレットの処理内容が書かれた r.js を見ていきます。

b.js
(function() {
    // JQueryの最低バージョン
    var v = "1.3.2";

    if (window.jQuery === undefined || window.jQuery.fn.jquery < v) {
        // jQueryが元のページで使用されていなかったら読み込んで処理を実行
        BML_LOAD_LIB('lib.all.js', function() {
            BML_BOOKMARKLET();
        });

    } else if (false === jQuery.isFunction(jQuery.receiveMessage)) {
        // jQuery postMessageが元のページで使用されていなかったら読み込んで処理を実行
        BML_LOAD_LIB('lib.js', function() {
            BML_BOOKMARKLET();
        });

    } else {
        // ライブラリがすべて元のページで読み込まれていたら処理を実行
        BML_BOOKMARKLET();
    }

    function BML_LOAD_LIB(BML_LIB_FILENAME, BML_CALLBACK) {
        var BML_IS_DONE = false;

        // ライブラリの読み込み
        var BML_LIB = document.createElement("script");
        BML_LIB.src = '//' + BML_D + '/b/' + BML_LIB_FILENAME;
        BML_LIB.onload = BML_LIB.onreadystatechange = function() {
            if (!BML_IS_DONE && (!this.readyState || this.readyState == "loaded" || this.readyState == "complete")) {
                // ライブラリが正しく読み込まれたら処理を実行
                BML_IS_DONE = true;
                BML_CALLBACK();
            }
        };
        document.getElementsByTagName("head")[0].appendChild(BML_LIB);
    }

    function BML_BOOKMARKLET() {
        (window.myBookmarklet = function($) {
            if ($("iframe#bookmarklet-overlay").length > 0) {
                return;
            }

            // 読み込むiframeタグを生成
            var $BML_IFRAME = $('<iframe/>');
            $BML_IFRAME.attr({
                'allowtransparency' : 'true',
                'scrolling' : 'no',
                'id' : 'bookmarklet-overlay',
                'name' : 'bookmarklet-overlay',
                'src' : '//' + BML_D + '/bookmarklet/' + encodeURIComponent(location.href)
            }).css({
                'border' : 'none',
                'height' : '100%',
                'width' : '100%',
                'position' : 'fixed',
                'z-index' : 2147483647,
                'top' : 0,
                'left' : 0,
                'display' : 'block'
            });

            $('body').append($BML_IFRAME);

            // iframe側からpostMessageで'close'のメッセージを受け取ったら、追加したiframeを削除
            $.receiveMessage(function(e) {
                if (e.data === 'close') {
                    $BML_IFRAME.remove();
                }
            });
        })(jQuery);
    }
})();

最後に、iframe内に表示されるページ (上記の例であれば http:// [ドメイン] /bookmarklet/ [読み込み元のURL] )から、自身を削除するメッセージを送信するための記述を見ていきます。

これは上記のサンプルコードが、元のページに覆いかぶさるようにiframeが配置するため、そのiframeが表示されている間は、その下に隠れる元のページを操作することができなくなります。

iframe内に表示されたページで処理を終えた後は、上に覆いかぶさったiframeを取り除いてあげる必要がありますが、iframe内に表示されるページと、iframeが追加されたページ(元のページ)はドメインが異なるため、このままでは、iframeを削除するための処理を、iframe内に表示されたページ側から行うことはできません。(クロスドメイン問題)

そこで、jQuery postMessage pluginを使用して、iframe内に表示させるページから、元のページへmessageを送り、そのmessageを受け取った元のページ側に読み込まれたJSファイルにより、iframeを除去します。

bookmarklet/index.html
<script type="text/javascript">
    function close {
        // 'close'のメッセージを送信
        $.postMessage('close', 'http:// [元のページのURL]', parent);
    }
</script>

(現時点の課題)
* このブックマークレットは、外部JSの読み込みを許可していないサイト(Facebookなど)では作動しないです。

10
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
10