Skip to content

Instantly share code, notes, and snippets.

@yoongi0428
Last active August 11, 2017 13:01
Show Gist options
  • Save yoongi0428/bb9a65d8c75ced4128e60f698c9c17a7 to your computer and use it in GitHub Desktop.
Save yoongi0428/bb9a65d8c75ced4128e60f698c9c17a7 to your computer and use it in GitHub Desktop.
Bytesjack App.js with Korean comments
/*
* BytesJack <https://github.com/EtienneLem/bytesjack>
*
* Dev Etienne Lemay <http://twitter.com/#!/EtienneLem>
* Design Tristan L'abbé <http://twitter.com/#!/_Tristan>
*
* Special thanks to rafBM <http://twitter.com/#!/rafbm> for some JS tricks!
*/
// Static class hack (auto init)
// 페이지 Document Object Model (DOM)이 준비가 되어 JS가 실행 될 때 처음 한번 실행
// window 객체의 App이라는 속성으로 'App' 객체를 instantiate 한다.
$(document).ready(function(){ window.App = new App() });
// Class
// App 객체는 App 객체가 갖고있는 initialize 메소드를 (App 자신과, 객체들)을 인자로 던져 실행한다.
var App = function() { this.initialize.apply(this, arguments) };
// App 객체의 프로토타입
App.prototype = (function() { var pro = {}; // pro 라는 빈 객체
// Contants
var ANIM_DELAY = 300, //(추측) Animation delay 300
KEY_SPACE = 32, // 각 키에 해당하는 코드
KEY_S = 83,
KEY_D = 68,
KEY_1 = 49,
KEY_2 = 50,
KEY_3 = 51,
PATTERNS = [ // 카드 갯수에 따른 rotate 패턴배열 (배열의 i번째는 카드가 i+1개일 때, 순서대로 i+1개의 카드 rotate css를 나타난다)
[{deg: 0, top: 0}],
[{deg: 5, top: 0}, {deg: -5, top: 0}],
[{deg: 5, top: 15}, {deg: -1, top: 0}, {deg: -5, top: 15}],
[{deg: 9, top: 20}, {deg: 4, top: 0}, {deg: -4, top: 0}, {deg: -9, top: 15}],
[{deg: 12, top: 50}, {deg: 8, top: 10}, {deg: -4, top: 0}, {deg: -12, top: 15}, {deg: -16, top: 40}],
[{deg: 14, top: 40}, {deg: 8, top: 10}, {deg: -2, top: 5}, {deg: -5, top: 15}, {deg: -8, top: 40}, {deg: -14, top: 70}],
[{deg: 14, top: 70}, {deg: 8, top: 30}, {deg: 4, top: 10}, {deg: 0, top: 5}, {deg: -4, top: 20}, {deg: -8, top: 40}, {deg: -16, top: 70}]
];
// Variables
var types = ['clubs', 'diamonds', 'hearts', 'spades'], // 카드 문양
cards = [], // 판에 놓인 카드들 (1~11)
cardsIndex = 0, //
isPlaying = false, // 게임 진행중
gameDealed = false, // 게임이 적어도 한번 이상 play 됐다.
dealNav = $('#deal'), // html에서 id="deal"을 가져온다. (deal 버튼)
actionsNav = $('#actions'), // html에서 id="actions"을 가져온다. (hit, stand, double 버튼)
doubleBtn = $('#double'), // html에서 id="double" 를 가져온다 (double 버튼)
pCardsContainer = $('#player-cards'), // player 카드들
dCardsContainer = $('#dealer-cards'), // dealer 카드들
playerTotal = $('#player-total'), // player 점수 총합
playerCards = [], // player 카드
playerAces = 0, // player 'A' 갯수
dealerTotal = $('#dealer-total'), // dealer 점수 총합
dealerCards = [], // dealer 카드
dealerAces = 0, // dealer 'A' 갯수
chips = $('#chips'), // id = "chips" div (칩 div 3개를 감싸고 있다)
allChips = $('.chip'), // chip 클래스를 가진 3 div들 ( chips안에 allChips가 들어있다 )
bank = 100, // 잔고
bankroll = $('#bankroll'), // 잔고 표시 부분 <div>
doubled = false, // double을 했는가
currentBet = allChips.first().data('value'), // 현재 베팅 금액 (항상 현재 베팅 금액이 chip 클래스 중 첫번째다)
resizeTimer = null, // 카드 패를 0.1초 뒤에 중앙 정렬 하는 타이머함수
canDoAction = true, // 행동 가능
isStanding = false, // Stand 중인가
gameEnded = false, // 게임 끝
html = $('html'); // html 통째로 가져오기
// public (실제로 접근이 가능한 메소드, App.deal(), App.hit()...)
pro.initialize = function(opts) { initialize() }; // pro 객체의 intialize = App.prototype.initialize()
pro.deal = function() { deal() }; // pro 객체의 deal = App.prototype.deal()
pro.hit = function() { hit() }; // pro 객체의 hit = App.prototype.hit()
pro.stand = function() { stand() }; // pro 객체의 stand = App.prototype.stand()
pro.doubledown = function() { doubledown() }; // pro 객체의 doubledown = App.prototype.doubledown()
// private (실제로 접근이 불가능한 감춰진 메소드)
// App.prototype 은 이 긴 함수 표현식의 실행된 결과를 갖게되는데 큰 틀에서 보면
// 결국 표현식은 마지막에 return pro를 하고 App.prototype은 pro 객체를 갖게된다.
// pro객체의 메소드는 위의 5개고 실제로 저것들만이 App을 상속받는 객체의 메소드가 된다.
var initialize = function()
{
$('a[href="#"]').bind('click', function(e){ e.preventDefault(); }); // a태그 중 href="#"인 모든 태그를 클릭하되 페이지 이동을 하지 않도록 한다.
initBet(); // Bet 초기화
initResize(); // 화면 초기화
initKeyboardKeys(); //
setTimeout(function(){
window.scrollTo(0, 1)
}, 500);
}
// Resize management
var initResize = function()
{
$(window).bind('resize', onWindowResize);
onWindowResize(null);
};
var onWindowResize = function ( e )
{
clearTimeout(resizeTimer); // resizeTimer를 중지시킨다.
resizeTimer = setTimeout(function(){ // 0.1초 뒤 centerContainers() 실행하는 타이머 resizeTimer
centerContainers();
}, 100);
};
// Keyboard managment
var initKeyboardKeys = function() {
$(document).bind('keydown', onKeyDown); // key를 눌렀을 때
$(document).bind('keyup', onKeyUp); // key를 뗐을 때
};
var onKeyDown = function ( e ) // 키보드 눌렸을 때
{
switch ( e.keyCode ) {
case KEY_SPACE :
( isPlaying )
? actionsNav.children('li:first-child').children('a').addClass('active') // 플레이 중이면 첫번째 li(hit)의 a 태그에 active 클래스 추가
: dealNav.children('a').addClass('active'); // 플레이 중이 아니면 deal 의 a 태그에 active 클래스 추가
break;
case KEY_S : actionsNav.children('li:nth-child(2)').children('a').addClass('active'); break; // 두번째 li(stand)의 a태그에 active 클래스 추가
case KEY_D : actionsNav.children('li:nth-child(3)').children('a').addClass('active'); break; // 세번째 li(double)의 a태그에 active 클래스 추가
case KEY_1 : selectChip(0); break; // 100b 선택
case KEY_2 : selectChip(1); break; // 500b 선택
case KEY_3 : selectChip(2); break; // 1k 선택
}
};
var onKeyUp = function ( e ) // 키보드 뗐을 때
{
e.preventDefault(); // 브라우저의 기본 동작 중지
switch ( e.keyCode ) {
case KEY_SPACE :
if ( isPlaying ) {
hit();
actionsNav.children('li:first-child').children('a').removeClass('active')
} else {
deal();
dealNav.children('a').removeClass('active');
}
case KEY_S :
stand();
actionsNav.children('li:nth-child(2)').children('a').removeClass('active');
break;
case KEY_D :
doubledown();
actionsNav.children('li:nth-child(3)').children('a').removeClass('active');
break;
case KEY_1 : selectChip(0); break;
case KEY_2 : selectChip(1); break;
case KEY_3 : selectChip(2); break;
}
};
var selectChip = function ( index )
{
if ( isPlaying || gameEnded ) return; // 플레이 중 이거나 게임이 끝났으면 함수 종료
allChips.eq(index).trigger('click'); // index 번째 chip click 이벤트 발생 (이 말은 allChips 는 항상 100b 500b 1k 순 이라는 말?)
};
// Cards management
var initDeck = function()
{
for ( var i = 0; i < types.length; i++ ) {
for ( var j = 1; j <= 13; j++ ) {
var value = ( j > 10 ) ? 10 : j;
cards.push({ card:j, value: value, type: types[i] });
};
} // 모든 종류의 카드를 cards에 넣고
cards.shuffle(); // 섞어
};
// side - 'front' 'back' 앞 뒤
// player - 'player' 'dealer'
// callback - 콜백
var addCard = function ( side, player, callback )
{
var cardData = cards[cardsIndex], // ?
container = ( player == 'player' ) ? pCardsContainer : dCardsContainer, // 플레이어 or 딜러 카드 컨테이너(div) 선택
card = buildCard(cardsIndex, cardData.type, cardData.card, side), // cardsIndex번째 카드, type문양, card 숫자, side(앞,뒤)
zIndex = 0;
cardsIndex++;
canDoAction = false; // 동작 불가
// 카드 스타일 css
card.css({
'top' : '-150%',
'left' : '100%'
});
// card를 패에 추가
container.append(card);
zIndex = ( player == 'player' ) ? card.index() : 50-card.index(); // z-index ?
card.css('z-index', zIndex);
setTimeout(function(){
card.css({
'top' : '0%',
'left' : 10 * card.index() + '%'
});
rotateCards(container, (player == 'player')); // 카드를 보기 좋게 rotate
setTimeout(function(){
centerContainer(container); // 패를 중앙에
if ( player == 'player' ) addToPlayerTotal(cardData.value); // 새로 추가한 카드를 플레이어 수의 더함.
else addToDealerTotal(cardData.value);
canDoAction = true; // 이제부터 다시 동작 가능
if ( callback != undefined ) callback.call(); // callback이 있으면 실행
}, ANIM_DELAY + 100); // ANIM_DELAY + 0.1초가 지난 후 animation 실행
}, 10); // 0.01초 delay 후 outer setTimeOut 실행
};
var rotateCards = function ( container, isPlayer )
{
var cards = container.children('.card'), //컨테이너 안에 card div들
numCards = cards.size() - 1, // 배열 길이 - 1 = 카드 수 - 1 = 마지막 카드의 index
increment = ( isPlayer ) ? -1 : 1, // player 카드면 -1, dealer 카드면 1
pattern = ( PATTERNS[numCards] ) ? PATTERNS[numCards] : PATTERNS[PATTERNS.length-1];
// 카드 수에 맞는 패턴이 있으면 그걸로 하고 아니면 맨 마지막 패턴 (제일 많은 경우로)
cards.each(function(i){
var deg = ( i < pattern.length ) ? pattern[i].deg : pattern[pattern.length-1].deg,
offset = ( i < pattern.length ) ? pattern[i].top : pattern[pattern.length-1].top + (20 * (i - pattern.length + 1));
$(this).css({
'-webkit-transform' : 'rotate('+ deg * increment +'deg)',
'-khtml-transform' : 'rotate('+ deg * increment +'deg)',
'-moz-transform' : 'rotate('+ deg * increment +'deg)',
'-ms-transform' : 'rotate('+ deg * increment +'deg)',
'transform' : 'rotate('+ deg * increment +'deg)',
'top' : offset * -increment + 'px'
});
});
};
var centerContainers = function()
{
centerContainer(pCardsContainer);
centerContainer(dCardsContainer);
};
var centerContainer = function ( container )
{
var lastCard = container.children('.card:last-child'), // lastCard 는 container의 card클래스 중 마지막
totalWidth = 0; //
if ( lastCard.size() == 0 ) return; // lastCard가 없으면 종료
totalWidth = lastCard.position().left + lastCard.width(); // 마지막 카드의 width(?) 왜 total 이지
if ( html.attr('browser') == 'Safari' ) // 사파리 브라우저
container.css('-webkit-transform', 'translate3d('+ -totalWidth / 2 +'px,0,0)');
else // 그외
container.css('margin-left', -totalWidth / 2 + 'px'); // container의 left margin 조정
};
var buildCard = function (id, type, value, side) // value - 카드 값
{
var card;
if ( side == 'back' ) card = $('<div data-id="'+id+'" class="card back"></div>'); // 뒷면일 경우
else {
var cardValue = ( value == 1 ) ? 'A' : ( value == 11 ) ? 'J' : ( value == 12 ) ? 'Q' : ( value == 13 ) ? 'K' : value, // value 가 문자면 문자 숫자면 숫자
cardIcon = ( type == 'hearts' ) ? '♥' : ( type == 'diamonds' ) ? '♦' : ( type == 'spades' ) ? '♠' : '♣', // 문양
corner = '<div><span>'+cardValue+'</span><span>'+cardIcon+'</span></div>', // 왼쪽 위 코너 표시 값
icons = '';
// 10 이하는 문양 x 값
if ( value <= 10 ) {
for ( var i=1, l=value; i <= l; i++ ) {
icons += '<span>'+cardIcon+'</span>';
}
} else icons = ( value == 11 ) ? '<span>♝</span>' : ( value == 12 ) ? '<span>♛</span>' : ( value == 13 ) ? '<span>♚</span>' : '';
// 11 이상 J,Q,K는 해당 문양
card = $('<div data-id="'+id+'" class="card value'+cardValue+' '+type+'">'+corner+'<div class="icons">'+icons+'</div>'+corner+'</div>');
}
// 카드 div 리턴
return card;
};
// Game management
var deal = function()
{
// 이미 플레이중이거나, action이 불가능하거나, 게임이 끝났으면 아무것도 return하지 않는다.
if ( isPlaying || !canDoAction || gameEnded ) return;
isPlaying = true; // Play 중
if ( gameDealed ) { // 처음 시작이 아니라면 초기화
doubleBtn.removeClass('desactivate');
playerTotal.html(''); // playerTotal 의 html을 ''로 설정
dealerTotal.html(''); // dealerTotal 의 html을 ''로 설정
playerAces = 0;
dealerAces = 0;
playerCards = [];
dealerCards = [];
cards = [];
cardsIndex = 0;
doubled = false;
canDoAction = true;
isStanding = false;
$('#message').remove(); // message 문구 제거
}
pCardsContainer.html('');
dCardsContainer.html('');
initDeck(); // Deck 초기화
changeBankroll(-1); // 베팅금액 차감
ditributeCards(); // 카드 분배
gameDealed = true;
};
var hit = function()
{
if ( !isPlaying || !canDoAction || isStanding || gameEnded ) return; // 플레이 중이 아니거나 액션을 할 수 없거나 스탠드 중이거나 게임이 끝나면 종료
doubleBtn.addClass('desactivate'); // 규칙상 hit을 하면 double을 할 수 없으므로 desactivate class 추가
addCard('front', 'player', function(){ // 카드 추가
if ( playerCards.sum() > 21 ) lose('lose-busted'); // 카드 합이 21이 넘으면 lose
});
};
var stand = function()
{
if ( !isPlaying || !canDoAction || isStanding || gameEnded ) return; // 플레이 중이 아니거나 액션을 할 수 없거나 스탠드 중이거나 게임이 끝나면 종료
isStanding = true; // stand 중 (hit에는 이런 불리안이 없는데 그 이유는 hit은 한번 하고 끝나지 않으면 또 선택 가능하지만 stand는 누르는 순간 결과를 기다릴 뿐이기 때문)
revealDealerCard(); // 딜러 카드 공개
setTimeout(function(){
if ( dealerCards.sum() < 17 ) dealerTurn(); // 딜러 카드가 17보다 작으면 딜러 한번 더
else end(); // 아니면 끝
}, ANIM_DELAY); // ANIM_DELAY 이후에 실행
};
var dealerTurn = function()
{
addCard('front', 'dealer', function(){ // 딜러에게 카드 한장 추가
dealerTotal.html(calculateDealerScore()); // 딜러 결과 합산
if ( dealerCards.sum() < 17 ) dealerTurn(); // 그래도 17 이하이면 다시
else end(); // 끝
});
};
var doubledown = function()
{
if ( !isPlaying || !canDoAction || isStanding || doubleBtn.hasClass('desactivate') || gameEnded ) return;
// 플레이 중이 아니거나 액션을 할 수 없거나 더블을 할 수 없거나 스탠드 중이거나 게임이 끝나면 종료
changeBankroll(-1); // 돈 한번 더 차감
doubled = true; // 더블 중
addCard('front', 'player', function(){ // 카드 한 장 더
if ( playerCards.sum() > 21 ) lose('lose-busted'); // 21 넘는다 = LOSE
else stand(); // 안넘는다 -> 딜러 차례 기다린다.
});
};
var push = function ( msg ) // 무승부
{
showMessage(msg);
var increment = ( doubled ) ? 2 : 1; // 돈 원상 복구
changeBankroll(increment);
stopGame();
};
var win = function ( msg )
{
showMessage(msg); // 메세지 보이기
var increment = ( doubled ) ? 4 : 2; // 더블 했으면 베팅의 4배, 아니면 2배
changeBankroll(increment); // increment배 증감
stopGame();
};
var lose = function ( msg )
{
showMessage(msg);
changeBankroll(0); // 돈 변동 X : 그럼에도 하는 이유는 html text 갱신
stopGame();
};
var showMessage = function ( status )
{
var msg = document.createElement('div'),
content = '',
message = $('#message');
if ( message.size() > 0 ) message.remove(); // message가 이미 있으면 제거
msg.className = status; // 메세지의 'status' 클래스 추가
msg.id = 'message'; // 아이디
switch ( status ) {
case 'win': content = 'You win'; break;
case 'win-blackjack': content = 'You win<span>Blackjack</span>'; break;
case 'win-dealer-busted': content = 'You win<span>Dealer busted</span>'; break;
case 'lose': content = 'You lose'; break;
case 'lose-blackjack': content = 'You lose<span>Blackjack</span>'; break;
case 'lose-busted': content = 'You lose<span>Busted</span>'; break;
case 'push': content = 'Push<span>No winner</span>'; break;
case 'game-over': content = 'Game over'; break;
default: content = '<span>Something broke, don’t know what happened...</span>'; break;
}
msg.innerHTML = content;
pCardsContainer.after(msg); // 플레이어 카드 컨테이너 다음에 msg div 삽입
};
var end = function() // 게임 종료 및 결과 산출
{
var pScore = playerCards.sum(), // 점수
dScore = dealerCards.sum(); //
// 플레이어가 21이 넘는 경우는 end 까지 오기전에 끝난다(?)
if ( dScore > 21 ) win('win-dealer-busted'); // 딜러 > 21 : 플레이어 승리
else if ( dScore > pScore ) lose('lose'); // 딜러 > 플레이어 : 패배
else if ( pScore > dScore ) win('win'); // 플레이어 > 딜러 : 승리
else if ( pScore == dScore ) push('push'); // 플레이어 = 딜러 : 무승부
};
var endGame = function() // 게임 끝 (아예 게임 오버)
{
showMessage('game-over');
gameEnded = true;
var overlay = document.createElement('div'); // overlay : 게임오버가 되면 전체 화면이 어두워지는데 이를 위한 div
overlay.id = 'overlay';
$('body').append(overlay); // html body 맨 뒤에 추가한다.
};
var stopGame = function()
{
isPlaying = false; // 플레이 중 아님
dealNav.show(); // deal 버튼 보여
actionsNav.hide(); // 행동 버튼 숨기기
chips.removeClass('disabled'); // 칩 선택 가능
allChips.each(function(i){
var chip = $(this); // 칩 하나
if ( chip.data('value') > bank ) { //칩이 잔고보다 크면
chip.addClass('desactivate'); // 칩이 잔고보다 크면 desactivate
var chipsAvailable = allChips.removeClass('bet').not('.desactivate'); // bet을 지우고 desactivate 아닌것 들
if ( chipsAvailable.size() == 0 ) endGame(); // 사용 가능 한 것이 없으면 게임 end
else {
var newChip = chipsAvailable.last();
newChip.addClass('bet'); // 마지막 가능 칩에 bet 추가
changeBet(newChip.data('value')); // new칩
chips.prepend(newChip); // chips 앞에다가 newChip추가
}
} else if ( chip.hasClass('desactivate') ) chip.removeClass('desactivate'); // 가능한데 desactivate 있으면 제거
});
};
var ditributeCards = function()
{
canDoAction = false; // 동작 차단.
addCard('front', 'player', function(){
addCard('front', 'dealer', function(){
addCard('front', 'player', function(){
addCard('back', 'dealer', function(){ // 번갈아가며 카드 추가 / 블랙잭 체크
checkBlackjack();
});
});
});
});
dealNav.hide(); // deal 버튼 감추기
actionsNav.show(); // 행동 버튼 보이기
chips.addClass('disabled'); // 칩들 고를 수 없게
};
var checkBlackjack = function()
{
var pScore = playerCards.sum(),
dScore = dealerCards.sum();
if ( pScore == 21 && dScore == 21 ) push('Push - No winner');
else if ( pScore == 21 ) win('win-blackjack');
else if ( dScore == 21 ) {
lose('lose-blackjack');
revealDealerCard();
}
};
// Player management
var addToPlayerTotal = function ( value )
{
if ( value == 1 ) {
value = 11;
playerAces++;
} // 1 (A)이면 11을 일단 넣고 Ace 수를 증가시킨다.
playerCards.push(value); // 카드에 숫자 추가
playerTotal.html(calculatePlayerScore()); // 플레이어 점수 표시
};
var calculatePlayerScore = function()
{
var score = playerCards.sum(); // 점수 합산
if ( score > 21 && playerAces > 0 ) { // 21이 넘었는데 A가 있다
playerCards.splice(playerCards.indexOf(11), 1, 1); // 11을 1로 바꿔본다
playerAces--; // Ace 숫자 감소
score = calculatePlayerScore(); // 다시 계산 (재귀)
}
return score; //리턴
};
// Dealer management
var revealDealerCard = function()
{
var card = $('.back'), // 뒷면 카드 ( 딜러의 두번째 크다 )
id = card.data('id'), // 그 카드의 index
data = cards[id], // 카드 data
newCard = buildCard(id, data.type, data.value, 'front'); // 앞면으로 카드를 만듬
newCard.css({
'left' : 10 * card.index() + '%',
'z-index' : 50-card.index()
});
card.after(newCard).remove(); // 뒷면 카드 뒤에 newCard를 넣고 뒷면 카드를 지운다
dealerTotal.html(calculateDealerScore()); //
};
var addToDealerTotal = function ( value )
{
if ( value == 1 ) {
value = 11;
dealerAces++;
}
dealerCards.push(value); // 플레이어와 같지만 점수 표시 하는 것 하나만 다르다 (같은 동작이 필요하면 범용 함수로)
};
var calculateDealerScore = function()
{
var score = dealerCards.sum(); // 합한다
if ( score > 21 && dealerAces > 0 ) { // 21이 넘었는데 Ace가 있다면
dealerCards.splice(dealerCards.indexOf(11), 1, 1); // Ace를 1로 바꾸고
dealerAces--; // Ace수를 줄이고 하나
score = calculateDealerScore(); // 다시 계산
}
return score;
};
// Bet management
var initBet = function()
{
allChips.bind('click', function(e){
var chip = $(this); // 클릭 된 chip
if ( isPlaying || chip.hasClass('desactivate') ) return; // 실행중이거나 chip(allChips)이 desactivate 클래스를 가지고 있으면 종료
allChips.removeClass('bet'); // 모든 chip 에서 bet 클래스 제거
chip.addClass('bet'); // chip (아마 100b) 에 bet 클래스 추가 (현재 bet인 칩에 bet클래스를 넣는 듯 하다)
changeBet(chip.data('value')); // currentBet 를 chip의 value로 갱신
chips.prepend(chip); //chips 앞에 chip을 추가한다. (bet이 추가된 chip)
});
};
//현재 베팅 금액을 바꾼다.
var changeBet = function ( newValue ) {
if ( isPlaying ) return;
currentBet = newValue;
};
//잔고를 현재 배팅금액의 increment배 한다.
var changeBankroll = function ( increment ) {
bank += increment * currentBet; // 계좌에서 currentBet 차감
bankroll.html((bank / 10) + 'k'); // 화면 갱신
};
return pro })();
/*
* Array shuffle <http://snipplr.com/view/535>
* Array sum <http://snipplr.com/view/533>
*/ // i : 카드배열 길이, i가 0보다 클 때 까지, j = 0~i-1중 하나, this[j] 와 this[i] swap
Array.prototype.shuffle = function() { for(var j, x, i = this.length; i; j = Math.floor(Math.random() * i), x = this[--i], this[i] = this[j], this[j] = x); }
Array.prototype.sum = function() { for(var s = 0, i = this.length; i; s += this[--i]); return s; }; // 배열 수 총합합
/*
* Browser Detect <http://teev.io/blog/text/13423292>
*/
var BrowserDetect = {
init: function () {
this.browser = this.searchString(this.dataBrowser) || "An unknown browser";
this.version = this.searchVersion(navigator.userAgent)
|| this.searchVersion(navigator.appVersion)
|| "an unknown version";
this.OS = this.searchString(this.dataOS) || "an unknown OS";
var b = document.documentElement;
b.setAttribute('browser', this.browser);
b.setAttribute('version', this.version );
b.setAttribute('os', this.OS);
},
searchString: function (data) {
for (var i=0;i<data.length;i++) {
var dataString = data[i].string;
var dataProp = data[i].prop;
this.versionSearchString = data[i].versionSearch || data[i].identity;
if (dataString) {
if (dataString.indexOf(data[i].subString) != -1)
return data[i].identity;
}
else if (dataProp)
return data[i].identity;
}
},
searchVersion: function (dataString) {
var index = dataString.indexOf(this.versionSearchString);
if (index == -1) return;
return parseFloat(dataString.substring(index+this.versionSearchString.length+1));
},
dataBrowser: [
{
string: navigator.userAgent,
subString: "Chrome",
identity: "Chrome"
},
{ string: navigator.userAgent,
subString: "OmniWeb",
versionSearch: "OmniWeb/",
identity: "OmniWeb"
},
{
string: navigator.vendor,
subString: "Apple",
identity: "Safari",
versionSearch: "Version"
},
{
prop: window.opera,
identity: "Opera",
versionSearch: "Version"
},
{
string: navigator.vendor,
subString: "iCab",
identity: "iCab"
},
{
string: navigator.vendor,
subString: "KDE",
identity: "Konqueror"
},
{
string: navigator.userAgent,
subString: "Firefox",
identity: "Firefox"
},
{
string: navigator.vendor,
subString: "Camino",
identity: "Camino"
},
{ // for newer Netscapes (6+)
string: navigator.userAgent,
subString: "Netscape",
identity: "Netscape"
},
{
string: navigator.userAgent,
subString: "MSIE",
identity: "Explorer",
versionSearch: "MSIE"
},
{
string: navigator.userAgent,
subString: "Gecko",
identity: "Mozilla",
versionSearch: "rv"
},
{ // for older Netscapes (4-)
string: navigator.userAgent,
subString: "Mozilla",
identity: "Netscape",
versionSearch: "Mozilla"
}
],
dataOS : [
{
string: navigator.platform,
subString: "Win",
identity: "Windows"
},
{
string: navigator.platform,
subString: "Mac",
identity: "Mac"
},
{
string: navigator.userAgent,
subString: "iPhone",
identity: "iPhone/iPod"
},
{
string: navigator.platform,
subString: "Linux",
identity: "Linux"
}
]
};
BrowserDetect.init();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment