サイトマップ

JavaScriptコードスニペット:Javascriptコンソール

FireFoxでFirebugを使ったり、Safariでは標準で用は足りるのですが、IEでもちょっとしたスクリプトを試したり、ページ上のオブジェクトを調べたりするのにJavaScriptのシェルのようなものがあれば便利かと思って作りました。

Firebug Lite1)なんてものもあって、それはそれで凄いのですが、自分のプアなマシンでは重たすぎてよほどのことがないと起動する気になれませんが、この程度なら気軽に立ち上げられます。そして、CSSセレクタでDOMオブジェクトを取り出せるようにしたので、場合によってはFirebugのDOMツリーをドリルダウンするより手軽で便利な場合もあります。

[console]←クリックすると小ウインドウが表示され、JavaScriptのコンソールが表示されます。使い方はコンソール上で'help'と入力してください。bookmarklet化してあるので、ブックマーク(お気に入り)に登録しておくと、任意のWebページ上で実行可能です。
//Firebugのwindow.consoleはreadonlyなので上書きされません。
window.console = new @INCLUDE(console.js);
console.js
/*
 * console.js - Firebug console emulator
 * 依存するライブラリ:
 *	event.js, window.js, style.js queryselector.js
 */
function() {
	var bind = function(obj, fn) {
		return function() { return fn.apply(obj, arguments); }
	};
	var fixEvent = @INCLUDE(event.js);
	var parse = function(str) {
		if (typeof str != 'string') return true;
		var stack = new Array();
		stack.match = function(ch, expect) {
			/*if (this.length == 0) {
				return false;
			} else */
			if (this.length > 0 && expect == this[this.length - 1]) {
				this.pop();
				return true;
			} else {
				this.push(ch);
				return false;
			}
		};
		for (var i = 0; i < str.length; i++) {
			switch(str.charAt(i)) {
			case '\\': break;
			case "'": stack.match("'", "'"); break;
			case '"': stack.match('"', '"'); break;
			case '(': stack.push('('); break;
			case ')': stack.match(')', '('); break;
			case '[': stack.push('['); break;
			case ']': stack.match(']', '['); break;
			case '{': stack.push('{'); break;
			case '}': stack.match('}', '{'); break;
			}
		}
		if (stack.length == 0) return true;
		else return false;
	};
 
	/* properties */
	this.title = 'console';
	this.width = 400;
	this.height= 300;
	this.content = document.createElement('ul');
	this.content.className = this.content.styleClass = 'console';
	this.window = new @INCLUDE(window.js)(this);
 
	/* style */
	this.style = (@INCLUDE(style.js))(
		"ul.console {" +
		"	font-family:monospace;" +
		"	word-wrap:break-word;" +
		"	list-style-type:none;" +
		"	margin:0;" +
		"	padding:0;" +
		"	text-align:left;" +
		"	color:black;" +
		"}" +
		"ul.console li.prompt span {" +
		"	outline:none;" +
		"}"
	);
 
	/* history */
	this.history = new Array();
	this.history.mark = 0;
	this.history.add = function(src) {
		this.push(src);
		this.clearMark();
	};
	this.history.clearMark = function() {
		this.mark = this.length;
	};
	this.history.prev = function() {
		if (this.length == 0) {
			return;
		} else if (this.mark > 0) {
			return this[--this.mark];
		} else {
			this.mark = 0;
			return this[0];
		}
	};
	this.history.next = function() {
		if (this.length == 0) {
			return;
		} else if (this.mark == this.length - 1) {
			return this[this.mark];
		} else if (this.mark < this.length) {
			return this[++this.mark];
		} else {
			this.mark = this.length - 1;
			return this[this.mark];
		}
	};
	this.history.toString = function() {
		var result = [];
		for (var i = 0; i < this.length; i++)
			result.push((i+1) + '. ' + this[i]);
		return result.join("\n");
	};
 
	/* functions */
	this.onunload = bind(this, function() {
		this.style.parentNode.removeChild(this.style);
	});
	this.clear = bind(this, function() {
		this.content.innerHTML = '';
		this.prompt();
	});
	this.log = bind(this, function(msg) {
		var line = this.content.appendChild(document.createElement('li'));
		var lines = typeof msg == 'string' ? msg.split("\n") : [msg];
		for (var i = 0; i < lines.length; i++) {
			line.appendChild(document.createTextNode(lines[i]));
			line.appendChild(document.createElement('br'));
		}
		return msg;
	});
	this.onmouseover = function(evt) {
		evt = fixEvent(evt);
		evt.preventDefault();
		evt.stopPropagation();
		if (this.commandLine) this.commandLine.focus();
		return false;
	};
	this.prompt = bind(this, function() {
		var line = this.content.appendChild(document.createElement('li'));
		line.className = line.styleClass = 'prompt';
		var prefix = line.appendChild(document.createElement('span'));
		prefix.innerHTML = 'js&gt;';
		var cmd = this.commandLine = line.appendChild(document.createElement('span'));
		cmd.console = this;
		cmd.contentEditable = true;
		cmd.onkeydown = bind(cmd, function(evt) {
			evt = evt ? evt : window.event;
			var console = this.console;
			var src = this.textContent || this.innerText;
			switch (evt.keyCode) {
			case 13: //\n
				if (src && !parse(src)) {
					var br = this.appendChild(document.createElement('br'));
					var empty = this.appendChild(document.createElement('span'));
					empty.appendChild(document.createTextNode("\n "));
					empty.style.height = '1em';
					empty.style.width = '0';
					this.moveLast();
					return true;
				} else if (src) {
					this.contentEditable = false;
					console.log(this.console.execute(src.replace(/\n>/g, "\n")));
					console.prompt();
					console.history.add(src);
					return false;
				} else {
					this.contentEditable = false;
					console.prompt();
					console.history.clearMark();
					return false;
				}
				break;
			case 27: //ESC
				console.clear();
				break;
			case 38: //UP ARROW
				var prev = console.history.prev();
				if (prev) this.innerHTML = prev;
				break;
			case 40: //DOWN ARROW
				var next = console.history.next();
				if (next) this.innerHTML = next;
				break;
			}
			return true;
		});
		cmd.moveLast = function() {
			window.getSelection().selectAllChildren(this);
			var range = window.getSelection().getRangeAt(0);
			range.setStart(range.endContainer, range.endOffset);
		};
		cmd.focus();
	});
	this.execute = bind(this, function(src) {
		try {
			if (src == null || src.match(/^\s*$/)) return "";
			var result = this.scope.exec(src);
 
			switch(typeof result) {
			case 'function':
				return 'function';
			case 'string' :
			case 'undefined':
			case 'null'    :
				return result;
			default:
				if (result && typeof result.toString === 'function')
					return result.toString();
				else
					return result;
			}
		} catch (e) {
			return e + ":" + src;
		}
	});
 
	this.dir = bind(this, function(obj) {
		var result;
		if (typeof(obj) == 'object' &&
		    typeof(obj.length) == 'number' && 
		    typeof(obj.shift) == 'function') {
			//maybe array
			var str = "[";
			var sep = "";
			for (var i = 0; i < obj.length; i++) {
				str += sep + obj[i];
				sep = ", ";
			}
			str += "]";
			result = str;
		} else if (typeof(obj) == 'object') {
			//object
			var str = "{";
			var keys = [];
			for (var key in obj) {
				keys.push(key);
			}
			keys = keys.sort();
			var sep = "";
			for (var i = 0; i < keys.length; i++) {
				if (!keys[i]) continue;
				try {
					var val = obj[keys[i]];
					if (val) str += sep + keys[i] + "=" + val;
				}catch(e){}
				sep = ",";
			}
			str += "}";
			result = str;
		} else if (typeof(obj) == 'function') {
			result = obj.toString();
		} else if (typeof(obj) == 'string') {
			result = obj;
		} else {
			result = obj;
		}
		self.log(result);
	});
 
	/* scope */
	var self = this;
	this.scope = new function() {
		var version = '2011-07-27';
		var help = [
			"* スクリプト+ENTERで式を評価",
			"* ESCで画面クリア\n* ↑↓で履歴を見る",
			"* help .. このヘルプを表示する",
			"* version .. バージョン",
			"* history .. 履歴の一覧",
			"* $(query) .. セレクタqueryに一致する要素を取り出す",
			"* log(msg) .. msgを出力する",
			"* dir(obj) .. objを調べる",
			"* exit() .. この画面を終了する"
			].join("\n");
		var $ = @INCLUDE(queryselector.js);
		var log = self.log;
		var dir = self.dir;
		var history = self.history;
		var grep = function(pattern, obj) {
			var result = [];
			var expr = new RegExp(pattern, 'i');
			for (var key in obj) {
				if (key.match(expr)) result.push(key);
			}
			return result.join("\n");
		};
		var exit = bind(self.window, self.window.exit);
		this.exec = bind(this, function(src) {
			return eval(src);
		});
	};
 
	this.prompt();
}

関連コンテンツ

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