メッセージ欄

2009年9月の日記

一覧で表示する

ショートカットキーをGUIで設定
2009/09/27(日) 21:00 Javascriptはてブ情報 はてブに登録 はてブ数

単一のイベントで複数のショートカットキーイベント - jimo/memo
http://d.hatena.ne.jp/jimo1001/20090601/1243782686

元ネタではCtrl+Deleteなどが使用できなかったのでちょっと修正。
動いてるのかは微妙
var ShortcutKey = function() {
	this.list = [];
	this.init();
}
ShortcutKey.prototype.keys = {
	8: 'BS',
	10: 'RET',
	13: 'RET',
	32: 'SPC',
	9: 'TAB',
	27: 'ESC',
	33: 'PageUp',
	34: 'PageDown',
	35: 'End',
	36: 'Home',
	37: 'Left',
	38: 'Up',
	39: 'Right',
	40: 'Down',
	45: 'Insert',
	46: 'Delete',
	112: 'F1',
	113: 'F2',
	114: 'F3',
	115: 'F4',
	116: 'F5',
	117: 'F6',
	118: 'F7',
	119: 'F8',
	120: 'F9',
	121: 'F10',
	122: 'F11',
	123: 'F12'
}
ShortcutKey.prototype.skeys = {
	8: 'BS',
	10: 'RET',
	13: 'RET',
	32: 'SPC'
}
ShortcutKey.prototype.mkeys = {
	'altKey' : 'A',
	'ctrlKey' : 'C',
	'metaKey' : 'M',
	'shiftKey' : 'S'
}
ShortcutKey.prototype.init = function() {
	var self = this;
	window.addEventListener('keydown', function(evt) {
		var key = self.get(evt);
		self.list.forEach(function(a) {
			if (a.key == key && (a.element == evt.target || a.element == evt.view)){
// 				console.log(a.key +"=="+ key);
				a.func();
			}
		});
	}, false);
}
ShortcutKey.prototype.add = function(elm, key, func) {
	this.list.push(
		{
			'element' : elm,
			'key' : key,
			'func' : func
		}
	);
}
ShortcutKey.prototype.get = function(evt) {
	var key = [], k = '';
	for (mk in this.mkeys) {
		if(evt[mk])
			key.push(this.mkeys[mk]);
	}
	if (evt.which){
		k = this.keys[evt.which] || String.fromCharCode(evt.which).toLowerCase();
		key.push(key.length ? '-'+k : k);
	}else if (evt.keyCode){
		k = this.keys[evt.keyCode];
		key.push(key.length ? '-'+k : k);
	}
	return key.join("");
}
var shortcut = new ShortcutKey();
GM_config.init('Configuration for search filter',{
	defaultTag:    { label: 'Pre text:', type: 'text' , default: 'Now browsing: ' },
	isSelection:  { label:'Use selection', type: 'checkbox', default: true },
	ShortURL: { label:'Short URL', type:'select', options: {'http://is.gd/api.php?longurl=' : 'is.gd','http://tinyurl.com/api-create.php?url=': ' tinyurl.com','http://tweetburner.com/links' : 'tweetburner.com'}, default: 'is.gd' },
	ShortCutKey:    { label: 'ShortcutKey:', type: 'text' , default: 'CS+return' },
	TwitterUserName: { section: ['Twitter'],label: 'Twitter Username:', type: 'text' , default: 'azu_re' },
	TwitterPassword: { label: 'Twitter Password :', type: 'text' , default: '' },
},  "#config_header {font-size:16pt !important;} .config_var {margin:5px 0 5px 20% !important;} #header {margin-bottom:30px !important;} .indent40 {margin-left:20% !important;}" , // to add your CSS - replace this with configStyle
	{
		open: function() {
			var iframe = document.getElementById("GM_config");
			iframe.contentDocument.getElementById("field_ShortCutKey").addEventListener('keydown', function(evt) {
				evt.preventDefault();
				this.value = shortcut.get(evt);
			},false);
    },
		save: function() {

		} // reload the page when configuration was changed
});
使うとき
var shortcut = new ShortcutKey();
shortcut.add(window, 'C-a', function() {
    alert('test');
});
shortcut.add($('IF4L_input'), 'd', function() {
    alert('test2');
});
// ショートカットキーを表示するインプットエリア
var inputTag = document.createElement("input");
inputTag.addEventListener('keydown', function(evt) {
				evt.preventDefault();
				this.value = shortcut.get(evt);
			},false);

XPath関数
2009/09/22(火) 10:40 Javascriptはてブ情報 はてブに登録 はてブ数

$X関数を並べてみる

Nov 17 2007 :: New version of $X / nulog, NULL::something : out of the washer
http://lowreal.net/blog/2007/11/17/1

型指定、複数/単数 タイプで決めていく
// $X(exp);
// $X(exp, context);
// $X(exp, type);
// $X(exp, context, type);
function $X (exp, context, type /* want type */) {
    if (typeof context == "function") {
        type    = context;
        context = null;
    }
    if (!context) context = document;
    var exp = (context.ownerDocument || context).createExpression(exp, function (prefix) {
        var o = document.createNSResolver(context).lookupNamespaceURI(prefix);
        if (o) return o;
        return (document.contentType == "application/xhtml+xml") ? "http://www.w3.org/1999/xhtml" : "";
    });

    switch (type) {
        case String:
            return exp.evaluate(
                context,
                XPathResult.STRING_TYPE,
                null
            ).stringValue;
        case Number:
            return exp.evaluate(
                context,
                XPathResult.NUMBER_TYPE,
                null
            ).numberValue;
        case Boolean:
            return exp.evaluate(
                context,
                XPathResult.BOOLEAN_TYPE,
                null
            ).booleanValue;
        case Array:
            var result = exp.evaluate(
                context,
                XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
                null
            );
            var ret = [];
            for (var i = 0, len = result.snapshotLength; i < len; i++) {
                ret.push(result.snapshotItem(i));
            }
            return ret;
        case undefined:
            var result = exp.evaluate(context, XPathResult.ANY_TYPE, null);
            switch (result.resultType) {
                case XPathResult.STRING_TYPE : return result.stringValue;
                case XPathResult.NUMBER_TYPE : return result.numberValue;
                case XPathResult.BOOLEAN_TYPE: return result.booleanValue;
                case XPathResult.UNORDERED_NODE_ITERATOR_TYPE: {
                    // not ensure the order.
                    var ret = [];
                    var i = null;
                    while (i = result.iterateNext()) {
                        ret.push(i);
                    }
                    return ret;
                }
            }
            return null;
        default:
            throw(TypeError("$X: specified type is not valid type."));
    }
}

[javascript]$X関数に少し手を加えてみた
http://d.hatena.ne.jp/ofk/20080204/1202084410
singleNodeValueが拾える
function $X(exp, context, type) {
	if (typeof context == 'function' || typeof context == 'number') {
		type = context;
		context = document;
	}
	else {
		context = context || document;
	}
	exp = (context.ownerDocument || context).createExpression(exp, function (prefix) {
		var o = document.createNSResolver(context).lookupNamespaceURI(prefix);
		return o ? o : (document.contentType == 'application/xhtml+xml') ? 'http://www.w3.org/1999/xhtml' : '';
	});
	if (typeof type == 'number') {
		if (type == 0) {
			return exp.evaluate(context, 9, null).singleNodeValue;
		}
		var result = exp.evaluate(context, 7, null);
		var length = result.snapshotLength;
		if (type < 0) {
			type += length;
		}
		return 0 <= type && type < length ? result.snapshotItem(type) : null;
	}
	switch (type) {
	case Number:
		return exp.evaluate(context, 1, null).numberValue;
	case String:
		return exp.evaluate(context, 2, null).stringValue;
	case Boolean:
		return exp.evaluate(context, 3, null).booleanValue;
	case Array:
		var result = exp.evaluate(context, 7, null), res = [];
		for (var i = 0, j = result.snapshotLength; i < j; ++i) {
			res[res.length] = result.snapshotItem(i);
		}
		return res;
	default:
		var result = exp.evaluate(context, 0, null);
		switch (result.resultType) {
		case 1:
			return result.numberValue;
		case 2:
			return result.stringValue;
		case 3:
			return result.booleanValue;
		case 4:
			var res = [], i = null;
			while (i = result.iterateNext()) {
				res[res.length] = i;
			}
			return res;
		}
		return null;
	}
}

シンプルな$X関数(simple dollar X) - 0xFF
http://d.hatena.ne.jp/os0x/20080730/1217395310

シンプル化
function $X (exp, context) {
	context || (context = document);
	var expr = (context.ownerDocument || context).createExpression(exp, function (prefix) {
	return document.createNSResolver(context.documentElement || context).lookupNamespaceURI(prefix) ||
	context.namespaceURI || document.documentElement.namespaceURI || "";
	});
	 
	var result = expr.evaluate(context, XPathResult.ANY_TYPE, null);
	switch (result.resultType) {
	case XPathResult.STRING_TYPE : return result.stringValue;
	case XPathResult.NUMBER_TYPE : return result.numberValue;
	case XPathResult.BOOLEAN_TYPE: return result.booleanValue;
	case XPathResult.UNORDERED_NODE_ITERATOR_TYPE:
	// not ensure the order.
	var ret = [], i = null;
	while (i = result.iterateNext()) ret.push(i);
	return ret;
	}
	return null;
}
XPathEvaluator - 素人がプログラミングを勉強するブログ
http://d.hatena.ne.jp/javascripter/20090225/1235566024

has:真偽値
first:最初
last:最後
all:配列
XPath.reset();してから使用。
var XPath = {
	cache: null,
	reset: function () {
		this.cache = {__proto__: null};
	},
	get: function (context, expr, type) {
		var x = new XPathEvaluator();
		var cache = this.cache, evaluator;
		if (expr in cache) {
			evaluator = cache[expr];
		} else {
			evaluator = cache[expr] = x.createExpression(expr, null);
		}
		return evaluator.evaluate(context, type, null);
	},
	has: function (context, expr) {
		return this.get(context, expr, XPathResult.BOOLEAN_TYPE).booleanValue;
	},
	first: function (context, expr) {
		return this.get(context, expr, XPathResult.FIRST_ORDERED_NODE_TYPE).singleNodeValue;
	},
	last: function (context, expr) {
		var all = this.get(context, expr, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE);
		return all.snapshotItem(all.snapshotLength - 1) || null;
	},
	all: function (context, expr) {
		var all = this.get(context, expr, XPathResult.ORDERED_NODE_ITERAATE_TYPE);
		var ret = [];
		for (var i; (i = all.iterateNext()) !== null;) {
			ret.push(i);
		}
		return ret;
	}
};
XPath.reset();

バイナリ画像をDataURIに変換
2009/09/21(月) 28:07 Javascriptはてブ情報 はてブに登録 はてブ数

XHRで取得したものをDataURIにする。というのを目指してただけで動いてないはず。
function Baseka(url , callback){
        var parseHTTPHeader=function(responseHeader){
            var headers=responseHeader.split("\n");
            var len=headers.length;
            var parsing=[];
            for(var i=0;i<len;i++){
                if(/^$/.test(headers[i])){
                }else if(/^[\x09\x20]/.test(headers[i])){
                    if(parsing.length==0){
                        throw "SyntaxError:HTTPHeader (first line) "+headers[i];
                    }
                    parsing[parsing.length-1]+="\n"+headers[i];
                }else{
                    parsing.push(headers[i]);
                }
            }
            var len=parsing.length;
            var parsed={};
            for(var i=0;i<len;i++){
                var pair=parsing[i].split(": ",2);
                if(pair.length!=2){
                    throw "SyntaxError:HTTPHeader (format) "+parsing[i];
                }
                if(pair[0] in parsed){
                    throw "SyntaxError:HTTPHeader (repetition) "+pair[0];
                }
                parsed[pair[0]]=pair[1];
            }
            return parsed;
        }

        var loadDataMethod=function(res){
            var headers=parseHTTPHeader(res.responseHeaders);
            if(res.status!=200){
                throw "RequestError"+
                    ":status="+res.status+
                    ":statusText="+res.statusText+
                    ":responseHeaders="+res.responseHeaders;
            }
            var contentType=("Content-Type" in headers)?
                headers["Content-Type"]:
                "application/octet−stream";
            var dataScheme="data:"+contentType+
                ";base64,"+btoa(
                    res.responseText.replace(
                        /[\u0100-\uffff]/g,
                        function(c){
                            return String.fromCharCode(c.charCodeAt(0)&0xff);
                        }
                    )
                );
            data.callback(dataScheme);
        }

        var getData=function(url){
        		console.log(url)
            data.url=url;
            GM_xmlhttpRequest(
                {
                    "method":"GET",
                    "url":data.url,
                    "onload":loadDataMethod,
                    "onerror":loadDataMethod,
                    "overrideMimeType":"text/plain; charset=x-user-defined"
                }
            );
        }

        var data={};

        var getFileByDataScheme=function(url,callback){
            data.callback=callback;
            getData(url);
        }
        
         var handler=function(url,callback){
             (function(){
                 getFileByDataScheme(url,callback);
             })();
         }
         handler(url,callback); 
 }
画像化してみる
function Baseka(url , callback){

        var parseHTTPHeader=function(responseHeader){
            var headers=responseHeader.split("\n");
            var len=headers.length;
            var parsing=[];
            for(var i=0;i<len;i++){
                if(/^$/.test(headers[i])){
                }else if(/^[\x09\x20]/.test(headers[i])){
                    if(parsing.length==0){
                        throw "SyntaxError:HTTPHeader (first line) "+headers[i];
                    }
                    parsing[parsing.length-1]+="\n"+headers[i];
                }else{
                    parsing.push(headers[i]);
                }
            }
            var len=parsing.length;
            var parsed={};
            for(var i=0;i<len;i++){
                var pair=parsing[i].split(": ",2);
                if(pair.length!=2){
                    throw "SyntaxError:HTTPHeader (format) "+parsing[i];
                }
                if(pair[0] in parsed){
                    throw "SyntaxError:HTTPHeader (repetition) "+pair[0];
                }
                parsed[pair[0]]=pair[1];
            }
            return parsed;
        }

        var loadDataMethod=function(res){
            var headers=parseHTTPHeader(res.responseHeaders);
            if(res.status!=200){
                throw "RequestError"+
                    ":status="+res.status+
                    ":statusText="+res.statusText+
                    ":responseHeaders="+res.responseHeaders;
            }
            var contentType=("Content-Type" in headers)?
                headers["Content-Type"]:
                "application/octet−stream";
            var dataScheme="data:"+contentType+
                ";base64,"+btoa(
                    res.responseText.replace(
                        /[\u0100-\uffff]/g,
                        function(c){
                            return String.fromCharCode(c.charCodeAt(0)&0xff);
                        }
                    )
                );
            getCanvas(dataScheme);
        }

        var getData=function(url){
            console.log(url)
            data.url=url;
            GM_xmlhttpRequest(
                {
                    "method":"GET",
                    "url":data.url,
                    "onload":loadDataMethod,
                    "onerror":loadDataMethod,
                    "overrideMimeType":"text/plain; charset=x-user-defined"
                }
            );
        }

        var data={};

        var getFileByDataScheme=function(url,callback){
            data.callback=callback;
            getData(url);
        }
        
         var handler=function(url,callback){
             (function(){
                 getFileByDataScheme(url,callback);
             })();
         }
         function getCanvas(resScheme){
              //Canvas要素を準備
              var canvas=document.createElement("canvas");
              //画像オブジェクトの準備
              var img=new Image();
              img.src=resScheme;
               //画像の描画
              var cx=canvas.getContext("2d");
              cx.drawImage(img,0,0);

              //画像データの取得とボディへの挿入
              var dataScheme=canvas.toDataURL("image/png");
              data.callback(dataScheme);
            }
         handler(url,callback); 
 }
XMLHttpRequestでファイルをDataSchemeで取得する実験 その3 (Kanasansoft Web Lab.)
http://www.kanasansoft.com/weblab/2009/04/xmlhttprequestdatascheme_3.html


画像をDataURIに変換するブックマークレット
javascript: (function () {
    var elem = document.images[0];
    var canvas = document.createElement('canvas');
    canvas.width = elem.width;
    canvas.height = elem.height;
    elem.parentNode.insertBefore(canvas, elem);
    var ctx = canvas.getContext("2d");
    ctx.drawImage(elem, 0, 0);
    elem.parentNode.replaceChild(document.createTextNode(canvas.toDataURL("image/png")), elem);
    canvas.parentNode.removeChild(canvas);
})();

replaceChildの注意点
2009/09/21(月) 21:16 Javascriptはてブ情報 はてブに登録 はてブ数

FirefoxはreplaceNodeはないので、replaceChildを使用する。
element.replaceChild - MDC
https://developer.mozilla.org/ja/DOM/element.replaceChild

replaceChildはある子ノードを置換するものですが、forなどで回していくときに注意する必要がル。
普段のように上から走査してreplaceChildでノードを書き換えていくと、一つ飛んだ形で置換が行われてしまいます。奇数目のノードしか置換されない。
var iframes = document.getElementsByTagName("iframe");
for (var i = 0; i < iframes.length; i++) {
	if (iframes[i].hasAttribute("src")) {
		var iframeURL = iframes[i].getAttribute("src");
		if (/nicovideo\.jp\/thumb(\/|\?v=)(\w+)/.test(iframeURL)) {
			var mId = RegExp.$2;
			var imgTag = document.createElement("img");
			imgTag.src = "http://niconail.info/" + mId;
			var aNode = document.createElement("a");
			aNode.href = "http://www.nicovideo.jp/watch/" + mId;
			aNode.appendChild(imgTag);
			var parentIframe = iframes[i].parentNode;
			parentIframe.replaceChild(aNode, iframes[i]);
		}
	}
}
あんまり詳しく調べてませんが、これはreplaceChildで書き換えをしたときにノードにずれができてしまうため、望んだ結果が起こらなくなっている。
これを回避するにはforを後ろから回してreplaceChildで置換していくと回避できる。
var iframes = document.getElementsByTagName("iframe");
for (var i = iframes.length - 1; i >= 0; i--) {
	if (iframes[i].hasAttribute("src")) {
		var iframeURL = iframes[i].getAttribute("src");
		if (/nicovideo\.jp\/thumb(\/|\?v=)(\w+)/.test(iframeURL)) {
			var mId = RegExp.$2;
			var imgTag = document.createElement("img");
			imgTag.src = "http://niconail.info/" + mId;
			var aNode = document.createElement("a");
			aNode.href = "http://www.nicovideo.jp/watch/" + mId;
			aNode.appendChild(imgTag);
			var parentIframe = iframes[i].parentNode;
			parentIframe.replaceChild(aNode, iframes[i]);
		}
	}
}

Emeditorのjavascript自動補完を強化する
2009/09/21(月) 14:06 Emeditorはてブ情報 はてブに登録 はてブ数

Emeditorの標準プラグインに[単語補完] (Word Complete) がありますが、デフォルトでもある程度の単語は補完してくれますが、ちょっと足りない気がするので。
javascriptとDOM関係の用語も補完できるように辞書ファイルを追加して使います。
辞書ファイルを適当なところに保存して、[単語補完] (Word Complete)のプロパティからこの辞書ファイルを参照するようにすれば補完候補として追加されます。
ss-2009-09-21-13-51-29.png

以下のような動作になります。


元ネタとなってるファイル
拡張lisp/javascript-mode - XyzzyWiki
http://xyzzy.s53.xrea.com/wiki/index.php?%B3%C8%C4%A5lisp%2F...

1: てれぱんだ 『補完が便利になりました!ありがとうございます。 ところで、辞書ファイルのリンク先が404を返します。 https://raw.g...』 (2011/06/08 21:32)