출처: http://ruru.tistory.com/entry/HTTP-Cookie-Javascript

clear가 제대로 동작하지 않아 새로 작성했다.
    var Cookies = {};
    Cookies.set = function(name, value){
         var argv = arguments;
         var argc = arguments.length;
         var expires = (argc > 2) ? argv[2] : null;
         var path = (argc > 3) ? argv[3] : '/';
         var domain = (argc > 4) ? argv[4] : null;
         var secure = (argc > 5) ? argv[5] : false;
         document.cookie = name + "=" + escape (value) +
           ((expires == null) ? "" : ("; expires=" + expires.toGMTString())) +
           ((path == null) ? "" : ("; path=" + path)) +
           ((domain == null) ? "" : ("; domain=" + domain)) +
           ((secure == true) ? "; secure" : "");
         
    };

    Cookies.get = function(name){
     var arg = name + "=";
     var alen = arg.length;
     var clen = document.cookie.length;
     var i = 0;
     var j = 0;
     while(i < clen){
      j = i + alen;
      if (document.cookie.substring(i, j) == arg)
       return Cookies.getCookieVal(j);
      i = document.cookie.indexOf(" ", i) + 1;
      if(i == 0)
       break;
     }
     return null;
    };

    Cookies.clear = function(name) {
      if(Cookies.get(name)){
      	var today = new Date();
      	today.setFullYear(today.getFullYear()-1);
        Cookies.set(name, "", today);
      }
    };

    Cookies.getCookieVal = function(offset){
       var endstr = document.cookie.indexOf(";", offset);
       if(endstr == -1){
           endstr = document.cookie.length;
       }
       return unescape(document.cookie.substring(offset, endstr));
    };


License
달리 정하지 않는 한, 이 저작물 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
Except where otherwise noted, this content is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 2.0 Korea License
파이어준님의 블로그에 엄청나게 좋은 글이 있었는데 저작권이 CC라서 보관도 할겸 가져왔다.
바로 프로토타입을 효과적으로 활용하는 방법에 관한 건데.
초반부를 보면서는 "음 나도 좀 쓰고있군" 했는데 update나 invoke, Ajax.Request 에서 parameters 쓰기 등에서 좌절. Template은 존재 여부도 모르고 있었다. 알게되었으니 유용하게 사용해야겠다.

//바르지 못한 방법:
document.getElementById("foo ")
//적당한 방법: 놀랍게도 어떤 사람들은 이것에 대해 잘 모른다.
$("foo ")

//바르지 못한 방법:
var woot = document.getElementById("bar").value
var woot = $("bar").value
//적당한 방법: 폼 값의 편리하고 빠른 호출
var woot = $F("bar")

//바르지 못한 방법:
$('footer').style.height = '100px';
$('footer').style.background = '#ffc';    
//적당한 방법: 모든 브라우저가 W3C의 권고를 따르고 있지 않다.
$('footer').setStyle({
    height: '100px',
    background: '#ffc'
})

//바르지 못한 방법:
$('coolestWidgetEver').innerHTML = 'some nifty content'
//적당한 방법:
$('coolestWidgetEver').update('some nifty content')
// 아래와 같은 문법 구사가 가능해 지므로
$('coolestWidgetEver').update('some nifty content').addClassName('highlight').next().hide()

//바르지 못한 방법:
new Ajax.Request('ninja.php?weapon1=foo&weapon2=bar')
//적당한 방법: 보기 좋으며 보다 나은 파라메터 구조 사용
new Ajax.Request('ninja.php', {
    parameters: {
        weapon1: 'foo',
        weapon2: 'bar'
    }
})

//바르지 못한 방법:
new Ajax.Request('blah.php', {
    method: 'POST',
    asynchronous: true,
    contentType: 'application/x-www-form-urlencoded',
    encoding: 'UTF-8',
})
//적당한 방법: 기본옵션은 생략하라!
new Ajax.Request('blah.php')

//바르지 못한 방법:
Event.observe('myContainer', 'click', doSomeMagic)
//적당한 방법: 논쟁의 여지가 있지만 객체지향적이다!
$('myContainer').observe('click', doSomeMagic)

//바르지 못한 방법:
$$('div.hidden').each(function(el){
    el.show();
})
//적당한 방법: 슬프게도 이 사용법을 아는 사람들이 많지 않다는 사실.
$$('div.hidden').invoke('show')

//바르지 못한 방법:
$$('div.collapsed').each(function(el){
    el.observe('click', expand);
})
//적당한 방법: invoke를 이용한 이벤트 핸들링, 졸라 쉽다!
$$('div.collapsed').invoke('observe', 'click', expand)

//바르지 못한 방법:
$$('input.date').invoke('observe', 'focus', onFocus);
$$('input.date').invoke('observe', 'blur', onBlur);
//적당한 방법: $$는 오버해드가 크기 때문에 invoke를 사용하면 $$를 여러번 사용할 필요도 없다.
$$('input.date').invoke('observe', 'focus', onFocus).invoke('observe', 'blur', onBlur)

//바르지 못한 방법:
$('productTable').innerHTML =
    $('productTable').innerHTML +
    '<tr><td>' + productId + ' '
    + productName + '</td></tr><tr><td>'
    + productId + ' ' + productPrice +
    '</td></tr>'
//적당한 방법: Template 클래스는 정말 쓸만한 DOM 솔루션이다. 하지만 잘 사용되고 있지 않는 것 같다.
var rowTemplate = new Template('<tr><td>#{id} #{name}</td></tr><tr><td>#{id} #{price}</td></tr>');
$('productTable').insert(
    rowTemplate.evaluate({
        id: productId,
        name: productName,
        price: productPrice
    }))
)

invoke에 인자로 넘어가는 function 이름이 string길래 순간 eval인가? 라는 말도안되는 생각에 설마하면서 소스를 뒤져보니 다행히 eval은 아니었고(당연하지!) invoke의 소스는 아래와 같이 되어있었다.
invoke: function(method) {
    var args = $A(arguments).slice(1);
    return this.map(function(value) {
        return value[method].apply(value, args);
    });
}

function명과 추가적인 인자들을 넘겨주면 해당 function에 자신과 인자들을 넣어서 실행하는 것 같다.
eval 대신에 그냥 맵처럼 function을 호출할 수 있다는건 조금 신기하기도 했고.

프로토타입은 쓰면 쓸수록 맘에 든다. 이 포스팅이 좀더 잘 활용할 수 있는 계기가 되길 바란다.


License
달리 정하지 않는 한, 이 저작물 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
Except where otherwise noted, this content is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 2.0 Korea License
얼마전 알바로 들어온 회사에서 프로젝트를 살짝 끝냈다.
개발자의 필수코스인 주말출근에 밤도 새면서(ㅠㅠ) 열심히 만들었는데,
예전엔 mootools같은 js라이브러리를 썼다가 안쓰고 만들려니, 크로스브라우징이 내 발목을 잡았다.

이번 프로젝트의 목표 브라우저는 Internet Explorer(이하 ie)와 Firefox(이하 ff).
그런데 내가 짠 자바스크립트가 둘중하나에서 동작을 안했던 경우가 있어
다른 개발자분들의 삽질을 조금이나마 줄여보고자. 이 포스트를 남긴다.


첫째. 동적으로 input을 생성할때.

우선 element를 만드는 명령어는 널리 알려져있다.
var input = document.createElement('input');

이렇게 하면 input라는 태그가 만들어진다.
<input />가 만들어진다고 생각하면 된다.

그런데 ie에서는 아래 명령어가 먹지않는다.
input.type = 'hidden';

그래서 해결하고자 ie는 아래와 같은 방법을 썼다.
var input = document.createElement('<input type="hidden" />');

단, 조심할것은 위 코드는 ie에서만 되는것 같다. ff에서는 확실히 안된다.



둘째. 공백을 노드로 인식하느냐 안하느냐 하는 문제.

우선 아래와 같은 HTML 코드가 있다고 하자.
<div id="div1">
    <span id="span1">내용1</span>
   <span id="span2">내용2</span>
   <span id="span3">내용3</span>
    ...(span이 동적이라 몇개가 될지 모름)
</div>



위와같은 상황에서. 모든 span에 특정 동작을 줘야할때.
난 보통 아래처럼 코딩한다.
var spans = document.getElementById('div1').childNodes;
for(var i=0; i<spans.length; i++){
    var span = spans.item(i);
    (span에 이짓저짓)
}


그런데 ff에서 문제가 발생했다.
난 이유를 알 수 없었다. 당연히 되야될 것 같았다.

그러나 저 이짓저짓부분에
alert(span.nodeType);

을 넣어보고 원인을 알 수 있었다.

ie에서는 whitespace(공백,엔터,탭 등)만으로 이루어진 공간을 무시하는데 비해
ff에서는 하나의 textnode로 취급하기때문에 생긴 에러였다.

그러니 이짓저짓 부분에 span.id 따위의 접근을 하면 에러가 날수밖에 없었다.
그래서 해결책으로 아래처럼 if를 추가했다.

var spans = document.getElementById('div1').childNodes;
for(var i=0; i<spans.length; i++){
    var span = spans.item(i);
   if(span.nodeType == 1){
       (span에 이짓저짓)
    }
}

저렇게 if문을 넣어놓으면 textnode를 피해갈 수 있다.
참고로 textnode의 타입은 3이다.

이 프로젝트를 하면서 결심했다.
자바스크립트 노가다에 시간을 쓰느니 걍 prototype쓰자. ㄷㄷㄷ

이 포스트가 여러분의 웹표준 개발에 조금이나마 도움이 되길 바라면서....
사용자 삽입 이미지



License
달리 정하지 않는 한, 이 저작물 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
Except where otherwise noted, this content is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 2.0 Korea License
  1. 이타카노 2007.07.11 15:42 신고

    저는 이런 분야는 잘 모르지만,
    웹프로그래머들이든 그와 관련된 업체에게 하고 싶은 말이라면

    "제발 액티브X좀 쓰지마삼"

    ..정말 싫어요 액티브X..

    • Widyou 2007.07.11 22:02 신고

      엑티브X 저도 정말 싫어합니다.
      그래서 꼭 들어가야하는 사이트가 아닐경우 파폭에서 안뜨면 안들어갑니다.

  2. guybrush 2007.07.11 20:34 신고

    input.setAttribute("type","hidden");

    혹시 이렇게 해도 안되나요?

    • Widyou 2007.07.11 22:02 신고

      그방법은 써보지는 않았네요.
      그런데 예전에 setAttribute를 써서 안먹는 속성이 많았던 경험때문에 안써본지 오래되었네요.

  3. 2007.07.12 13:59

    비밀댓글입니다

Mootools에는 Tips라는 클래스가 있다.
이 객체는 Drag.Move클래스처럼 new 키워드로 생성만 해주면 작동하는 방식인데
지정된 객체위에 마우스가 올라가면 선언할때 생성된 div를 마우스 옆에 따라다니도록 만든다.
사용법은 아래와 같다.

var myTips = new Tips(Element들이 들어있는 리스트, 옵션);
예)
var myTips = new Tips($$('img.toolTip'), {maxTitleChars: 50, offsets: {'x': 16, 'y': 16} });





하지만 이번에 Tips를 사용하는 중에 스크롤해도 툴팁은 스크롤을 따라오지못하는 문제를 발견했다.
소스를 공개하자면,

1. 툴팁을 띄울 이미지.
<img id="mapimg" class="toolTip" title="클릭하면 큰화면으로 볼 수 있습니다." src="images/handbook/map.jpg">


2. 스크립트(body의 onload에 실행됨)
var myTips = new Tips($$('img.toolTip'), {
     offsets: {'x': 0, 'y': 20}
});


3. css파일에 툴팁스타일 추가(툴팁의 className은 디폴트가 tool-tip이다)
.tool-tip{
     padding: 3px;
     border: 1px solid rgb(102,102,102);
     background-color: rgb(255,255,153);
}


4. imgElement.href를 하면 src의 내용이 나오기때문에 이미지에서도 주소가 나타나는 문제가 있어서 build메소드에 if 추가
(아마 IE문제인듯.)
...
...
build: function(el){
     if(el.getTag() != 'img') el.myTitle = el.href ? el.href.replace('http://', '') : (el.rel || false);
...
...

*변경결과:
사용자 삽입 이미지

변경 전




사용자 삽입 이미지

변경 후




하지만 스크롤시 문제가 발생! 참고로 브라우저는 IE7이다.

사용자 삽입 이미지

스크롤 전

























사용자 삽입 이미지

스크롤 후














원인을 찾아보니 Tips 클래스에서 마우스 이동시마다 툴팁의 위치를 바꿔주는 locate메소드가 문제였다.
코드를 보면,

locate: function(event){
     var win = {'x': window.getWidth(), 'y': window.getHeight()};
     var scroll = {'x': window.getScrollLeft(), 'y': window.getScrollTop()};
     var tip = {'x': this.toolTip.offsetWidth, 'y': this.toolTip.offsetHeight};
     var prop = {'x': 'left', 'y': 'top'};
     for (var z in prop){
          var pos = event.page[z] + this.options.offsets[z];
          if ((pos + tip[z] - scroll[z]) > win[z]) pos = event.page[z] - this.options.offsets[z] - tip[z];
          this.toolTip.setStyle(prop[z], pos + 'px');
     };
     event.stop();
},


위에 진하게 표시한 부분이 현재 스크롤 위치를 알아내는 부분인데,
window.getScrollTop()의 코드를 보니
getScrollTop: function(){
     return this.pageYOffset || document.documentElement.scrollTop;
},

인데, 테스트해보니 document.documentElement.scrollTop은 항상 0을 리턴하고,
document.body.scrollTop을 써야 제대로 리턴이 되는 것이었다.
(이건 혹시 IE7의문제???)
그래서 일단 위의 getScrollTop메소드를
getScrollTop: function(){
     return this.pageYOffset || document.body.scrollTop || document.documentElement.scrollTop;
},


로 바꾸어서 body를 먼저 참조하고 undifined일때 documentElement를 참조하도록 했다.
그리고 windows내의 documentElement를 사용하는 모든 메소드에 body참조를 추가했다
(window.getWidth(), window.getHeight(), window.getScrollLeft(), window.getScrollTop() 등등..)

바꾸고나니까 잘 작동한다. 후후후...

하지만,
가면갈수록 싫어지는 IE..
dlrtmvmffhfj wnrdjfk~


License
달리 정하지 않는 한, 이 저작물 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
Except where otherwise noted, this content is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 2.0 Korea License
난 태그를 자바스크립트로 동적 생성할때는 아래처럼 쓰는 버릇이 있었다.

...
var input = document.createElement('input');
input.name = 'id';
input.type = 'text';
form.appendChild(input);
...


MooTools(이하 무툴)를 쓰게 된 이후로는 아래처럼 됐다.


...
var input = new Element('input');
input.setProperties({name: 'id', type: 'text'});
form.adopt(input);
...


이렇게 잘 쓰고 있는데 이상하게 ie6에서만 name이 지정 안되길래 무툴의 소스를 봤더니,


...
setProperties: function(source){
    for (var property in source) this.setProperty(property, source[property]);
    return this;
}

setProperty: function(property, value){
    switch (property){
        case 'class': this.className = value; break;
        case 'style': this.setStyles(value); break;
        case 'name': if (window.ie6){
            var el = $(document.createElement('<'+this.getTag()+' name="'+value+'" />'));
            $each(this.attributes, function(attribute){
                if (attribute.name != 'name') el.setProperty(attribute.name, attribute.value);
            });
            if (this.parentNode) this.replaceWith(el);
            return el;
        }
        default: this.setAttribute(property, value);
    }
    return this;
}
...


이 소스를 보면 name속성 코드가 ie6을 위해 따로 제작되어있다.
하지만 ie6용 코드에서는 자기자신을 바꾸지 않는다. 부모노드를 가진 객체일경우만 새로 생성해서 바꿔준다.
그러나 위에 내가 짠 코드는 속성을 설정한 후에 부모에 붙이기때문에 ie에서 작동하지 않았다..

저 오류를 발견한건 이미 저런 코딩이 몇개 더 있는 상황이라 무툴의 소스를 살짝 고쳐봤다.


setProperty: function(property, value){
    switch (property){
        case 'class': this.className = value; break;
        case 'style': this.setStyles(value); break;
        case 'name': if (window.ie6){
            if (this.parentNode){
                var el = $(document.createElement('<'+this.getTag()+' name="'+value+'" />'));
                $each(this.attributes, function(attribute){
                    if (attribute.name != 'name') el.setProperty(attribute.name, attribute.value);
                });
                this.replaceWith(el);
                return el;
            }else{
                this.name = value;
                break;
            }
        }
        default: this.setAttribute(property, value);
    }
    return this;
}
...


이렇게 바꿔서 잘 되기는 하는데 뭔가 문제가 생길지도..

그런데 이문제는 내 코딩습관이 잘못된건가.. 아님 무툴에서 구현을 잘못한건가...
나도 잘 모르겠다.


License
달리 정하지 않는 한, 이 저작물 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
Except where otherwise noted, this content is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 2.0 Korea License
  1. 임장혁 2008.04.22 11:43 신고

    저도 동적으로 생성할 때 property가 제대로 안들어가는 경우가 있었습니다.
    왜 안되는지 한참 고민했었는데 ^^;;

    제 경우는 table에 자식들을 생성할 때였는데,
    어느 외국 블로그에 IE에선 부모에 삽입 해주고 속성들을 바꿔야 해결된다고 나와 있더라구요..

    이 문제도 그거와 비슷한 것 같네요.
    먼저 부모에 삽입해주고 하시는게 ^^

    • Widyou 2008.04.22 14:38 신고

      저도 지금은 그게 맞다고 생각합니다.
      이걸 쓰던때엔 제 스타일대로 하고싶은 고집에 라이브러리를 수정해버렸죠.

자바 스크립트 라이브러리중에 MooTools라는게 있다.
알아본 바로는 moo.fx라는 라이브러리를 어떤 이유로 고친 느낌이다.
내가 현재 진행중인 프로젝트에서 살짝 써봤는데
매우 만족하고 있다.

그전까지 난 prototype1.4를 쓰고 있던중에 1.5의 소식을 듣게되었고
그때 mootools의 존재를 함께 알았다.

mootool의 장점은 prototype를 기본적으로 본받으면서 Fx로 시작하는 클래스들이 꽤나 유용하다.

단점은 prototype1.5랑 함께 로드했더니 일부 메소드에서 에러가 난다.
같은 이름의 다른 메소드가 있어서 그런 듯 하다.
둘다 풀버전을 써서 그런건지..
prototype1.5랑 mootool의 모든 기능을 다 쓸수는 없는걸까.
아직은 그다지 불편하지 않으므로 패스...

앞으로는 mootool의 사용법도 차차 올려야겠다.


License
달리 정하지 않는 한, 이 저작물 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
Except where otherwise noted, this content is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 2.0 Korea License

+ Recent posts