Home > 2008年04月

2008年04月

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。
  • Comments (Close): -
  • TrackBack (Close): -

ログインしていない時のはてなのピンの処理

はてなブックマークにログインしていると、一度ピンをたてておけば別のページに移動した後、あるいはブラウザを閉じて後日にでも、ピンを立てたエントリーを閲覧することが可能なわけだが、当然ログインしていないとページを移動した時立てたピンを失ってしまう。

もちろんページを移動する前に立てたピンをまとめて開けばすむことだが、うっかりミスすることもあるのでそれを防ぐために、 Opera User JavaScriptでページから移動した時に立てたピンを自動的に開くようにしてみようと思った。

Karafuto Blog Operaの unloadイベント で書いたようにページを移動する時は unloadイベントが発動されるからいいが、ページを閉じる、更新、履歴の移動はイベントが発動されない。 仕方がないのでページを閉じるショートカットCtrl+wに限定して対応したので、かなり使える幅の狭いものになってしまった。

スクリプトの流れ

  1. 開くピンの数(userjs_openpinnumber)を設定
  2. ページを移動した時 4.以下を実行
  3. ctrl+wを押した時ページを閉じる。window.close()で閉じるため 4.以下が実行される
  4. 立てたピンの数が開くピンの数(userjs_openpinnumber)以下ならば、ピンをまとめて開く
  5. 立てたピンの数が開くピンの数より多ければ、立てたピンのリンクのリストを別ウィンドウに表示する(ただし表示する立てたピンのリンクは100までにしておいた)

Operaのポップアップの設定を「ポップアップをバックグラウンドで開く」または「すべてのポップアップを有効にする」にしておく。ポップアップの設定は、サイト設定の編集>一般設定または設定>一般設定から行う。

// ==UserScript==
// @include http://b.hatena.ne.jp/*
// ==/UserScript==


// 開くピンの数の設定
window.opera.addEventListener('BeforeScript', function (e){
    userjs_openpinnumber = 10;
    var src = e.element.getAttribute('src');
    if ( src && src.match(/pin\.js$/) ) {
        var text = e.element.text;
        text = text.replace(/num = num \|\| this\.numOpenAtOnce \|\| 5;/, "num = num || this.numOpenAtOnce || " + userjs_openpinnumber + ";");
        e.element.text = text;
    }
}, false);


document.addEventListener('load', function (){

    if (!Hatena.id){
        document.addEventListener('unload', function (){
            openPin_logout();
        }, false);
        Bookmark.keybind.add('ctrl-w', function (){
            window.close();
        });
    }

    // 立てたピンを処理する関数
    function openPin_logout(){
        if (Bookmark.pin.items.length) {
            if ( Bookmark.pin.items.length < userjs_openpinnumber + 1){
                Bookmark.openPinned();
            } else {
            var content = '<ul>';
            Bookmark.pin.items.slice(0, 100).each(function (e){
                content += '<li><a href="' + e.url + '" target="_blank">' + e.title + '</a></li>'
            });
            content += ('</ul>');
            var newWindow = window.open();
            newWindow.document.write(content);
            }
        }
    }   

}, false);

hateb_openpin_unload_logout.js

開くピンの数の変数 userjs_openpinnumberはグローバル変数でグローバルな名前空間を汚している。userjs_openpinnumberは開くピンの数を取得したいので設定している。

上のほうにも書いたが、ページ移動とctrl+wにしかスクリプトは反応しない。特にページを閉じる方法はたくさんあって(マウスジェスチャー、メニュー、タブをマウスホイールでクリック、全てのタブを閉じる、その他)、ミスを防ぐという意図を果たせていないような。

書いといて言うのはなんだが、結論としてはてなブックマークはログインして使えということ。そうすればこのスクリプトは要らない。

Operaの unloadイベント

Operaの unloadイベントは、ページを移動する時はイベントが発生するが、ページを閉じた時、更新、履歴の移動ではイベントが発生しない。

ところが、JavaScriptの window.close()や history.forward()、history.back()では unloadイベントが発生する。ああ JavaScriptの場合は発生するのかと思っていると、location.reload()ではイベントが発生しない。よく分からん。

ちなみに Firefoxでは ページの移動、ページを閉じる、更新、履歴の移動で unloadイベントが発生する。JavaScriptの window.close()、history.forward()、history.back()、location.reload()でもイベントは発生する。

まあイベントが多けりゃいいってもんでもないけど、ウィンドウを閉じるイベントはほしいなあ。

参考にした記事

Unload event in Opera - 赤心慶福 - by akahuku

選択文字列で URL移動するマウスジェスチャー

マウスジェスチャーの↑→で選択文字列を URLとして移動に設定している。別のタブ(ウィンドウ)に開く。

下記のどこかで拾ってきたものを使わせてもらっていたが、

GestureUp, GestureRight="Go to page, "javascript:(function (){select_txt = document.getSelection();x = select_txt.slice(0,4);if(x == 'http'){open(select_txt)}else if(x == 'ttp:' || x == 'ttps'){open('h' + select_txt)}else if(x == 'www.'){open('http://' + select_txt)}else{alert('選択文字列はURLではありません。')}})()""

選択文字列はURLではありません。と断られることが多いので、作ってみた。

http://xxxxxxxxxxxx         →        http://xxxxxxxxxxxx
ttp://xxxxxxxxxxxx          →        http://xxxxxxxxxxxx
tp://xxxxxxxxxxxx           →        http://xxxxxxxxxxxx
p://xxxxxxxxxxxx            →        http://xxxxxxxxxxxx
://xxxxxxxxxxxx             →        http://xxxxxxxxxxxx
//xxxxxxxxxxxx              →        http://xxxxxxxxxxxx
/xxxxxxxxxxxx               →        http://xxxxxxxxxxxx
xxxxxxxxxxxx                →        http://xxxxxxxxxxxx

https://xxxxxxxxxxxx        →        https://xxxxxxxxxxxx
ttps://xxxxxxxxxxxx         →        https://xxxxxxxxxxxx
tps://xxxxxxxxxxxx          →        https://xxxxxxxxxxxx
ps://xxxxxxxxxxxx           →        https://xxxxxxxxxxxx
s://xxxxxxxxxxxx            →        https://xxxxxxxxxxxx

神経質にこんな感じになるようにした。選択した文字列はすべて URL(http,https)だと思いこみ、移動しようとする。

var txt = document.getSelection();
var p = 'http://';
var s = 'https://';
var l = p + txt;
for (var i = 0; i < 7; i ++ ){
    if (txt.indexOf(p.substring(i,7)) == 0){
        l = p.substring(0,i) + txt;
        break;
    } else if (txt.indexOf(s.substring(i,8)) == 0){
        l = s.substring(0,i) + txt;
    }
}
open(l);

マウスジェスチャー↑→で選択した文字列を URLとして別のタブ(ウィンドウ)に開く。

GestureUp, GestureRight="Go to page, "javascript:(function(){var txt = document.getSelection();var p = 'http://';var s = 'https://';var l = p + txt;for (var i = 0; i < 7; i ++ ){if (txt.indexOf(p.substring(i,7)) == 0){l = p.substring(0,i) + txt;break} else if (txt.indexOf(s.substring(i,8)) == 0){l = s.substring(0,i) + txt;}}open(l);})();""

マウスジェスチャー↑→↓で選択した文字列を URLとして同じタブ(ウィンドウ)に開く。

GestureUp, GestureRight, GestureDown="Go to page, "javascript:(function(){var txt = document.getSelection();var p = 'http://';var s = 'https://';var l = p + txt;for (var i = 0; i < 7; i ++ ){if (txt.indexOf(p.substring(i,7)) == 0){l = p.substring(0,i) + txt;break} else if (txt.indexOf(s.substring(i,8)) == 0){l = s.substring(0,i) + txt;}}location.href=l;})();""

正規表現ならこんな感じか。

var txt = document.getSelection();
var l = txt.replace(/^(?:(?:http|ttp|tp|p|)(s)?:\/\/|\/\/|\/|)/, 'http$1://');
open(l);

マウスジェスチャー↑→で選択した文字列を URLとして別のタブ(ウィンドウ)に開く。

GestureUp, GestureRight="Go to page, "javascript:(function(){var txt = document.getSelection();var l = txt.replace(/^(?:(?:http|ttp|tp|p|)(s)?:\/\/|\/\/|\/|)/, 'http$1://'); open(l);})();""

マウスジェスチャー↑→↓で選択した文字列を URLとして同じタブ(ウィンドウ)に開く。

GestureUp, GestureRight, GestureDown="Go to page, "javascript:(function(){var txt = document.getSelection();var l = txt.replace(/^(?:(?:http|ttp|tp|p|)(s)?:\/\/)?/, 'http$1://');location.href=l;})();""

選択文字列を検索するマウスジェスチャー

マウスジェスチャーの↑で選択した文字列を検索するようにしてある。検索結果を別のタブ(ウィンドウ)に開く。検索サイトは Googleサジェスト

GestureUp, Go to page, "javascript:(function(){var t=document.getSelection();if(t){open('http://www.google.co.jp/search?complete=1&hl=ja&lr=lang_ja&num=30&q='+encodeURIComponent(t));}})()"

こういう風に JavaScriptで書いていたが、Operaのアクションだけで選択文字列の検索ができるのを知らなかった。

GestureUp=Copy & Go to page & Insert, "gs " & Paste & Go

gsは Googleサジェストに設定したニックネーム。

マウスジェスチャーの↑↓で検索結果を同じタブで開く場合は、

GestureUp, GestureDown=Copy & Focus address field & Insert, "gs " & Paste & Go

Googleサジェストを使っていたが、日本語版は無くなってしまった。便利でよく使っていたのに…。(英語版のGoogle Suggestは生きているが、私の環境の Operaでは日本語を確定する前は候補が出てこないし、確定してもカーソルを動かしたり、バックスペースを押さないと候補が出てこないため使いづらい。)

と書こうと思っていたら、日本のGoogleサジェストが復活していた。

クロージャのメモ

クロージャのことが分かりかけてきたのでメモしておく。

普通は関数の実行が終わると、ローカル変数はなくなる。

function outer(){
    var a = 0;
    function inner(){
        a++;
        alert(a);
    }
    inner();
}

outer();        // 1
outer();        // 1

しかし、クロージャを使うと、内側の関数が外側の関数のローカル変数を参照していることによってローカル変数が保持される。

function outer(){
    var a = 0;
    function inner(){
        a++;
        alert(a);
    }
    return inner;
}

var count = outer();
count();        // 1
count();        // 2

関数を実行して内側の関数を返す。内側の関数を残すことによって、内側の関数から参照されているローカル変数が保持される。
通常は外側の関数からしか呼び出せない内側の関数が、内側の関数を返すことによって、関数の外でも実行できる。
通常は関数の外からアクセスできないローカル変数が、内側の関数を使うことで関数の外でローカル変数にアクセスできるようになる。

クロージャを使わないで失敗する例

for (var i = 0; i < document.links.length; i ++ ){
    document.links[i].onclick = function (){
        alert(document.links[i]);
        return false;
    }
}

全てのリンクにイベントハンドラを設定している中で、イベントハンドラを設定するループの中で関数内の変数 iにも同じ数が代入されることを期待しているが、失敗する。

イベントハンドラを設定した時には関数が実行されないため、関数内の変数 iには何も代入されない。そのため、どのリンクをクリックしても関数内の変数 iには現在の変数 iの値(document.links.length)が代入されて、そのリンクは存在しないため undefinedが表示される。

そこでクロージャを使う

for (var i = 0; i < document.links.length; i ++ ){
    document.links[i].onclick = function (a){
        return function (){
            alert(document.links[a]);
            return false;
        }
    }(i);
}

クロージャを使って関数の外の変数 iを保持する。イベントハンドラを設定するループの中で、外側の関数を実行して、イベントハンドラに内側の関数を返す。その時に変数 iの値を外側の関数の引数 aにとり、内側の関数から引数 aを参照して保持している。

こういう時は本当は thisを使えばいいと(クロージャの練習なんでいらないが)。

for (var i = 0; i < document.links.length; i ++ ){
    document.links[i].onclick = function (){
        alert(this);
        return false;
    }
}

参考にしたページ

Core JavaScript 1.5 Guide:Working with Closures - MDC

Home > 2008年04月

おまかせリンク(R)
全記事表示リンク
Search
Meta
Feeds

Page Top

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。