slide.js 7日目

まぁ目標としていたレベルは完成したかな。
自分的にはα版まではできた。
フェードインをつけたい。
あと目次の自動生成して、クリック移動できるモーダルウィンドウ・ナビゲーターつけたら終了かな。

今回のポイント

 背景色(background-color)と文字色(color)を同じ色にして、
 クリックしたら背景色をスライドの背景色と同じに変更するだけ。
 zoom-inに至っては、cssの:hoverを使っただけ。

  • グリッドレイアウトも一応それっぽくできた

 CSS難しい。

  • ページ指定ジャンプ機能実装
  • ブラウザ互換addEventListener実装(どこからかのぱくり)
  • クラス名でDOM Elementが取れるdocument#getElementsByClassNameを実装(どこからかのぱくり)

slide.js

/*
 * slide.js
 * @version:	2007/05/10
 * @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;

	//set style sheet
	this.setStyleSheet('./slide.js/css/slide.css');

	//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="./slide.js/core/help.html?height=200&amp;width=400&modal=true" class="thickbox" title="slide.js -help-">help</a>'
			 + '<a href="#top" id="start" onclick="javascript:slide.jump(0)">top</a>'
			 + '<a href="#prev" id="prev" onclick="javascript:slide.prev()" disable>prev</a>'
			 + '<input type="text" name="jump" id ="jump" width="30px" value="1"' 
			 + 'onkeypress="javascript:if(event.keyCode == 13) {slide.jump((this.value-1));}"/>'
			 + '<span id="lastPage">/0</span>'
			 + '<a href="#next" id="next" onclick="javascript:slide.next()">next</a>'
			 + '<a href="#quit" id="quit" onclick="javascript:slide.quit()">quit</a>'
			 + '&nbsp;&nbsp;</div>';

	//store slide base element on memory
	this.header = document.getElementById('header');
			
	if (document.getElementById('next')) {
		document.getElementById('next').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';
		}
	}
	
	//set lastPage
	document.getElementById('lastPage').innerHTML = '/' + this.contents.length;

	//load first page
	this.jump(0);
};

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

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

Slide.prototype.jump = function(p) {

	if (!this.mode || typeof p == 'undefined' || isNaN(p)) 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';

		this.setEffect();

		//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 = '<span class=title>' + this.contents[p].childNodes[j].innerHTML + '</span>';
				break;
			}
		}

		//set inputed page to the current page.
		this.page = p;
		document.getElementById('jump').value = (p+1);

		// change next button disable
		if (p == this.contents.length - 1){
			if (document.getElementById('next')){
				document.getElementById('next').disabled = true;
			}			
		}
		// change prev button disable
		if (document.getElementById('prev')){
			if (p == 0){
				document.getElementById('prev').disabled = true;
			}else {			
				document.getElementById('prev').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.setStyleSheet();
	
	//change to normal-mode(not slideshow-mode)
	this.initialize();
	this.resetEffect();
};

Slide.prototype.setStyleSheet = function (sheet) {
	
	if(links = document.getElementsByTagName('link')){
		for(var i=0; i<links.length; i++) {
			if (links[i].rel == 'stylesheet' && links[i].type == 'text/css') {
				//set normal or another stylesheet enable if slideshow-mode
				if (this.mode) {
					if(links[i].title != 'slide'){
						links[i].disable = false;	
					}else {
						links[i].disable = true;
						document.getElementsByTagName('head')[0].removeChild(links[i]);	
					}; 
				}
			}
		}
	}
	
	if (sheet) {
		linkTag = document.createElement('link');
		linkTag.setAttribute('title', 'slide');
		linkTag.setAttribute('rel', 'stylesheet');
		linkTag.setAttribute('type', 'text/css');
		linkTag.setAttribute('href', sheet);
		
		document.getElementsByTagName('head')[0].appendChild(linkTag);
	}
};

Slide.prototype.setEffect = function() {
	//TODO
	//fade-in
	
	//monta
	var montas = document.getElementsByClassName('monta');
	for(var i=0; i<montas.length; i++) {
		montas[i].setAttribute('style', 'z-index:10');
		addEventListener(montas[i], 'click', 
						function() {
							this.className = 'monta-off';
						});
	}
	
};

Slide.prototype.resetEffect = function() {
	//monta-off
	var montas = document.getElementsByClassName('monta-off');
	for(var i=0; i<montas.length; i++) {
		montas[i].className = 'monta';
	}
};

/**
 * general eventListner
 * @param {Object} target
 * @param {Object} type
 * @param {Object} func
 * 
 * @usage:addEventListner(obj, 'click', func1);
 */
function addEventListener(target, type, func) {
  if(target.attachEvent) {
    target.attachEvent("on" + type, func);
  } else if(target.addEventListener) {
    target.addEventListener(type, func, true);
  } else {
    target["on" + type] = func;
  }
}

/**
 * 
 * @param {Object} className
 */
document.getElementsByClassName = function(className) {
	var elementsAll = document.getElementsByTagName('*') || document.all;
	var elements = new Array();
	for(var i = 0; i < elementsAll.length; i++) {
		var classNames = elementsAll[i].className.split(' ');
		for(var j = 0; j < classNames.length; j++) {
			if (classNames[j] == className) {
				elements[elements.length] = elementsAll[i];
				break;
			}
		}
	}
	return elements;
}

//app
var slide = new Slide();

呼び出すHTML

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

<link rel="stylesheet" type="text/css" href="./slide.js/css/normal.css"/>

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

<!--help-->
<script type="text/javascript" src="./slide.js/plugins/FishEye.js"></script>

<script type="text/javascript" language="JavaScript" charset="utf-8" src="./slide.js/plugins/shortcuts.js"></script>
<script type="text/javascript" language="JavaScript" charset="utf-8" src="./slide.js/core/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();});
-->
</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>

<div class="page">
	<h3 class="title">class指定でできるエフェクト</h3>
	<ul>
		<li class="fishEye">li.fishEye --- FishEyeメニュー
		<li>monta --- <span class="monta">もんたメソッド</span>
		<li>zoom-in --- <span class="zoom-in">拡大</span>
	</ul>
</div>

</body>
</html>

slide.css

z-indexっていうオーバーレイ表現でよく使う属性を初めて使った。
これでモーダルウィンドウ実装するのね。なるほど。

*{
	margin:0px;
	border:0px;
	font-family:MeiryoKe_Pgothic, メイリオ, Osaka, Arial, Helvetica, sans-serif;
}

#body{
	height:100%;
	width:100%;
	background-color:#c4daa3;
}

/* header */
#header{
	height:2em;
	color:#003366;
	background-color:#c4daa3;	
	margin:0px;
	padding:1em 0.7em 0em 1em;/*top right bottom left */
	font-weight:bolder;
	font-size:2.5em;
	vertical-align:text-bottom;
}

#header .title{
	border-bottom:0.2em solid;
	width:80%;
	border:solid #50682b;
 	border-width:0 0 1px 12px;
 	padding:0.4em 0.4em;	
}

/* current page */
.main{
	font-size:1.5em;
	font-weight:bold;
	color:#003366;
	background-color:#c4daa3;
	border:0px;
	border-top:#FFFFFF 0px solid;
	margin:0px;
	padding:0.2em 0.5em 0em 1em;/*top right bottom left */
	line-height:40px;
}

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

.main ul, .main ol{
	padding-left:2em;
}

/* footer */
#footer {
	position:absolute;
	bottom:0px;
	z-index:10; 
	width:100%;
	background-color:#314051;
	border-top:#FFFFFF 0px solid;
	padding:0.1em 0em 0.1em 0em;/*top right bottom left */
	text-align:right;
	vertical-align:middle;;
	color:#ffffff;
	font-size:1em;
}

#footer input{
	margin-left:10px;
	width:30px;
}

img{
	border:none;
}

A{
	margin-left:10px;
}

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

/* effect */
.hide{
	display: none;
} 

.main li.zoom-in:hover{
	font-size:2em;
}

.main .monta {
	background-color:yellow;
	color:yellow;
}

.main .monta-off{
	
}

normal.css

normal.css(スライドモードじゃないとき)はてきとーに書いてOK

body{
	background-color:#ffffff;
	color:#003366; 	
}

div.page{
	padding-left:3em;
	padding-top:2em;
}

div.page ul, div.page ol{
	padding-left:3em;
}

div.page.h1, div.page.h2, div.page.h3, div.page.h4, div.page.h5{
	padding-left:0em;
}