JavaScript - LinkedList, nodeType(재귀), Event 핸들러, DOM

|
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>0910 실습</title>
<style>
	.cls1{
		color: red;
	}
</style>

<script type="text/Javascript">

/* 0910실습 */
function LinkedList(){ // stack 생성자 함수
	var list = function(a){
		this.a = a;
		this.next = null; // 다음
	};
	var head = null; // 머리
	var length = 0; // 연결리스트에 담긴 데이터의 갯수
	
	this.append = function(a){ // 마지막에 삽입
		var node = new list(a), current; // current는 마지막 node
	
		if(head == null){ // 머리가 없으면
			head = node;  // 머리가 노드
		} else { // 머리가 있으면
			current = head; //
			while(current.next != null){ // 마지막 원소를 발견할 때까지 루프 순환
				current = current.next;
			}
			current.next = node; // 마지막 원소를 링크할 수 있게 다음 노드에 할당.
		}
		length++; // 리스트의 크기를 업데이트 한다.
	}; 
	
	this.insert = function(pos, a){ // 특정 index에 추가
		// index가 개입되면 범위체크는 필수
		if(pos>=0 && pos <= length){ // 범위 이외의 값인지 체크한다.
			var node = new list(a),
			current = head,
			pre, index=0;
			if(pos === 0){ // 첫번째로 추가
				node.next = current; // 리스트의 중간 또는 맨끝에 추가하는 경우
				head = node; // 머리가 노드
			} else { // 머리가 있으면
				while(index++ < pos){
					prev = current;
					current = current.next;
				}
				node.next = current;
				prev.next = node;
			}
				length++;
				return true;
			} else {
				return false;
		}
	}; 
	
	this.removeAt = function(pos){ // 데이터 위치를 기준으로 삭제 
			if(pos>=0 && pos <= length){ // 범위 이외의 값인지 체크한다.
				var current = head,
				pre, index=0;
				if(pos === 0){ // 첫번째 원소 삭제
					head = current.next;
				} else {
					while(index++ < pos){
						prev = current;
						current = current.next;
					}
					prev.next = current.next; // 현재의 다음 과 이전을 연결: 삭제하기 위해 건너뜀.
				} 
					length--;
					return current.a;
				} else {
					return null;
			}
	}; 
	
	this.remove = function(a){ // 데이터값을 기준으로 삭제
		var index = this.indexOf(a);
		return this.removeAt(index);
	};
	
	this.indexOf = function(a){ // value의 index를 리턴
		var current = head, index = 0;
		while(current){
			if(a === current.a){
				return index;
			}
			index++;
			current = current.next;
			}
		return -1;
	};
	
	this.toString = function(){
 		var current = head, str = '';
 		while(current){
 			str += current.a;
 			current = current.next;
 		}
        return str;
    };
	
	this.print = function(){
		var current = head, str = '';
		if(head == null){
			console.log("출력할 리스트가 존재하지 않습니다.");
		} else {
			str += '[';
			while(current.next != null){
				str += current.a + " ";
				current = current.next;
			}
			str += current.a;
			str += ']';
			console.log(str);
		}
	};
}

// 1. LinkedList 객체를 만들기
function question1(){
	var list = new LinkedList();
	list.append(15); // 맨뒤에 추가
	list.print(); // = 15
	console.log(list.indexOf(15)); // value의 index를 리턴    = 0
	list.append(10); // 15 10
	list.print(); // 15 10
	console.log(list.indexOf(10)); // 1
	list.append(13); // 15 10 13
	list.print(); // 15 10 13
	console.log(list.indexOf(13)); // 2
	console.log(list.indexOf(10)); // 1
	list.append(11); // 15 10 13 11
	list.append(12); // 15 10 13 11 12
	list.print(); // 15 10 13 11 12
	console.log(list.removeAt(1)); // 특정 index를 삭제   여기서  15=0 10=1  10을 삭제한다
	list.print() //15 13 11 12
	console.log(list.removeAt(3)); // 12를 삭제한다. 
	list.print(); // 15 13 11
	list.append(14); // 15 13 11 14
	list.print(); //15 13 11 14
	list.insert(0, 16); // 특정 index에 추가  0번째에 16을 추가한다
	list.print(); // 16 15 13 11 14
	list.insert(1, 17); // 1번째에 17을 추가한다.
	list.print(); // [16 17 15 13 11 14]
}


/* nodeType */
// 노드가 요소, 텍스트, 속성 중 어느 타입의 노드인지를 리턴
// 요소노드 : 1, 속성노드 : 2, 텍스트노드 : 3
//DOM예제
function myFunction(){
	var textnode = document.createTextNode("Water");
	var item = document.getElementById("myList").childNodes[0]; // childNodes 어레이 리턴
	item.replaceChild(textnode, item.childNodes[0]);
	// child를 바꿔라 / textnode : new / item.childNodes[0] : old
	// child가 water로 바뀜
}

// 문서의 노드순회
function countTags(n){
	var numtags = 0;
	if(n.noteType == 1) // 요소노드냐?
		numtags++; 
	var children = n.childNodes;
	for(var i=0; i<children.length; i++){
		numtags+= countTags(children[i]); // recursive 재귀호출
	}
	return numtags;
}

// 노드 아래의 모든 텍스트 얻기
// text노드를 이어 붙이고 문자열로 반환
function getText(n){
	var strings = [];
	getStrings(n, Strings);
	return strings.join(" ");
	function getStrings(n, strings){
		if(n.nodeType == 3){ // textnode면 push
			strings.push(n.data);
		}else if(n.nodeType == 1){ // 요소노드면 첫번째 자식을 찾고
			for(var m= n.firstChild; m!=null; m=m.nextSibling){ // 다음 노드를 찾으면서 재귀호출
            // 
				getStrings(m, strings);
			}
		}	
	}
}

/*Event 예제*/
function test1(){ // c b a ( 자식노드 -> 부모노드, 기본값 false)
	document.getElementById('a').addEventListener('click',function(){console.log('a')});
	document.getElementById('b').addEventListener('click',function(){console.log('b')});
	document.getElementById('c').addEventListener('click',function(){console.log('c')});
}
function test2(){ // a b c ( 부모노드 -> 자식노드, true)
	document.getElementById('a').addEventListener('click',function(){console.log('a')}, true);
	document.getElementById('b').addEventListener('click',function(){console.log('b')}, true);
	document.getElementById('c').addEventListener('click',function(){console.log('c')}, true);
}
function test3(){ // c b (stopPropagation : 이벤트 전파차단)
	document.getElementById('a').addEventListener('click',function(){console.log('a')});
	document.getElementById('b').addEventListener('click',function(evt){evt.stopPropagation(); console.log('b')}); // 이후부터 이벤트차단
	document.getElementById('c').addEventListener('click',function(){console.log('c')});
}

/*이벤트 핸들러 추가하기*/
// onload 후에 추가하고자 하는 메소드가 있을 경우엔 다음과 같이 처리할 수 있다.
window.onload = prepareGallery; // 하나의 함수등록
window.onload = function(){ // 함수가 여러개일때
	firstFunction();
	secondFunction();
}
// 위의 소스는 실체 onload와 연결된 소스를 함수가 추가될 때마다 수정해주어야한다.
// 이에 대한 해결책으로 addLoadEvent 기법을 사용하면 좋다
// ★★★★ 모든 브라우저에서 사용 가능한 이벤트 핸들러 등록방식 - 많이 응용해서 쓰인다. ★★★★
function addLoadEvent(func){
	var oldonload = window.onload; // onload event에 연결된 메소드를 얻어온다.
	if(typeof window.onload !='function'){ // type이 function이 아니면, onload에 연결된 함수없으면
		window.onload = func; // 다른 function이 연결되어 있지 않으므로 그냥 연결
	} else {
		window.onload = function(){
			oldonload(); // 이전에 onload에 연결되었던 func를 호출한다.
			func();
		}
	} 
}
addLoadEvent(firstFunction);
addLoadEvent(secondFunction);


/*실행시에 마크업 코드 생성하기 - DOM사용*/
// 실습예제 : <p>이것은<em>텍스트</em>입니다.</p>
var para = document.createElement("p");
var txt1 = document.createTextNode("이것은");
console.log(para.appendChild(txt1)); // 이것은

var emphasis = document.createElement("em");
var txt2 = document.createTextNode("텍스트");
console.log(emphasis.appendChild(txt2)); //텍스트
console.log(para.appendChild(emphasis)); // <em>텍스트</em>

var txt3 = document.createTextNode("입니다.");
console.log(para.appendChild(txt3)); // 입니다.

/*DOM예제2*/
function test(){
	var sp1 = document.createElement("span");
	var sp2 = document.getElementById("childElement");
	var parentDiv = sp2.parentNode;
	parentDiv.insertBefore(sp1, sp2); // 앞에 span 태그 생김.
}

function test4(){
	var myobj = document.getElementById("demo");
	myobj.remove(); // 노드제거 
}

function test5(){
	document.getElementsByTagName("H1")[0].removeAttribute("class"); // 속성제거
}

function test6(){
	var list = document.getElementById("myList2");
	list.removeChild(list.childNodes[0]); // child제거
}

/*DOM 문제 - 모든 textNode의 데이터를 대문자로 변경*/
function upcase(n){
	if(n.nodeType == 3){ // 노드가 text노드이면 텍스트를 대문자로 바꾼다.
		n.data = n.data.toUpperCase(); // data 대신 value로 써도됨.
	} else { // 현재 노드가 text노드가 아니면 각 자식에 대해 재귀적으로 호출
		var kids = n.childNodes;
		for(var i=0; i<kids.length; i++)
			upcase(kids[i]);
	}
}

/* CSS와 DOM연동하기 -  특정 노드에 style 주기*/
function styleHeaderSiblings(){
	if(!document.getElementsByTagName) return false;
	var headers = document.getElementsByTagName("h1"); // 모든 h1 tag를 얻는다.
	for(var i=0; i<headers.length; i++){
		//첫번째 요소노드에 css지정
		var elem = getNextElement(headers[i].nextSibling); // nextSibling -> 다음 요소노드로 이동
		elem.style.fontWeight = 'bold';
		elem.style.fontSize = "1.2em";
	}
}
//다음 요소노드가 나올 때까지 재귀호출
function getNextElement(node){
	if(node.nodeType == 1)
		return node;
	if(node.nextSibling){
		return getNextElement(node.nextSibling);
	}
	return null;
}

/* CSS와 DOM연동하기 - 반복되는 style 주기 - 목록 중 짝수 번째 항목에 style을 지정*/
function stripeTables(){
	if(!document.getElementsByTagName) return false;
	var tables = document.getElementsByTagName("table"); // 모든 table에 대해서
	for(var i=0 ; i< tables.length; i++){
		var odd = false;
		var rows = tables[i].getElementsByTagName("tr"); // table내 모든 tr에 대해서
		for(var j=0; j<rows.length; j++){
			if(odd == true){ // 짝수이면 backcolor를 변경한다.
				rows[j].style.backgroundColor = "#ffc";
				odd = false;
			} else {
				odd = true;
			}
		}
	}
}

/* DOM예제 3 - Tooltip*/
var toolTip = new Tooltip();

function show(){
	toolTip.show('ToolTip입니다', 100, 100);
}

function hide(){
	toolTip.hide();
}

function Tooltip(){
	this.tooltip = document.createElement("div");
	this.tooltip.style.position = "absolute";
	this.tooltip.style.visibility = "hidden"; // hidden상태로 시작
	this.tooltip.className = "tooltipShadow"; // css 조작할 수 있게 css클래스 이름 지정
	
	this.content = document.createElement("div"); // 내용 부분을 위한 div생성
	this.content.style.position = "relative"; // 상대 위치로 지정
	this.content.className = "tooltipContent";
	
	this.tooltip.appendChild(this.content); // 그림자 위에 내용을 추가
}

Tooltip.prototype.show = function(text, x, y){
	this.content.innerHTML = text; // tooltip의 text 설정
	this.tooltip.style.left = x + 'px';
	this.tooltip.style.top = y + 'px';
	this.tooltip.style.visibility = 'visible'; // 보이게 한다.
	//아직 툴팁이 문서에 추가되지 않았다면 이를 문서에 추가한다,
	if(this.tooltip.parentNode != document.body){
		document.body.appendChild(this.tooltip);
	}
};

Tooltip.prototype.hide = function(){
	this.tooltip.style.visibility = "hidden"; // 감춘다
}

/* DOM예제 4 - sun earth moon*/
window.onload = function(){
	var sun = document.getElementById('sun'); // 변수선언
	var earth = document.getElementById('earth');
	var moon = document.getElementById('moon');
	sun.style.position = 'absolute'; // 문서 객체의 스타일 속성을 변경
	earth.style.position = 'absolute';
	moon.style.position = 'absolute';
	sun.style.left = 250 + 'px';
	sun.style.top = 200 + 'px';
	var earthAngle = 0;
	var moonAngle = 0;
	setInterval(function(){ 
		var earthLeft = 250 + 150 * Math.cos(earthAngle); // 각도로 지구와 달의 좌표를 구함.
		var earthTop = 200 + 150 * Math.sin(earthAngle);
		var moonLeft = earthLeft + 50 * Math.cos(moonAngle);
		var moonTop = earthTop + 50 * Math.sin(moonAngle);
		// 위치를 이동
		earth.style.left = earthLeft + 'px';
		earth.style.top = earthTop + 'px';
		moon.style.left = moonLeft + 'px';
		moon.style.top = moonTop + 'px';
		// 각도를 변경
		earthAngle += 0.1;
		moonAngle += 0.3;
	}, 1000/30);
};




/* Event예제 - event안에 자바스크립트 코드 넣는 예제들*/
document.f1.b1.onclick = function(){alert('Thanks!!'); }

var b = document.myform.mybutton;
var oldHandler = b.onclick;
function newHandler(){
}
b.onclick = function() { oldHandler();newHandler(); }

/*예외 예제*/
try{
	try{
		throw new Error("oops");
	}
	finally{
		console.log("finally");
	}
}
	catch(ex){
		console.log("outer", ex.message);
	}

try{
	var array = new Array(9999999999);
} catch(exception){
	console.log('11: ' + exception.message);
	console.log('22: ' + exception.description);
	console.log('33: ' + exception.name);
}

try{
	try{
		throw new Error("oops");
	}
	catch(ex){
		console.log("inner", ex.message);
	}
	finally{
		console.log("finally");
	}
}
	catch(ex){
		console.log("outer", ex.message);
}

try{
	try{
		throw new Error("oops");
	}
	catch(ex){
		console.log("inner", ex.message);
	}
	finally{
		console.log("finally");
	}
}
	catch(ex){
		console.log("outer", ex.message);
	}



</script>
</head>
<body>

	<input type="button" value="LinkedList 객체를 만들기" onClick="question1()" />

	<br><br><br>
	1. DOM예제 - 줄바꿈시 childnode값 변경됨(엔터도 포함)
	<ul id="myList"><li>Coffee</li><li>Tea</li><li>Milk</li></ul> 
	<button onClick="myFunction()">Try it</button> <!-- coffee가 water로 바뀜 -->
	
	<br><br><br>
	2. 문서의 노드순회
	<!-- 
	<body onload="alert(countTags(document))">this is a <i>sample</i>document. <!-- document 문서의 최상단  -->
	 -->
	<br><br><br>
	3. event예제 
	<!-- 
	<body onload='test1()'>
	<div id='a'>a Click하세요
		<div id='b'>b Click하세요
			<div id='c'>c Click하세요</div>
		</div>
	</div>
	
	
	<br><br><br>
	4. DOM예제2
	<body onload='test()'>
		<div id="parentElement">
			<span id="childElement">foo bar</span>
		</div>
	 -->
	
	<br><br><br>
	4. DOM예제2 - 노드제거
	<p>포그바</p>
	<p id="demo">click</p>
	<button onClick='test4()'>remove</button> <!-- 누르면 click 삭제 -->
	
	<br><br><br>
	4. DOM예제2 - 속성제거
	<h1 id="demo" class="cls1">click the class attribute</h1> <!-- 빨간색 속성들어간거 삭제됨 -->
	<button onClick='test5()'>remove2</button>
	
	<br><br><br>
	4. DOM예제 - child제거
	<ul id="myList2"><li>Coffee</li><li>Tea</li><li>Milk</li></ul> 
	<button onClick="test6()">remove3</button> <!-- 누르면 목록 위부터 한개씩 삭제 -->
	
	<br><br><br>
	5. DOM문제
	<!-- 
	<body onload="upcase(document)">
	 <div>
	   <h1>aa</h1>
	   <h2>bb</h2>
	 </div>
	 <div>
	   <h1>cc</h1>
	   <h1>dd</h1>
	 </div>
	  -->
	  
 	<br><br><br>
	6. DOM문제
	<!-- 
	<body onload="styleHeaderSiblings()">
		<h1>첫번째 제목</h1>
		<p>이것은 첫번째 단락입니다.</p>
		<p>테스트1</p>
		<h1>두번째 제목</h1>
		<p>이것은 두번째 단락입니다.</p>
		<p>테스트2</p> 
	-->		
	<br><br><br>
	7. DOM예제 3 - Tooltip
	<button onClick="show()">show</button>
	<button onClick="hide()">show</button>
	
	<br><br><br>
	8. DOM예제 4 - sun earth moon
	<h1 id="sun">@</h1>
	<h1 id="earth">O</h1>
	<h1 id="moon">*</h1>
	
	<br><br><br>
	9. Event예제 - event안에 자바스크립트 코드 넣는 예제들
	<input type="button" value="9번" onclick="if(window.numclicks)numclicks++; else numclicks=1; this.value='Click#'+numclicks;">
	<!-- 누를때마다 버튼의 숫자 값 증가 -->
	<form name="f1">
 		<input name='b1' type='button' value='Press Me' >
	</form>
	<form name='action.do' onsubmit="if(this.elements[0].value.length == 0) return false;">
		<input type="text">
	</form>
	
	
	
	
	
	
	
</body>
</html>

And