파일을 업로드 할 서버가 마땅한 곳이 없어서 티스토리 스킨에 업로드했다.

http://goo.gl/b4qHK 에서 직접 확인 가능!

소스보기를 해보면 알겠지만 어떤 크기의 네모로직도 문제없도록 만들었다.


 

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

    안녕하세요 혹시 가능하다면 ㄴ ㅔ모로직 자바스크립트 소스 좀 구할 수 있을까요 ?

한RSS에서 돌아가는 코드


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

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

난 처음엔 시멘틱 웹이라는게 뭔지 몰랐다..
존재자체도 몰랐다

어느날 인터넷 여기저기서 웹 2.0이다 뭐다 하고 떠들어대고 난 후에 AJAX를 알았고
웹2.0에 대에 조사를 하기 시작했다.
AJAX를 코딩해보니 AJAX는 그냥 javascript라는걸 알게 되었다.
그리고 웹2.0에 대해 알면 알수록,
시멘틱웹에 대해 알면 알수록,
다 개소리라는걸 알았다.

그렇다.. 다 개소리다..

시맨틱웹? 웹2,0?
뜬구름잡는 이야기다.
그냥 웹이 발전될 뿐 웹2.0이라는 패러다임은 없다.
웹은 웹이다.



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

    맞는 얘기네요 ㅎ
    웹은 그냥 웹이고, 변경된 것 없이 기존기술을 쓴 것 뿐인데..

    • Widyou 2007.03.02 19:50 신고

      댓글 감사합니다.
      그렇죠. 기존기술의 간단한 응용을 2.0이라고 한다면 2.0붙일거 무지 많을거에요

  2. N.com 2007.05.24 18:58 신고

    말씀대로 2.0은 별 의미가 없죠.
    웹2.0하면서 예를 들은 서비스들을 보면 이미 한국에선 서비스하던 것들이 많고, 사실 외국이야기를 우리나라에도 들먹이는 듯한 느낌이 어느정도 있습니다.

    하지만, Ajax와 시멘틱웹은 다릅니다.
    개인적으로도 이름만 섞어놓은 Ajax라는 단어를 그렇게 긍정적으로 보는건 아니지만, 예전같으면 그냥 찔끔찔끔 DHTML이나 끄적여야 했던 자바스크립트들이 비동기통신을 만나면서 하나의 어플리케이션이 이뤄질 수 있는 수준까지 됨에 대한 파급효과는 상당하죠. 예전엔 ActiveX나 플래시나 자바어플릿이 아니면 죽어도 못할것이라 하는걸 웹브라우저 자체 해석엔진만 가지고도 전부 해낼 수 있게 됐습니다. 이정도라면 상징적 의미로 Ajax라는 단어를 쓰는데 큰 문제는 없다고 생각합니다.

    시멘틱웹도 마찬가지인데, 이 단어는 꼭 쓰지 않으면 안된다고 생각합니다. 아시다시핀 아직까지 보편적으로 사용되는 html코딩은 테이블기반의 야매코딩이 대부분이죠. 화면구성에만 신경을 쓰고 html문서 자체의 문서로써의 가치는 너무 떨어집니다. 그래서 사람들이 xhtml 표준코딩 해라 시멘틱한 코딩 해라 하는거죠. 제목은 <h1>태그해서 강조해주고! 디자인요소는 문서랑 큰 연관없으니 <div>하고 등등 식으로 적절하게 써주고 디자인은 css로 따로 빼버리는거죠. 그렇게 하면 html파일이 문서로써의 가치를 발휘할 수 있죠. 그래서 의미있는 웹인 시멘틱웹이라고 부르는 겁니다. 또, 이렇게 코딩하면 시각장애인분들도 손쉽게 사이트를 돌아다니실 수 있습니다. 이래저래 좋은거죠.

    • Widyou 2007.05.25 08:06 신고

      저도 이 포스팅을 쓸땐 시맨틱웹과 웹2.0의 차이를 잘 몰랐었습니다. 지금도 완벽하게는 이해가 부족하지만 시멘틱웹은 xhtml기반의 방탄웹정도로 해석하고 있습니다. 어떤 브라우저로 봐도 기획자의 의도대로 화면을 알수 있게 해주는 웹표준 같은거라고요.
      좋은 말씀 감사합니다.

+ Recent posts