slide.js 6日目

今回のポイント

  • #next()と#prev()を汎化させて#loadPage()を作った

 #next()と#prev()ではページ番号のインクリメント・デクリメント?だけして
 loadPageでそのページ番号に対応する配列インデックスをロード(style切り替え)

  • titleを取得してid=headerなdivに埋め込み
  • nextなどのボタンを下部につけた
  • cssのグリッドレイアウトに苦しむ(;´Д`)

 でもスライドショーっぽくなってきた!

  • エフェクト系を調べ始め、FishEyeエフェクトを改変してみた(コードの整理してないからHTMLに直書)
  • script.aculo.usのeffectにあるHighLightもつけてみたが、つけてみただけorz

slide.js

/*
 * slide.js
 * @version:	2007/05/09
 * @author:		futa23
*/

// Slide class
function Slide() {
    this.initialize.apply(this, arguments);
}

Slide.prototype.initialize = function() {
	this.header;
	this.contents = new Array();	
	this.page = 0;
	//deafult: false(normal mode)
	this.mode = false;
};

Slide.prototype.start = function(){

	//neglect slide mode
	if (this.mode) {
		return;
	}
	
	//change mode
	this.mode = true;
		
	//create header, footer into body
	document.getElementById('body').innerHTML
		= '<div id=\"header\" class=\"header\">header</div>'
			 + document.getElementById('body').innerHTML
			 + '<div id=\"footer\" class=\"footer\">'
			 + '<a href=\"#\" onClick=\"javascript:Modalbox.show(\'slide.js -help-\'\, \'slide/help.html\'\, {width: 460\, height:400})\;return false\;\">(h)elp</a>'
			 + '<input type=\"button\" value=\"start!\" id=\"startBtn\" onclick=\"slide.start()\" disable>'
			 + '<input type=\"button\" value=\"prev!\" id=\"prevBtn\" onclick=\"slide.prev()\" disable>'
			 + '<input type=\"button\" value=\"next!\" id=\"nextBtn\" onclick=\"slide.next()\"></div>';
	
	//store slide base element on memory
	this.header = document.getElementById('header');
	
	//change startBtn button disable
	if (document.getElementById('startBtn')) {
//		document.getElementById('startBtn').value = 'quit!';
//		document.getElementById('startBtn').addEventListener('onClick', slde.quit(), false);
		document.getElementById('startBtn').disabled = true;
	}
	if (document.getElementById('nextBtn')) {
		document.getElementById('nextBtn').disabled = false;
	}
	
	//load contents
	var divPages = document.getElementsByTagName('div');
	for (var i=0; i<divPages.length ; i++) {
		if (divPages[i].className == 'page') {
			divPages[i].id = this.contents.length;
			this.contents.push(divPages[i]);
			
			divPages[i].className = 'hide';
		}
	}
	
	//load first page
	this.loadPage(0);
};

Slide.prototype.next = function() {
	this.loadPage(++this.page);
};

Slide.prototype.prev = function() {
	this.loadPage(--this.page);
};

Slide.prototype.loadPage = function(p) {

	if (!this.mode) {
		return;
	}

	if (0 <= p && p < this.contents.length) {
		for (var i=0; i<this.contents.length; i++) {
			this.contents[i].className = 'hide';
		}
		//for current page
		this.contents[p].className = 'main';

		//TODO
		if (typeof Effect != 'undefined') {
			new Effect.Highlight(document.getElementById(p), {duration: 2});
		}

		//get title
		for(var j=0; j<this.contents[p].childNodes.length; j++) {
			if (this.contents[p].childNodes[j].className
				 && this.contents[p].childNodes[j].className == 'title') {
//				alert(this.contents[p].childNodes[j].innerHTML);
				this.header.innerHTML = this.contents[p].childNodes[j].innerHTML;
				break;
			}
		}

		//set inputed page to the current page.
		this.page = p;

		// change next button disable
		if (p == this.contents.length - 1){
			if (document.getElementById('nextBtn')){
				document.getElementById('nextBtn').disabled = true;
			}			
		}
		// change prev button disable
		if (p == 0){
			if (document.getElementById('prevBtn')){
				document.getElementById('prevBtn').disabled = true;
			}			
		}else {
			if (document.getElementById('prevBtn')){
				document.getElementById('prevBtn').disabled = false;
			}
		}
	}else{
		this.quit();
	}
};

Slide.prototype.quit = function() {
	if (!this.mode) {
		return;
	}

	for(var i=0; i<this.contents.length; i++) {	
		this.contents[i].className = 'page';
		this.contents[i].removeAttribute('style');
	}

	//remove header
	document.getElementById('body').removeChild(this.header);
	//remove footer
	document.getElementById('body').removeChild(document.getElementById('footer'));
	
	this.initialize();

	if (document.getElementById('startBtn')){
			document.getElementById('startBtn').disabled = false;
	}
	if (document.getElementById('nextBtn')){
			document.getElementById('nextBtn').disabled = false;
	}
};

//app
var slide = new Slide();

呼び出すhtml側

<html>
<head>
<title>slide.js</title>

<link rel="stylesheet" type="text/css" href="includes/modalbox.css" media="screen" />
<link rel="stylesheet" type="text/css" href="slide/slide.css"/>

<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=UTF-8">

<!--help-->
<script type="text/javascript" src="includes/prototype.js"></script>
<script type="text/javascript" src="includes/scriptaculous.js"></script>
<script type="text/javascript" src="includes/modalbox.js"></script>
<script type="text/javascript" language="JavaScript" charset="utf-8" src="FishEye.js"></script>

<script type="text/javascript" language="JavaScript" charset="utf-8" src="shortcuts.js"></script>
<script type="text/javascript" language="JavaScript" charset="utf-8" src="slide.js"></script>

<script type="text/javascript">
<!--
	//add keybind
	shortcut('s', function(){slide.start();});
	shortcut('left', function(){slide.prev();});
	shortcut('right', function(){slide.next();});
	shortcut('space', function(){slide.next();});
	shortcut('q', function(){slide.quit();});
	shortcut('h', function(){
						Modalbox.show(
							'slide.js -help-', 
							'slide/help.html', 
							{width: 460, height:400}
							);
						return false;
					}
			);
-->
</script>

</head>

<body id="body" bgcolor="#FFFFFF" text="#003366" link="#3399FF" vlink="#99CCFF" alink="#FF3333">

<div class="page">
	<h3 class="title">自己紹介</h3>
	<ul>
		<li >名前:futa23
		<li>職業:SEでもプログラマーでもないIT系
		<li>装備:Java(普通に), PHP(並以下), Perl(並以下), Ruby(初心者)
	</ul>
</div>

<div class="page">
	<h3 class="title">slide.jsを作るきっかけ</h3>
	<ul>
		<li>oopなJavaScriptを書いてみたかった。
		<li>作るなら実用的なもの。
		<li>他のライブラリも使ってエフェクトも掛けたい。
		<li>ショートカット厨なので、ショートカット機能は必須実装機能。
		<li>HTML表示モードとプレゼンモードの切り替えができるように。
	</ul>
</div>

<div class="page">
	<h3 class="title">slide.jsのショートカット一覧</h3>
	<ul>
		<li><strong>s</strong> --- start slide show
		<li><strong>right(→) or space</strong> --- go to next page
		<li><strong>left(←)</strong> --- go to previous page
		<li><strong>q</strong> --- quit slide show
		<li><strong>h</strong> --- show this help page
		<li><strong>esc</strong> --- close this help page
	</ul>
</div>

<script type="text/javascript">
<!--
	//FishEye
	var fishEye = new FishEye(
					{'large':'3em', 'medium':'2em', 'regular':'1em'}
					, {'target': 'li'}
				);
	targets = document.getElementsByTagName('li');
	for(var i=0; i<targets.length; i++) {
//		alert(targets.length);
		targets[i].addEventListener('onmouseover', this.bigger ,true);
		targets[i].addEventListener('onmouseout', this.normal ,true);
	}
-->
</script>
</body>
</html>

css

/* header */
#header{
	height:15%;
	width:100%;
	background-color:#4a617b;
	margin:0px;
	padding:0.5em 0.7em 0em 1em;/*top right bottom left */
	color:#ffffff;
	font-size:2em;
	font-weight:bold;
	vertical-align:middle;
}

/* current page */
.main{
	height:77%;
	width:100%;
	font-size:1.5em;
	background-color:#eeeeee;
	border:0px;
	border-top:#FFFFFF 0px solid;
	margin:0px;
	padding:1.5em 1em 0em 1em;/*top right bottom left */
	/*行間隔*/
}

/* current page's title */
.main .title{
	display:none;
}

/* footer */
#footer{
	height:8%;
	width:100%;
	background-color:#314051;
	border-top:#FFFFFF 0px solid;
	margin:0px;
	padding:0.1em 0em 0em 0em;/*top right bottom left */
	text-align:right;
	vertical-align:middle;
}

img{
	border:none;
}


A:link{
	color:#0ac0ff;
	text-decoration:none;
	}
A:visited{
	color:#5080e0;
	text-decoration:none;
}
A:hover{
	color:#2ae0ff;
	text-decoration:underline;
}

.hide{
	display: none;
} 

FishEye.js

おまけ。
DOMのpreviousSibling、nextSiblingを知った。
こんなシンプルに実装できるのね。感動。
FishEyeのオリジナルにオプションで引数渡せられるようにしたのと、クラス化しただけ。

/**
 * FishEye
 * by http://dannyayers.com/2003/10/fisheye.html
 * 
 * revised by futa23
 */

// FishEye class
function FishEye() {
    this.initialize.apply(this, arguments);
}

FishEye.prototype.initialize = function() {
	//default
	this.large = '3em';
	this.medium = '2em';
	this.regular = '1em';
	this.targetTagName = null;

	if(fontSize = arguments[0]) {
		if(fontSize['large']) this.large = fontSize['large'];
		if(fontSize['medium']) this.medium = fontSize['medium'];
		if(fontSize['regular']) this.regular = fontSize['regular'];
	}
//	if(option = arguments[1]) {
//		alert(option['target']);
//		if(option['target']) {
//			this.targetTagName = option['target'];
//			targets = document.getElementsByName(this.targetTagName);
//			for(var i=0; i<targets.length; i++) {
//				alert(targets.length);
//				targets[i].addEventListener('onmouseover', this.bigger ,true);
//				targets[i].addEventListener('onmouseout', this.normal ,true);
//			}
//		}
//	}
};

//function convertPreBlocks() {}

FishEye.prototype.bigger = function (thing){
	thing.style.fontSize = this.large;
	
	siblingElement = thing.previousSibling;

	while(siblingElement) {
		if(siblingElement.tagName == thing.tagName) {
			siblingElement.style.fontSize = this.medium;
			break;
		}
		siblingElement = siblingElement.previousSibling;
	}

	siblingElement = thing.nextSibling;

	while(siblingElement) {
		if(siblingElement.tagName == thing.tagName) {
			siblingElement.style.fontSize = this.medium;
			break;
		}

		siblingElement = siblingElement.nextSibling;
	}
}

FishEye.prototype.normal = function(thing){
	thing.style.fontSize = this.regular;

	siblingElement = thing.previousSibling;

	while(siblingElement) {
		if(siblingElement.tagName == thing.tagName) {
			siblingElement.style.fontSize = this.regular;
			break;
		}
		siblingElement = siblingElement.previousSibling;
	}

	siblingElement = thing.nextSibling;

	while(siblingElement) {
		if(siblingElement.tagName == thing.tagName) {
			siblingElement.style.fontSize = this.regular;
			break;
		}

		siblingElement = siblingElement.nextSibling;
	}
}

参考

JavaScriptのコード自体は初めて書いたに等しいけど、ちょこちょこ本は読んでた。
オライリーのサイ本。
レビューにもあるとおり、書かれてるJavaScriptのバージョンは古いけどためになる。
prototypeベースなオブジェクト指向の意味がわかった本。
あと、JavaScriptにおいて
連想配列JavaでいうHashMapクラスだと思っていいforJavaしか知らない人)はオブジェクト、
というかオブジェクトは連想配列なこととか、
documentクラスやwindowsクラス、for inなど基礎がたくさん載ってる名著。