Hatena::ブログ(Diary)

Higé au lait Twitter

 | 

2007年09月28日

キーイベント追加 2

// KeyBinds.js
// Author: Higeorange
// Licence: MIT

var KeyBinds = function(elm, k) {
    this.elm = elm;
    this.keybind = {};
    for(var t in k) {
        this.add(t, k[t]);
    }
};
    KeyBinds.prototype.expand = function(key) {
        var keycode;
        var m = null
        var sp = {
            "Up" : 38,
            "Down" : 40,
            "Right" : 39,
            "Left" : 37
        }
        key.replace(/^(([CSA])-)?(\w+)$/, function($0, $1, $2, $3) {
            if($2) m = $2;
            keycode = sp[$3] || $3.toUpperCase().charCodeAt(0);
        });
        return [keycode, m]
    }

    KeyBinds.prototype.add = function(key, func) {
        var e = this.expand(key);
        var keycode = e[0];
        var m = e[1];
        if(!this.keybind[keycode]) {
            this.keybind[keycode] = {};
        }
        if(m) {
            this.keybind[keycode][m] = func;
        } else {
            this.keybind[keycode].func = func;
        }
        return this;
    };
    KeyBinds.prototype.remove = function(key) {
        var e = this.expand(key);
        var keycode = e[0];
        var m = e[1];
        if(this.keybind[keycode]) {
            if(m && this.keybind[keycode][m]) {
                delete this.keybind[keycode][m]
            } else if(this.keybind[keycode].func){
                delete this.keybind[keycode].func
            }
        }
        return this;
    }
    KeyBinds.prototype.load = function(func) {
        var self = this;
        var addEvent = function(elm, type, func, c) {
            if(elm.addEventListener){
                elm.addEventListener(type, func, c);
                return true;
            }
            else if(elm.attachEvent){
                return elm.attachEvent('on' + type, func);
            }
            else{
                elm["on" + type] = func;
            }
        }
        addEvent(this.elm, "keypress", function(e) {
            e = e || window.event
            var c = false;
            var num = e.keyCode || e.charCode;
            var k = self.keybind[num]
            if(k) {
                if(e.ctrlKey) c = k.C 
                else if(e.shiftKey) c = k.S 
                else if(e.altKey) c = k.A 
                else c = k;
            }

            if(c) {
                if(e.preventDefault) {
                    e.preventDefault();
                    e.stopPropagation();
                } else {
                    e.returnValue = false;
                    e.cancelBubble = true;
                }   
            }
        }, false);
        addEvent(this.elm, 'keydown', function(e) {
            e = e || window.event;
            var num = e.keyCode || e.charCode;
            if(func) func(e)
            var k = self.keybind[num];
            if(k) {
                if(e.ctrlKey) {
                    if(k.C) k.C(e)
                } else if(e.shiftKey){
                    if(k.S) k.S(e)
                } else if(e.altKey) {
                    if(k.A) k.A(e)
                } else {
                    if(k.func) k.func(e);
                }
            }
        }, false);
    }

使いかた

new KeyBinds(window, {
  "a": function() {
    alert("hoge")
  },
  "f": function() {
    alert("fuga")
  }
}).load()
new KeyBinds(document).add("f", function() { alert("fuga") }).load()

追記

全てのキーに割り当てる場合, load の引数に関数をあたえる

new KeyBinds(document).load(function(){ alert("keypress") })

再追記

たぶん IE に対応。 IE, Opera, Firefox, Konqueror に対応したつもり

再々追記

KeyBinds.remove() を追加。 使い道あるかどうかわからないけど。

new KeyBinds(window, {
  "a": function() {
    alert("hoge")
  },
  "f": function() {
    alert("fuga")
  }
}).remove("f").load()

再々々追記

IE に対応させたつもりがコード直すの忘れてた。

さらに手直しをしてこんどこそ IE に対応させたつもり。


修正

ブラウザ側のショートカットを抑止

バグ

"w" にキーバインドを割り当てると ブラウザ側の ”Shift+w", "Ctrl+w", "Alt+w" まで抑止してしまう。

参考

ultra blue:JavaScript : Opera と Firefox でのキーイベントの違い


修正

上のバグの修正

2007年09月27日

キーイベント追加

var KeyBind = {};
    KeyBind.add = function(elm, key, func) {
        var keycode;
        var m = null;
        var sp = {
            "Up" : 38,
            "Down" : 40,
            "Right" : 39,
            "Left" : 37
        }
        if(key) {
            key.replace(/^(([CSA])-)?(\w+)$/, function($0, $1, $2, $3) {
                if($2) {
                    m = ({
                        C : "ctrl",
                        S : "shift",
                        A : "alt"
                    })[$2] + "Key";
                }
                keycode = sp[$3] || $3.toUpperCase().charCodeAt(0);
            });
            elm.addEventListener('keydown', function(evt) {
                if(m) {
                    if(evt[m] && evt.keyCode == keycode) {
                        func(evt);
                    }
                } else {
                    if(evt.keyCode == keycode) {
                        func(evt);
                    }
                }
            }, false);
        } else {
            elm.addEventListener('keydown', func, false);
        }
    }

使いかた

KeyBind.add(window, "C-r", function(evt) {
    alert("hoge")
});

説明

第一引数: 追加したい要素

第二引数: キーバインド C-: Ctrl+, S-: Shift+, A-: Alt+。ふたつ以上の組み合わせは不可。記号に対応していない。 すべてのキーにあたえたい場合 null or false

第三引数; 実行したい関数

2007年09月13日

配列にプロパティ & メソッドを持たせる。

var Hoge = [1,3];
    Hoge.fuga = "foobar"
    Hoge.print = function(a) {
        print(this + ":" + this.length);
    }   

Hoge.print(); // 1,3:2
Hoge.push(3);
Hoge.print(); // 1,3,3:3
Hoge.push(4);
Hoge.print(); // 1,3,3,4:4

print(Hoge.fuga) // foobar

配列はオブジェクトなんだった*1


参考

はてなブログ

*1:typeof で 'object' が返る

2007年09月12日

コーディングスタイル

var Person = {
    name : "higeorange",
    getName: function() {
        alert(this.name);
    }   
}

var Person = {};
    Person.name = "higeorange";
    Person.getName = function() {
        alert(this.name);
    };

どっちが見やすい?

アホなミス

["H", "o", "g", "e"].pop().join(””) // pop() で配列が返ると思い込む。

["F", "u", "g"].push("a").join("") // push() で配列が返ると思い込む。

こうするるよ。

Array.prototype._pop = function() {
    this.pop();
    return this;
}

Array.prototype._shift = function() {
    this.shift();
    return this;
}

Array.prototype._push = function(o) {
    this.push(o);
    return this;
}

Array.prototype._unshift = function(o) {
    this.unshift(o);
    return this;
}

["H", "o", "g"]._push("e")._shift()._unshift("fuga").join("")  // fugaoge
 |