저때만든 코드를 보니 얼굴이 붉어진다. 코드 하나하나에 주석을 달아 두었다.;;;; 함수네이밍이나 코드컨벤션과 같은 이해도 없었을 뿐더러 레이어의 분할같은 사상적인 개념도 없었던 탓에 스파게티 소스를 커뮤니티 사람들에게 설명하느라고 참 고생한 흔적이 역력하다. 하지만 Event Driven의 개발기법은 알게 모르게 습득한 탓에 이벤트 관련된 부분은 따로 재정의를 해둔것을 발견한다.
<script language="Javascript">
var playState; // 현재 연주중이면 true, 아니면 false
var currentPosition; // 현재 연주되는 곡이 전체 5곡중의 3번째 곡이면 이 변수에는 3이 들어갑니다.
// ASX파일에 포함된 곡들을 자바스크립트에서 핸들링할때는 배열로 이것을 취급하여 핸들링합니다.
// 아래 currentIndex 변수는 이 배열의 첨자를 말합니다.
// 즉, 현재 연주되는 곡이 전체 5곡중의 3번째 곡이라면 currentPosition 에는 3이 currentIndex에는 2가 들어갑니다.
// 왜냐.. 자바스크립트의 배열첨자는 0부터 시작하니까요.
var currentIndex;
var totalminute; // 현재 연주되는 곡의 연주시간 중 분(minute) 부분을 가지고 있습니다.
var totalsecond; // 현재 연주되는 곡의 연주시간 중 초(second) 부분을 가지고 있습니다.
var elapsedminute; // 현재 곡이 연주된 시간 중 분(minute) 부분을 가지고 있습니다.
var elapsedsecond; // 현재 곡이 연주된 시간 중 초(second) 부분을 가지고 있습니다.
// 변수를 초기화합니다.
// 처음엔 당연히 정지상태일거고, 첫번째 곡이 연주될 것이므로 그렇게 세팅해 놓습니다.
playState = false;
currentPosition = 1;
currentIndex = 0;
// 연주된 시간 및 연주된 시간을 프로그레스 바로 표시하는 함수입니다.
// 위의 playStateChange 함수의 NewState가 3번일 때, 즉... 연주중일때 1초에 한번씩 이 함수가 호출됩니다.
function displayDuration() {
temp = Player.controls.currentPositionString.indexOf(":");;
elapsedminute = eval(Player.controls.currentPositionString.substr(0, temp));
elapsedsecond = eval(Player.controls.currentPositionString.substr(temp + 1));
// 위의 세 줄을 실행하면... 어떤 결과가 나오느냐......
// 우선 Player.controls.currentPositionString 함수는 현재 연주된 시간을 23:30과 같은 문자열로 반환합니다.
// elapsedminute, elapsedsecond변수는 이것을 파싱해서 분과 초를 각각 숫자 형태로 가지고 있게 됩니다.
// 아래 if 문을 잘 계산해보세요. 노래가 끝나기 1초 전이면... 이라는 결과가 나온다면 잘 계산하신 겁니다.
if (totalminute * 60 + totalsecond - 1 == elapsedminute * 60 + elapsedsecond) {
if (document.jukebox.randomplay.checked) // 만약 무순서연주가 체크되어 있으면
// Player.controls.playItem()함수는 인자로 전달되는 Media 객체를 연주하는 함수입니다.
// 그럼 () 사이에 있는 Player.currentPlaylist.item(getRandomItem())가 뭔지는 모르지만 Media 객체를 리턴한다는 것을 알 수 있습니다.
// 여기서 Media 객체란 노래 한곡 한곡을 말합니다.
// Player.currentPlaylist.item() 함수는 현재 플레이리스트(ASX 파일)에서 n번째 곡을 의미합니다. 즉, n번째 곡=Media 객체이지요.
// 단, 지금 이곳은 자바스크립트 내(內)이므로 첫번째 곡은 Player.currentPlaylist.item(0), 두번째 곡은 Player.currentPlaylist.item(1)인거 아시죠?
// 그럼 제일 마지막 곡은 Player.currentPlaylist.item(Player.currentPlaylist.count - 1) 이겠죠?
// getRandomItem은 현재 ASX파일에 5곡이 등록되어 있고 지금 3번째 곡을 연주하고 있으면
// 3번째 곡을 제외한 나머지 곡에서 한 곡을 선택해서 리턴해주는 함수입니다.
// 정확히 말하면 현재 5곡이므로(0~4까지의 숫자 중에) 현재 3번째 곡을 연주하고 있으므로(2)를 제외한 나머지 숫자중에 하나를 리턴해줍니다.
// 리턴된 숫자는 곧바로 Player.currentPlaylist.item() 에 전달되고 여기서 결과로 나온 Media 객체는 Player.controls.playItem()로 전달되어서 랜덤 연주가 이루어지는 것입니다.
Player.controls.playItem(Player.currentPlaylist.item(getRandomItem()));
else // 그렇지 않으면 1초 전이라도 무시하고 노래 끝까지 틀면 그만입니다.
// Player.controls.currentPositionString은 현재 얼만큼 연주됐나를 23:30과 같은 형태로 리턴하고
// Player.controls.durationString은 현재 연주되는 노래의 전체 시간은 23:30가 같은 형태로 리턴합니다.
// 아래는 runningtime이라는 레이어에 내용을 뿌려주는 함수입니다.
document.all.runningtime.innerHTML = Player.controls.currentPositionString + " / " + Player.currentMedia.durationString;
}
else // 끝나기 1초전이 아니면
document.all.runningtime.innerHTML = Player.controls.currentPositionString + " / " + Player.currentMedia.durationString;
// 위에서 elapsedminute, elapsedsecond, totalminute, totalsecond가 뭐하는 놈인지 설명했죠?
// 그걸 가지고 현재 몇 %나 연주되었는지 구합니다.
// progressbar1이라는 레이어에 현재 진행률을 표시합니다.
// progressbar2는 일명 "게이지 레이어"입니다. 아래 html 부분을 보시면 아시겠지만 progressbar1과 progressbar2는 위치와 크기가 동일한 레이어입니다.
// 여기서 progressbar1은 에초부터 가로 크기가 200인 레이어이고 배경이 투명합니다.
// 그러나 progressbar2는 가로 크기가 0이면서 배경이 파란색인 레이어입니다.
// 아래 document.all.progressbar2.style.pixelwidth = percentage * 2; 부분은 이 progressbar2의 레이어 크기를 현재 진행률 * 2 크기로 늘려주는 스크립트입니다.
// 왜... 곱하기 2를 하느냐.. 퍼센테이지는 100이 끝이고 레이어 크기는 200이 끝이니까 2를 곱해줘야지요.
// 위에 올라와 있는 progressbar1의 배경이 투명이므로 글자와 배경이 겹쳐도 이상없이 잘 출력되는 효과를 내는 것입니다.
// 처음 공개되는 팁 같으니 꼭 기억하시기 바랍니다.
percentage = Math.ceil((elapsedminute * 60 + elapsedsecond) / (totalminute * 60 + totalsecond) * 100);
document.all.progressbar1.innerHTML = percentage + "%";
document.all.progressbar2.style.pixelWidth = percentage * 2;
}
// 재생/일시정지 버튼을 눌렀을 경우
function startPlay() {
if (playState) // 현재 연주되고 있으면
Player.controls.pause(); // 잠깐 멈추고
else // 현재 잠깐 멈춰있거나 정지상태이면
Player.controls.play(); // 연주한다
}
// 일시정지가 아닌 정지 버튼을 눌렀을 경우
function stopPlay() {
Player.controls.stop(); // 멈춘다
}
// 다음곡 재생 버튼을 눌렀을 경우
function goNext() {
if (document.jukebox.randomplay.checked) // 무순서 연주가 체크되어 있으면
Player.controls.playItem(Player.currentPlaylist.item(getRandomItem())); // 이 함수는 위에서 설명했죠?
else // 무순서 연주가 아니라 차례대로 연주하는 거면
Player.controls.next(); // 다음곡 튼다
}
// 이전곡 재생 버튼을 눌렀을 경우
function goPrevious() {
if (document.jukebox.randomplay.checked)
Player.controls.playItem(Player.currentPlaylist.item(getRandomItem()));
else
Player.controls.previous();
}
// 인자로 넘어온 값을 화면의 레이어에 뿌려주는 함수입니다.
// 설명은 하지 않겠습니다.
function changeDisplay(playerstate, musictitle, author, fileinfo, runningtime, progressbar1) {
document.all.playerstate.innerHTML = playerstate;
document.all.musictitle.innerHTML = musictitle;
document.all.author.innerHTML = author;
document.all.fileinfo.innerHTML = fileinfo;
document.all.runningtime.innerHTML = runningtime;
document.all.progressbar1.innerHTML = progressbar1;
}
// playState의 값을 변경하는 함수입니다.
function setPlayState(state) {
playState = state;
}
// 현재 연주되는 곡이 몇번째 곡인지를 알아내는 함수
function getCurrentPosition() {
for (i = 0; i < Player.currentPlaylist.count; i++) // ASX파일에 등록되어 있는 곡의 수만큼 돌면서
if (Player.currentPlaylist.item(i) == Player.currentMedia) // i번째 Media 객체가 현재 연주되는 Media 객체와 같으면
currentPosition = i + 1; // 현재 위치는 i + 1번째입니다. 왜냐? 배열이므로 1을 더해줘야 우리가 생각하는 몇번째 곡이라는게 나오겠죠?
}
// 현재 연주되는 곡을 제외한 나머지 곡들 중 하나를 선택하는 함수입니다.
function getRandomItem() {
if (document.jukebox.randomplay.checked) { // 무순서 연주가 체크되어 있으면
while (true) { // 계속 돌면서
// 아래 한줄을 실행하면 currentIndex에는 0~현재 등록되어 있는 곡의 수 - 1 사이의 값 중 하나가 들어갑니다.
// 잘 계산해보세요.
currentIndex = Math.ceil(Math.random() * 10000) % Player.currentPlaylist.count;
// 그래서 나온놈이 currentPosition - 1과 다르다면 루프를 빠져나갑니다.
// 위에서 currentPosition - 1 = currentIndex라고 했습니다. 다 기억나시죠?
if (currentPosition - 1 != currentIndex)
break;
}
} // 무순서 연주가 체크되어 있다면 결국 나오게 되는 currentIndex는 현재 곡이 아닌 나머지 곡 중 하나의 배열첨자 값이 될 것입니다.
else { // 무순서 연주가 체크되어 있지 않다면
currentIndex++; // currentIndex를 하나 증가시켜 다음 곡을 가리키게 합니다.
if (currentIndex >= Player.currentPlaylist.count) // 그랬는데... 만약 ASX 파일에 등록된 곡의 개수보다 커진다면...
currentIndex = 0; // 처음곡으로 돌려야겠죠? 누차 말씀드리지만 currentIndex는 배열의 인덱스라고 했습니다. 즉, 첫번째 곡을 가리킬때는 0이 되겠죠?
}
return currentIndex; // currentIndex를 리턴합니다.
}
// 반복연주를 할지 말지를 세팅하는 함수입니다.
function changeLoopMode() {
if (document.jukebox.loop.checked) // 반복재생이 체크되어 있으면
Player.settings.playCount = 10000; // 재생힛수를 10000회로 세팅합니다.
else // 그렇지 않으면
Player.settings.playCount = 1; // 한번만 연주하고 땡~ 하면 되겠죠?
}
// 음소거를 할지 여부를 세팅하는 함수입니다.
function changeMuteMode() {
if (document.jukebox.mute.checked) // 음소거가 체크되어 있으면
Player.settings.mute = true; // 음소거 하고
else // 아니면
Player.settings.mute = false; // 말고
}
// 현재 연주되는 곡의 재생시간을 얻어 그것을 파싱한 후 totalminute와 totalsecond에 숫자 형태로 저장합니다.
// 현재 곡이 연주되고 있는 동안 호출됩니다.
function setRunningTime() {
temp = Player.currentMedia.durationString.indexOf(":");; // Player.currentMedia.durationString는 현재 곡의 총 연주시간을 23:30 형태로 반환합니다.
totalminute = eval(Player.currentMedia.durationString.substr(0, temp));
totalsecond = eval(Player.currentMedia.durationString.substr(temp + 1));
}
// 프로그레스 바를 0%로 만듭니다. 배경이 파란색인 progressbar2 레이어의 가로 크기를 0으로 하면 되겠죠?
function clearProgressbar() {
document.all.progressbar2.style.pixelWidth = 0;
}
// 현재 연주되는 파일의 음질 및 포멧을 리턴합니다.
function getFileInfo() {
// Player.currentMedia.getItemInfo("Bitrate")는 현재 연주되는 파일의 음질을 나타냅니다.
// 65283과 같은 bps 형태로 나타나므로 1000으로 나누었습니다.
// Player.currentMedia.getItemInfo("MediaType")는 현재 연주되는 파일의 형태를 나타냅니다.
return Math.floor(eval(Player.currentMedia.getItemInfo("Bitrate") / 1000)) + " kbps / " + Player.currentMedia.getItemInfo("MediaType");
}
// 플레이어가 처음 실행될 때는 볼륨 조절 바를 현재 볼륨에 맞도록 위치를 조정해줘야합니다.
// Player.settings.volume은 현재의 볼륨을 0~100 사이의 수치로 얻어옵니다.
function initVolume() {
document.all.handle.style.pixelTop = document.all.volumebar.style.pixelTop + (Player.settings.volume / 2.3);
}
// 볼륨바를 움직이면 그에 따라 볼륨도 실제로 변해야겠죠?
function changeVolume(volume) {
Player.settings.volume = volume;
}
// 여기서부터 스크립트의 끝까지는 볼륨바를 컨트롤하는 부분입니다.
// 다이나믹 HTML에 대한 지식이 어느 정도는 있어야 이해할 수 있는 부분입니다.
// 현재 드레그가 가능한 상태인지 아닌지를 담고 있는 변수입니다.
// 드레그가 가능한 상태 : 마우스가 볼륨조절 바 위에 있으면서 왼쪽 버튼을 누르고 있을 때...
// 드레그가 가능하지 않은 상태 : 위의 경우가 아닌 전부~
var dragPossible = false;
// 마우스 버튼을 눌렀을 경우
function mouseDown() {
// 이벤트가 발생한 소스를 얻습니다.
// 이 문장 바로 아래에 alert로 eventSrc를 찍어보세요. 실제 페이지에서 마우스 버튼을 누르면 뭐가 담기는지 알 수 있겠죠?
var eventSrc = event.srcElement;
// 만약 이벤트가 발생한 소스의 id가 handle이 아닌동안 계속 돕니다.
// 즉, 마우스 버튼을 볼륨 조절 버튼 위에서 눌렀는지를 판가름합니다.
// 만약 현재 이벤트가 일어난 이벤트 소스가 볼륨조절 버튼이 아니라면 볼륨조절 버튼을 찾아 상위 소스로 이동합니다.
// eventSrc = eventSrc.parentElement;가 어떤 일을 하는지 모르시는 분은
// eventSrc = eventSrc.parentElement; 다음에 alert(eventSrc);로 결과를 한번 확인해보시기 바랍니다.
// 테스트 하실 때는 while 문에 { } 치는거 잊지마시구요.
while (eventSrc.id != "handle" && eventSrc.tagName != "HTML")
eventSrc = eventSrc.parentElement;
// 만약 현재 이벤트가 일어난 소스가 볼륨조절 버튼이라면 = 볼륨조절 버튼이 담겨있는 레이어의 id가 handle입니다.
if (eventSrc.id == "handle") {
dragPossible = true; // 현재 드래그가 가능한 상태입니다.
document.handleimage.src = "p1-button.gif"; // 볼륨조절 버튼의 이미지를 좀 밝은 이미지로 바꿉니다.
}
else { // 이벤트가 일어난 소스가 볼륨조절 버튼이 아니군요...
dragPossible = false;
document.handleimage.src = "p1-button.gif";
}
}
// 마우스 버튼을 놓았을 때는
function mouseUp() {
dragPossible = false; // 다 아시죠?
document.handleimage.src = "p1-button.gif";
}
// 마우스를 움직일 때는
function mouseMove() {
var eventSrc = event.srcElement; // 마우스가 어디서 움직였는지를 알아내서 저장합니다.
// 아래 while 문을 잘 보세요.
// 결국 볼륨 조절 버튼 위에서 이벤트가 발생했는지를 알아내기 위한 while문입니다.
while (eventSrc.id != "handle" && eventSrc.tagName != "HTML")
eventSrc = eventSrc.parentElement;
// 볼륨 조절 바 위에서 + 드래그가 가능한 상태에서 + 왼쪽 버튼을 누르고 있을때만!!
if (dragPossible && event.button == 1) {
document.handleimage.src = "p1-button.gif"; // 이미지 바꾸고
// 아래 if문은 볼륨조절 버튼의 위치를 결정하는 겁니다.
// event.y = 현재 마우스 의 y 좌표
// document.all.volumebar.style.pixelTop = 볼륨조절 버튼의 상단 위치
// document.all.volumebar.style.pixelHeight = 볼륨조절 바(버튼 뒤의 긴 막대기)의 세로 길이
if (event.y < document.all.volumebar.style.pixelTop) // 만약 마우스의 현재 위치가 볼륨조절 바의 상단 끝보다 더 상단으로 갔다면
barPosition = document.all.volumebar.style.pixelTop; // 현재 볼륨조정 버튼의 위치를 볼륨조정 바의 제일 상단으로 이동합니다.
else if (event.y > document.all.volumebar.style.pixelTop + document.all.volumebar.style.pixelHeight - 9) // 위의 반대 경우... 9을 뻬주는 이유는 볼륨조정 버튼의 가로 크기가 10이기 때문입니다.
barPosition = document.all.volumebar.style.pixelTop + document.all.volumebar.style.pixelHeight - 9;
else // 이것도 저것도 아니라면 볼륨조정 바 사이에 마우스가 있는 것이므로 현재 위치가 볼륨조정 버튼의 위치가 됩니다.
barPosition = event.y;
// barPosition이 볼륨 조절 버튼의 현재 세로 위치를 나타냅니다.
// 그러므로 이동해야겠죠?
document.all.handle.style.pixelTop = barPosition;
// 실제 볼륨도 바꾸구요.
changeVolume(90-((barPosition - document.all.volumebar.style.pixelTop) * 2.3));
}
}
// 이 함수는 마우스로 드래그를 시작할때나 선택을 시작할 때(선택도 일종의 드래그죠...)의 처리를 하는 함수입니다.
// 있는 그대로 설명을 하면 드래그를 하고자 하는 놈이 볼륨조절 버튼이라면 event.returnValue = false를 사용하여
// 드래그 이벤트를 무료화시키는 일을 합니다. 왜냐. 볼륨조절 버튼은 다른 곳에서 이미 처리하고 있기 때문입니다.
function mousedragstart() {
var eventSrc = event.srcElement;
while (eventSrc.id != "handle" && eventSrc.tagName != "HTML")
eventSrc = eventSrc.parentElement;
if (eventSrc.id == "handle")
event.returnValue = false;
}
document.ondragstart = mousedragstart; // drag가 시작될 때의 이벤트 처리를 mousedragstart 함수로 넘깁니다.
document.onselectstart = mousedragstart; // select(선택)이 시작될 때의 이벤트 처리를 mousedragstart 함수로 넘깁니다.
document.onmousedown = mouseDown; // 마우스 버튼을 눌렀을 때의 이벤트 처리를 mouseDown 함수로 넘깁니다.
document.onmouseup = mouseUp; // 마우스 버튼을 놓았을 때의 이벤트 처리를 mouseUp 함수로 넘깁니다.
document.onmousemove = mouseMove; // 마우스가 움직일 때의 이벤트 처리를 mouseMove 함수로 넘깁니다.
</script>
저 때 만약 Object Programming에 대해서 이해도가 있었다면 아마도 객체로 분할해서 코드를 작성했을 것이다. (하지만 php스크립트에 객체지향 개념이 나왔던게 PHP5였지 아마?) 지난 코드를 구하기도 쉽지만은 않다. 하지만 커뮤니티의 온전한 보호속에 이렇게 고스란히 지난 추억을 되살릴 수 있는 시간이 있어서 좋다. 지난코드를 보고 또 한번 상념에 잠기며 객체 프로그래밍으로 다시 꾸며볼 생각을 하니 또 한번 작은 웃음이 나온다.
그리고 다시 한번 포스팅할꺼리가 늘어났다. "프로젝트내 자바스크립트 컴포넌트 제작"이라는 제목으로 글을 올리려고 하는데
귀차니즘때문에 손이 가질 않는다. 큰맘먹고 조만간 올려드려야지..
공유하고 이야기하고 싶은 것들이 너무나 많다. 블로그에 공개하지 못한 부분들까지 같이 공유하고 싶은 공간이 필요하다. 유난스럽지도 않고 대놓고 상대접을 하는 어려운 장소가 아닌 자연스러운 그런곳 말이다. 인터넷은 기록을 지배하는 장소라서 독자들은 사람이 올린글로 사람을 판단하는 실수를 가끔씩 한다. 그것이 전부가 아닌데도 불구하고 그것을 마치 전부인것 처럼 느끼는 것이 바로 그것이다. 다시한번 말하지만 내 블로그는 격식과 절차 없는, 쓰고 싶을 때 쓰는 그런 장소이고, 풍유가 섞인 그런 곳이다. 내 인생의 2%라고 해야함이 맞다. 블로그로 밥을 먹고 광고하면서 사는 그런 부류가 아니란 이야기다.
최근엔 블로그 작성이 예전만큼 자유롭지가 않다. 보는 눈이 많아졌으니 예의를 갖출 필요도 있는 것이다.
자유스럽게 글을 기재할 수 있는 또 다른 공간이 필요한 시점이기도 하다.
2010/07/23 21:04 [수정/삭제] [답글]
헐 저 때문에 부랴부랴 찾아서 올리신글 같아요 ㅋ
한번 시간내서 뜯어봐야겠습니다 +_+!
좋은자료 감사합니다!!!!
2010/07/24 00:23 [수정/삭제]
오랜만에 자바스크립트를 보니 예전 생각이 나서요.ㅎㅎ
아..정말 공유할 수 있는 개념들이 많은데.. 블로그에 그냥 올리는 것도 그렇고 말이예요. 시간상 다 올릴수도 없고.. 언제한번 스터디나 해볼까요? ㅎㅎ