블로그 이미지

카테고리

데꾸벅 (194)
Publisher (39)
Scripter (97)
AJAX (6)
COMET (1)
JAVASCRIPT (34)
EXTJS (50)
jQuery (5)
Prototype.js (1)
Programmer (1)
Designer (30)
Integrator (18)
Pattern Searcher (4)
News (2)
강좌 및 번역 (3)

최근에 올라온 글

최근에 달린 댓글

'Scripter/JAVASCRIPT'에 해당되는 글 34건

  1. 2010.02.04 offsetParent의 모든것!
  2. 2009.11.18 자바스크립트 delete 연산자에 대한 고찰 8
  3. 2009.01.12 Javascript로된 Wiki Parser : Creole 1.0
  4. 2008.12.03 자바스크립트 가이드
  5. 2008.11.12 JsonML 활용하기
  6. 2008.10.26 CSS & JAVASCRIPT 최적화 도구
  7. 2008.08.19 자바스크립트 단축키 사용 [Key Binding]
  8. 2008.07.30 자바스크립트 최적화(반복문)
  9. 2008.07.02 자바스크립트 코딩가이드 #1 1
  10. 2008.06.25 getBoundingClientRect in FF3 3
  11. 2008.06.24 FF3에서의 window.showModalDialog
  12. 2008.05.12 IE6에서 CSS로 fixed로 했을경우 고정되지 안는 문제 2
  13. 2008.05.08 Mouse wheel programming in JavaScript
  14. 2008.04.22 IE7에서 파일업로드 미리보기 기능
  15. 2008.04.17 IE에서 Javascript 로컬 실행(ActiveX 창뜰때) 8
  16. 2008.04.16 JSON에 대한 작은 단상 : JSON Diet 1
  17. 2008.04.15 HTML include하기
  18. 2008.04.01 FireFox에서 Fiddler 사용 및 Json Formatter설치 2
  19. 2008.03.29 Javascript and jQuery Talk
  20. 2008.03.28 XHTML1일때 스크롤링시 문제점
  21. 2008.03.28 자바스크립트로 루비프로그래밍을? 2
  22. 2008.03.27 IE8에서의 자바스크립트
  23. 2008.03.26 FF의 검색사이트 추가방법
  24. 2008.03.12 Protoflow : prototype.js를 이용한 Coverflow
  25. 2008.03.11 window.status in FF & IE7
  26. 2008.03.06 Browser detect
  27. 2008.03.06 IE7, FF3 에서 전체화면 팝업창 띄우기
  28. 2008.03.06 즐겨찾기 및 시작페이지 추가 IE FF모두 가능
  29. 2008.03.06 자바스크립트로 구현한 3D 포토갤러리
  30. 2008.03.06 JsonSQL: JSON parser, SQL style




이전에 getBoundingClientRect()에 대해서 포스팅한적이 있다.  이 함수는 객체의 페이지내의 위치값과 너비, 높이값을 반환한다. 편리하게 사용했었는데 오늘 역시 이부분을 짚고 넘어가야할 문제에 봉착했다.
기존에 데꾸벅이 2002년도에 제작해 지금껏 수정하면서 써오고 있는 캘린더가 IE8에서 동작하지 않는것이다. 문제는 각 브라우저에서 객체의 offsetParent 값을 계산하는 방법이 틀려서 생긴 문제였다. 특히 IE8....

처음에는 body를 못찾는 문제인줄 알았는데 IE에서의 객체 위치값을 표현하는 offsetParent값에 문제가 있다는 것을 알게되었다. 관련내용을 찾다가 아주 좋은 글을 발견(?)하여 포스팅한다.



아래는 HappyFriday님의 글을 인용한것임을 밝힌다.

언제나 그렇지만 항상 IE가 문제다.
크로싱을 위한 최고의 난적은 대부분 IE이다. 일단 offsetParent는 무엇일까? 말그대로 현재 대상 엘리먼트를 transform 하는 상위 엘리먼트를 참조하는 속성이다. 일반적으로 parentNode와는 다른 개념으로 이것은 concatenate 가 적용되는 부모 엘리먼트에만 유효하기 때문에...꼭 대상 엘리먼트의 상위엘리먼트를 의미하지는 않는다. 
일반적으로 이 속성에 대한 설명이 자식을 offset하는 엘리먼트라고 나와있는데.. 이해하기가 난해하므로... 자식엘리먼트의 위치에 영향을 미치는 상위 엘리먼트를 치칭 하는것으로 이해하면 되겠다.
그렇다면 자식엘리먼트에 영향을 미친다는건 무엇일까? 바로 position 속성이다. 모든 엘리먼트의 position속성은 기본이 static이다. 즉 정적상태를 유지하는것... 따라서 position이 relative / absolute가 되었을때 바로 자식엘리먼트에 영향을(좌표상으로) 미치게 됨으로offsetParent를 반환하는 대상 엘리먼트는 반드시 position이 relative나 absolute가 되어야 한다. 
즉 수식으로는 getStyle(obj, 'position) != 'static' 으로 표현될 수 있다.

일반적으로 offsetParent가 많이 사용되는 부분은 대상엘리먼트를 글로벌 좌표포지션으로 변환한 후 이값을 활용하는 곳들이다.
그런데..IE브라우져(ie8 이하)의 경우 상위 엘리먼트의 position이 'relative' 일때 자신의 offsetLeft가 0이 되어야 하는데 디폴트로 최상위 엘리먼트의  padding (paddingLeft/paddingTop)값을 취하도록 설계되어 있다. 이해를 돕기 위해서 다음 코드를 보자.

<div id='a' style='background-color:#ff0000; padding:30px; '>
    <div id='b' style='position:relative; background-color:#000000; '>
        <div id='c' style='position:relative; background-color:#0ff000; '>
            <div id='d' style='background-color:#666666;'>
                aaaa<br>
                aaaa<br>
            </div>
        </div>
    </div>
<div>

위의 노드중 d의 입장에서는 부모 position이 relative이기 때문에 당연 자신의 offsetLeft는 0이어야 한다.
왜냐면 상대경로로 다시 초기화 되었으니..부모입장에서 padding값이 들어간게 아니니까... 만약 부모의 position이 relative가 아니면 그제서야 부모 offsetParent가 static이 됨으로 그때는 자신이 30의 값을 가져야 한다. 그런데 IE7는 무조건 30의 값을 가지고 시작한다. 즉 최상위 a의padding(padding-left)이 30임으로 그값에 영향을 받아서 표시를 하게된다. 바로 이게 문제다. 이 문제로 인해 최종 글로벌 포지션의 left30이어야 함에도 불구하고 60이 되어버린다. 결국 이중값이 들어간다는 말이다.
따라서 IE7의 경우에는 바로 이 최상위 엘리먼트, 즉 body바로 밑의 엘리먼트를 구한후 (이것은 해당 엘리먼트가 position이 relativeabsolute 아닌경우 반환하지 않으므로) 해당 엘리먼트의 padding값을 빼줘야 한다.





참고적으로 캘린더 소스 :  
(이미 다른 자바스크립트 라이브러리를 사용하는 중이라.. 별~)

'Scripter > JAVASCRIPT' 카테고리의 다른 글

자바스크립트 delete 연산자에 대한 고찰  (8) 2009.11.18
Javascript로된 Wiki Parser : Creole 1.0  (0) 2009.01.12
자바스크립트 가이드  (0) 2008.12.03
JsonML 활용하기  (0) 2008.11.12
CSS & JAVASCRIPT 최적화 도구  (0) 2008.10.26
Post by 넥스트리소프트 데꾸벅(techbug)
, |



AJAX에서 XMLHttpRequest 객체 삭제

ajax 강의중 메모리에 있는 객체를 삭제시키는 방법에 대해서 질문을 하신 분이 있었는데 사실 명시적으로 null 로 처리하면 되나 좀더 깔끔한 방법을 소개하고자 한다.
function deletexhr(xhr) {
    function doNothing() {
    }
    xhr.onreadystatechange = doNothing; //onreadystatechagne를 더미함수로 대체    
    xhr.abort();                        //xhr 요청 중단
    delete xhr;                         //xhr 객체 밑의 모든 프로퍼티 삭제
}





자바스크립트에서 delete 연산자

자바스크립트의 delete연산자는 단항연산자로써 피연산자로 지정된 객체 프로퍼티, 배열원소 또는 변수의 삭제를 시도한다.
(C++ 프로그래머라면 자바스크립트의 delete연산자는 C++의 delete연산자와 전혀 닮지 않았다는 것을 발견할 것이다. 자바스크립트의 메모리 해제는 GC에 의해 자동으로 관리되기 때문에-순환참조 제외- 메모리를 직접 해제하는일에 신경 쓸 필요가 전혀없다.)

피연산자가 성공적으로 삭제되었을 경우 true를 반환하고, 삭제될 수 없는 경우 false를 반환한다. 모든 변수나 프로퍼티를 삭제할 수는 없다. 즉 객체자체는 삭제할 수 없으나 객체의 프로퍼티는 삭제할 수 있다는 것이다.  몇몇 핵심 프로퍼티나 클라이언트측 프로퍼티는 삭제하려 해도 소용으며  사용자가 var문으로 정의한 변수들도 삭제할 수 없다. 존재하지 않은 프로퍼티에 대해 delete을 호출할 경우 true가 반환되며 심지어 ECMAScript표준에 따르면 피연산자가 프로퍼티, 배열 원소 또는 변수가 아닐 경우에도 true를 반환한다고 명시되어 있다. 

var o = {           //변수 정의 및 객체 초기화
    x:1,
    y:2
}
delete o.x;         //객체 프로퍼티중 하나를 삭제한다. true 반환
typeof o.x;         //존재하지 않은 프로퍼티. "undefined" 반환
delete o.x;         //존재하지 않는 프로퍼티를 삭제하려한다. true반환
delete o;           //선언된 변수는 삭제할 수 없다. false 반환
delete 1;           //정수도 삭제할 수 없다. true 반환
x = 1;              //var 키워드를 사용하지 않고 암묵적으로 변수를 선언
delete x;           //이와 같은 변수는 삭제할수 있다. true반환
x;                  //런타임 에러, x는 삭제되었으므로 정의되지 않았다.


삭제된 프로퍼티나 변수, 배열원소는 단순히 undefined값으로 설정된 것이 아니라는 것을 주의하라. 어떤 프로퍼티가 삭제되면 그 프로퍼티는 더이상 존재하지 않는다.
한가지 중요한 점은, delete이 영향을 미치는 것은 오직 프로퍼티 뿐이며 해당 프로퍼티가 참조했던 객체는 무관하다는 것이다.
var my = new Object();      //'my'라는 이름의 객체를 생성
my.hire = new Date();       //my.hire는 Date객체 참조
my.fire = my.hire;          //my.fire도 동일한 객체 참조
delete my.hire;             //hire속성 삭제 true반환
document.write(my.fire);    //하지만 my.fire는 여전히 Date객체를 참조

javascript에서의 delete는 개체(object), 개체의 속성(property), 배열의 특정 인덱스에 있는 원소(element)를 지우는 연산자이며. 문법은 다음과 같다
delete objectNamedelete objectName.property
delete objectName[index]delete property // with 문장 안에서만 유효
objectName은 개체 이름이고, property는 개체에 존재하는 속성이고, index는 배열의 원소 위치를 나타내는 정수. 네 번째 형식은 개체의 속성을 지우는 코드인데, with 문장 안에서만 사용할 수 있다. 
암시적으로 선언된 변수를 지울 때는 delete 연산자를 사용할 수 있지만 단 var 문장을 이용해서 선언된 변수는 지울 수 없다. 
delete 연산자 실행이 성공하면, 속성이나 원소가 undefined로 설정되며. delete 연산자는 실행이 가능하면 true를 반환하고, 불가능하면 false를 반환하게 된다. 
var x=42;
var y= 43;
var myobj=new Number();
myobj.h=4;      // h라는 속성을 만듭니다
delete x;       // returns true (암시적으로 선언된 변수는 지울 수 있습니다)
delete y;       // returns false (var로 선언한 변수는 지울 수 없습니다)
delete Math.PI; // returns false (미리 정의된 속성은 지울 수 없습니다)
delete myobj.h; // returns true (사용자 정의 속성은 지울 수 있습니다)
delete myobj;   // returns true (암시적으로 선언되었으므로 지울 수 있습니다)

당연하지만 배열의 원소를 지워도, 배열의 길이에는 변화가 없게 된다. 즉 delete로 지우는 경우 원소는 더이상 배열에 존재하지 않게 된다(undefined). 하지만 delete와 배열원소에 undefined를 할당한 경우 조금 의미가 다르다. 
먼저 아래 예제에서 trees[3]을 delete로 제거한 예제이다. 
trees=new Array("redwood","bay","cedar","oak","maple");
delete trees[3];
if (3 in trees) {   // 이 블록은 실행되지 않는다.
   alert(trees[3]);
}
즉 trees라는 배열에는 trees[3] 이라는 배열원소 자체가 삭제(undefined)되어 실행되지 않지만 단지 배열 원소가 존재하긴 하지만 정의되지 않은 값을 가지도록 하고 싶다면 delete 연산자 대신 undefined 키워드를 사용하면 된다. 
다음은 trees[3]에 undefined 값을 할당하는 경우이다 
trees=new Array("redwood","bay","cedar","oak","maple");
trees[3]=undefinedif (3 in trees) {   // 이 블록은 실행된다.
}
undefined 키워드로 배열의 값은 정의되지 않았지만 배열원소는 유지되므로 블록은 실행된다







- PHPSCHOOL에서 - 

delete는 해당 변수를 삭제하는 용도로 주로 쓰입니다. C언어에서는 클래스를 삭제하는 등등 뭐 여러가지로 잘도 쓰이죠. 하지만 JS에서는 그닥 delete문은 쓰잘데기 없습니다. 기본적인 사용예제입니다.
var a=document.getElementsByTagName('div');
 for(i=0;i
a를 통해 div 태그를 모조리 뽑아온 다음 모조리 배경색을 초록으로 바꾸고 그변수를 버립니다. 물론 그 이후 a를 출력시키면 undefined로 나오죠. 뭐.. 객체 자체를 삭제할 수는 있지만 객체 안의 멤버를 삭제할 수는 없습니다.
 
delete a.member; 
이래봐야 결과값은 각설이처럼 죽지도 않고 또출력되네~ 입니다. 하지만 a의 동적 멤버, 즉, 프로토타입은 delete문으로 지울 수 있습니다. 
delete Integer.prototype.toUnsigned; 
물론 객체 자체를 삭제해야 하기 때문에 괄호를 붙이면 안되겠죠. 그렇다고 객체 자체가 삭제되지는 않으니 안심하세요. 어쨌든 이렇게 되면 잠시동안 프로토타입을 선언한 후 쓰다가 지울 수 있는 괴기한 스크립트를 만들 수 있겠습니다. 
Object.prototype.extend=function(obj){
       for(var x in obj)
           this[x]=obj[x];
       return this;
 }

var ob={
    a:'가',
    b:'나',
    c:function(){
        return '다';
      },
    d:4
};

ob=ob.extend({e:5,f:'라마바',g:(function(ret){return ret;})('사아자차카타파하')}); 
delete Object.prototype.extend; 
prototype 멤버를 delete로 삭제할 수 있다는 걸 알려주는것 뿐입니다.




자바스크립트에서의 가비지컬렉션

300.slimes님 블로그글중 일부발췌

먼저 순환 참조에 대한 일반적인 이해에는 Garbage Collector에 대한 간단한 작동 방식을 이해해야 된다.다음 코드를 보자.
var Vervain = new Herb();
var Verbena = Vervain;  


Vervena 가 객체 Vervain을 참조하게 되면 scope 내에 Vervain에 대한 참조카운트가 1이 증가한다. 그리고 실행이 끝나고, scope 를 벗어날 때 해당 scope 내에 Verbena는 파괴되게 된다. 그렇게 되면 Vervain 객체에 대한 참조카운트는 다시 1이 감소한다. 그렇게 되면 GC에서는 Vervain의 참조카운트가 0이 되었으므로 더 이상 사용하지 않는 객체로 판단하고 메모리를 해제하게 된다.하지만 다음과 같은 경우는 어떨까?

var Vervain = new Herb();
var Verbena = new Herb();  
Vervain.see = Verbena;  
Verbena.see = Vervain;  

Vervain과 Verbena는 서로를 참조하고 있다. 이러한 경우를 순환참조라고 한다. 객체에 대한 참조를 따라가 보면 완전한 연결고리를 형성하게 된다. 
하지만 위와 같은 경우는 어떻게 메모리를 해제해야 될까? 
Vervain과 Verbena의 참조카운트는 모두 1이다. Vervain 를 해제하기 위해서는 Vervain에 대한 참조카운트가 0이 되어야 하는데, 이는 Verbena.see 가 Vervain을 참조하고 있다. 
역으로 Verbena에 대한 참조카운트도 0이 되어야 하나 Vervain.see 는 Verbena를 참조하고 있다. 
결국 이러한 순환참조는 메모리 누수현상을 가져오게 된다. (IE 7에선 이러한 문제가 해결되었다.) 이러한 메모리 누수현상을 방지하기 위해서는 위와 같은 순환 참조를 형성하지 않거나, Vervain.see = null 혹은 Verbena.see = null 을 할당함으로써 참조카운트를 0으로 만들어 GC에서 메모리를 해제하게끔 만들어야 한다.






extjs에서 delete 연산자 사용확인

extjs-base.js파일을 까보았다. 객체를 소멸시킬때 사용하는 destroy함수에도 쓰이고 있었다.
//IE일 경우 모든 이벤트 및 프로퍼티 삭제
if(Ext.isIE) {
    function fnCleanUp() {
        var p = Function.prototype;
        delete p.createSequence;
        delete p.defer;
        delete p.createDelegate;
        delete p.createCallback;
        delete p.createInterceptor;
        window.detachEvent("onunload", fnCleanUp);
    }
    window.attachEvent("onunload", fnCleanUp);
}//객체 destory 처리
destroy : function(){
    Ext.each(arguments, function(arg){
        if(arg){
            if(Ext.isArray(arg)){
                this.destroy.apply(this, arg);
            }else if(Ext.isFunction(arg.destroy)){
                arg.destroy();
            }else if(arg.dom){
                arg.remove();
            }
         }
    }, this);
},
destroyMembers : function(o, arg1, arg2, etc){
    for(var i = 1, a = arguments, len = a.length; i < len; i++) {
        Ext.destroy(o[a[i]]);
        delete o[a[i]];
    }
},
remove : function(o){
    var index = this.indexOf(o);
    if(index != -1){
        this.splice(index, 1);
    }
    return this;
}











'Scripter > JAVASCRIPT' 카테고리의 다른 글

offsetParent의 모든것!  (0) 2010.02.04
Javascript로된 Wiki Parser : Creole 1.0  (0) 2009.01.12
자바스크립트 가이드  (0) 2008.12.03
JsonML 활용하기  (0) 2008.11.12
CSS & JAVASCRIPT 최적화 도구  (0) 2008.10.26
Post by 넥스트리소프트 데꾸벅(techbug)
, |


Beautifully Documented Code를 보다가 일전에 Wiki 관련 Parser에 대해서 관심을 가지게 되었다.
그때는 Java로 된, 혹은 Server side 언어쪽만 찾아봤었는데 이렇게 자바스크립트로 된 파서를 찾아서 꿈쳐둔다.

웹페이지를 퍼블리싱할때 디자인적인 측면이 많이들 강조된다. 타이포나 문장에 대한 배치등 그리드에 대한것도 전적으로 디자이너의 몫으로 넘기기 쉽다. 그러나 사실 이러한 문서 작업은 디자이너들 보다는 퍼블리셔나 산출물작업의 양만으로 따진다면 서버 프로그래머들의 작업량이 더 많다.

사내프로젝트를 진행하다가 든 생각중 하나가 실제 개발자들이 개발에 대한 지식이나 업무에 대해서 공유할수 있는 사이트를 만들어 보고 싶었다. 이슈(Trac, Bugzilla) 소스의 공유(CVS,SVN), 혹은 설계문서나 산출물들을 한곳에서 문서로 관리할수 잇다면 얼마나 좋을까 생각한것이 Wiki였다.  
Wiki를 만든다는것은 엄청난 자원의 손실이며 사실 마음에 드는 Wiki또한 없었다.  

뭐 잡설은 집어치고,  이전 레이텍(Latex)이나 HanTex과 같이 화면상에 문서를 구성할수 있게 실시간으로 스크립트를 이용해서 만들어 준다면 얼마나 좋을까? 바로 Creole Parser가 이러한 것을 가능하게 해주었다.
 





'Scripter > JAVASCRIPT' 카테고리의 다른 글

offsetParent의 모든것!  (0) 2010.02.04
자바스크립트 delete 연산자에 대한 고찰  (8) 2009.11.18
자바스크립트 가이드  (0) 2008.12.03
JsonML 활용하기  (0) 2008.11.12
CSS & JAVASCRIPT 최적화 도구  (0) 2008.10.26
Post by 넥스트리소프트 데꾸벅(techbug)
, |

 

스크립트 관련 레퍼런스

 

JavaScript 시작

  1. <script type="text/javascript" defer="defer">
  2. //<![CDATA[
    1. // defer="defer" 옵션을 지정하면, JavaScript에서 문서 내용을 생성하지 않는다는 의미이며,
    2. // 이 때문에, 브라우져는 자바스크립트를 로딩하기 전에 먼저 웹 페이지를 먼저 처리한다.
    3. // 이 옵션은 IE에서만 작동한다.(2008년 현재)
  3. //]]>
  4. </script>
  • JavaScript의 위치
    • <body> : 페이지를 로드할 때 동적으로 웹페이지의 컨텐트를 생성하는 경우
    • <head> : 함수 안에서 정의하고 page 이벤트에 사용되는 자바스크립트 코드, body 태그가 읽히기 전에 미리 읽히게 된다.
  • JavaScript 선언시 HTML 주석 <!-- -->으로 감싸지 말것. XHTML 규칙에 어긋난다.

 

var 키워드와 영역(scope)

  • 함수 내에서 var 키워드로 변수를 선언하면 함수내 영역에 종속된다.
  • 함수 내에서 var 키워드 없이 변수를 선언하면 전역 영역에 종속된다.
  • 함수 밖 전역 영역에서는 var 키워드 사용 유무에 관계 없이 무조건 전역 영역에 종속된다.
  • undefined : 변수를 선언해 놓고서, 값을 지정하지 않은 상태.

 

좋은 코딩 습관

  • 함수 안의 변수는 항상 "var"로 선언하라.
  • 자바스크립트의 유무와 관계없이 싸이트의 정보를 모두 사용할 수 있도록 하라(JavaScript를 끄고 코딩하기).
  • JavaScript 접근성 튜토리얼(영문)
  • noscript : JavaScript가 작동안하면 출력되는 정적인 코드를 <noscript>태그 안에 넣는다. JavaScript가 작동할 경우에는 무시된다.
  • Mozilla JavaScrip Style Guide
  • &&, || 연산시 CPU를 더 적게 사용하는 식을 왼편에 두면 효율성이 높아진다.
  • 인라인 이벤트 등록 방식은 되도록 피하고, Javascript를 이용한 기본 이벤트 등록 방식을 사용하라. (object.onevent=func)

 

형(Type)

  • object.toString()
  • object.toBoolean() : "",숫자 0, NaN, Null, Undefined 일경우에는 false 나머지는 모두 true
  • parseInt(string)
  • parseFloat(string)
  • Number(string)
  • isNaN(변수) : 변수가 숫자가 아니면 true
  • const CURRENT_MONTH = 3.4;  // CURRENT_MONTH 는 상수가 되었다.
  • 정수/정수의 결과가 실수가 될수도 있다. 3/2 == 1.5

 

연산자

  • "3.0" == 3.0 : true - 동등 연산자, ==, !=
  • "3.0" === 3.0 : false - 일치연산자, ===, !==

 

구문

  • for (varName in 연관배열) { statements...; }
  • if (value in [연관배열|배열|객체])

 

내장 클래스

  • Number 클래스
  • String 클래스 : 문자열("...")은 자동으로 String 객체로 변환된다.
  • Date 클래스 : 날짜 연산.
    • Date.now : 현재 시각
    • Date.parse : Unix Time millisecond
    • 웹 사용자에게 보여줄 시간은 Local 시간을, 국제적으로 시간 비교가 필요할 때는 UTC 사용.
  • Math 클래스 : 대부분 정적 프라퍼티, 정적 메소드
    • Math.random() : 0~1 사이의 난수
  • Array 배열
    • array.slice(2,4) : 지정 범위를 배열로 반환
    • array.concat(배열) : 배열 연결
    • array.join("구분자") : 배열의 값들을 "구분자"로 연결한 하나의 문자열로 변환
    • 콜백 함수관련 메소드들 : 이 메소드들은 FireFox 1.5 이상에서만 지원된다. IE 7 이하, Opera 9.2 이하에서는 지원되지 않는다. prototype.js 를 사용하면 어느 정도 지원해 준다.
      • 각 콜백 함수는 element, index, array 를 인자로 받는다.
      • array.filter(func) : 특정 조건을 만족하지 못하는 원소 제거. 조건 체크는 함수 인자가.
      • array.forEach(func) : 배열 원소를 함수 인자에서 처리
      • array.every(func) : 배열의 모든 원소에 대해 false 값이 반환될 때까지 콜백 함수 실행
      • array.map(func) : 배열의 모든 원소에 대해 콜백 함수를 실행하고 결과를 배열로 리턴
      • array.some(func) : 배열의 모든 원소에 대해 true 값이 반환될 때까지 콜백 함수 실행
    • 배열인덱스 사용하기
  1. var langs = new Array('a', 'b', 'c');
  2. for (var itemIndex in langs) {
  3. alert(langs[itemIndex];
  4. }
  • 연관배열 : HashMap
  1. var assocArray = new Object();
  2. assocArray["one"] = "one";
  3. assocArray["two"] = "two";

 

정규표현식

  • JavaScript 정규표현식 Tutorial
  • new RegExp('+s')/+s/ 와 같다.
  • /pattern/i,new RegExp('pattern', 'i') : 대소문자를 구분하지 않는다.
    • i : 대소문자 구분 안함
    • g : 전역 매칭. 마지막 매칭 위치를 기억하고 있다가, 또 다시 regexp.exec(string)이 호출되면 그 이후부터 검색한다.
    • m : 여러줄 매칭
  • 특수문자
    • * : 0회 이상 반복
    • + : 1회 이상 반복
    • ? : 0 또는 1개 문자
    • . : 1개 문자

 

  1. // 정규표현식 replace
  2. var regExp = /\s\*/g;
  3. var str = "This *is *a *test *string";
  4. var resultString = str.replace(regExp, '-');

 

 

  1. // 정규표현식 매칭되는 문자열 찾기
  2. var regExp = /:\D*\s\d+\sd+/;
  3. var str = "This is a date: March 12 2005";
  4. var resultString = str.match(regExp);

 

  • 괄호
    • 매칭(String.match(regex)) 결과를 ["전체매칭문자열","첫번째괄호에들어가는문자열", "두번째", ...] 형태의 배열로 리턴한다.
    • 각 괄호에 매칭된 문자열을 $1, $2, .. 로 나타내어 대체가 가능하다. str.replace(regExp, "$2-$1")
  • /s{2}/ : 문자 s가 2회 나온다.

 

함수

함수도 객체다.

  • 익명함수 : 읽을때마다 파싱
    • new func = new Function("인자1", "인자2", ..., "함수몸체");
  • 함수 리터럴 : 단 한번만 파싱
  1. var func = function (인자들) {
  2.     statements;
  3. }
  • 클로저(closure) : 다른 함수 내에서 내부 객체로 생성된 함수 리터럴을 반환하여 호출 프로그램에서 이를 변수로 배정한 것
  • 함수명.length : 인자의 개수
    • arguments[i] : 각 인자의 값을 순서대로 가지고 있다.

 

이벤트

  • QuriksMode JavaScript
  • IE 에서는 window.event 에 이벤트 객체가 저장된다.
  • FireFox/Mozilla/Opera 등은 이벤트 함수에 event 객체가 인자로 전달된다.
  1. // 브라우저에 무관한 이벤트 처리
  2. function eventProc(nsEvent) {
    1. var theEvent = nsEvent ? nsEvent : window.event;
    2. // 이벤트 처리..
  3. }
  • 이벤트 함수 내의 this는 이벤트를 발생시킨 객체를 의미한다.
  • DOM 2 : 한 이벤트에서 여러개의 함수 호출 가능
    • object.addEventListener('event', function, 이벤트처리방식boolean);
    • object.removeEventListener()
    • object.dispatchEvent()
    • IE 에서는 이를 지원하지 않는다.
      • object.attachEvent, object.detachEvent() 사용.
      • 각 이벤트가 메모리를 차지하므로, window.onunload 이벤트를 받아서 attach된 이벤트들을 모두 제거해줘야만 한다.
  • HTML의 인라인 이벤트 메소드들은 FireFox의 경우 event 라는 이름으로 변수를 설정해야 이벤트 객체가 전달된다.

    • 이벤트 객체 체크방식은 기존과 마찬가지로 IE와 FF 방식을 분리해서 하는 방식을 사용하면 된다.
    1. <img src="test.jpg" onclick="testinlinemethod(event, arg1, arg2, ...);" />

 

도메인

document.domain = "somecompany.com";

이후부터는 자바스크립트가 *.somecompany.com와 소통 가능.

 

BOM

  • window.open
  • self.method() : 현재 윈도우 자신에게 메소드 수행
  • opener.method() : 현재 윈도우를 열어준 부모 윈도우 참조
  • screen : 화면 정보 availTop, availLeft, availWidth, availHeight, colorDepth, pixelDepth

 

Tips



함수 function

 자바스크립트는 숫자, 문자열, 부울값등 기본적은 데이터형을 지원할 뿐만 아니라,
 기본 데이터 집합체인 객체(object)와 배열(array)등 두가지 복합 데이터 형(complex data type)도 지원한다.
 대부분의 언어와 달리 자바스크립트는 데이터 형으로서 함수도 지원하여 자바스크립트 프로그램을 문자열처럼 취급할 수 있게 해준다. 
 
함수가 변수, 배열, 객체에 저장될 수 있고, 함수가 인자로 다른 함수에 전달 될 수 있다.
 함수가 객체의 프로퍼티에 할당되는 경우에 이 함수를 객체의 메소드라고 한다.
 자바스크립트의 함수는 구문일 뿐만 아니라 데이터이기도 하다
 
 - 함수 호출 연산자 () : 고정된 피연산자 개수를 가지고 있지 않다. 
 
 - 자바스크립트에서 문장은 프로그램에서 동적인 동작을 수행하는 반면 함수 정의는 프로그램의 정적인 구조를 나타낸다.
   문장이 실행 시간(runtime)에 수행되는 반면 
함수는 자바스크립트 코드가 파싱되거나 컴파일될 때 정의된다.
   자바스크립트 파서가 함수 정의를 만나면 그것은 함수의 본문을 구성하는 문장을 파싱하고 저장한다. (실행하지는 않는다.)
   그리고 나서 그 함수를 나타내는 이름과 같은 이름의 프로퍼티를 정의한다.

    alert(f(4));      // 16을 출력한다. f()는 그것이 정의되기 전에 호출쇨 수 있다.

                        // 단, 이벤트 핸드러에서 함수를 호출할 경우에는 미리정의 되어 있어야 한다.
    var f=0;          // f의 프로퍼티를 재설정한다.
    function f(x){  // 이 문장은 위 두 행이 실행되기 전에 함수 f를 정의한다.
       return x*x;
    }
   alert(f);           // 0을 출력한다. f()는 변수 f에 의해 재설정 된다.

위와 같은 결과가 나온 이유는 함수 정의가 변수 정의와 다른 시점에 발생하기 때문이다.


 -  a.sort(function(a,b){return a-b;});      // 함수를 정의하고 그것을 다른 함수에 전달
    var s = (function(x){return x*x;})(10); // 정의와 호출을 동시에


 arguments 객체 - 함수의 인자

arguments는 arguments 객체를 참조하는 호출 객체의 특정한 프로퍼티이다.
- arguments[] 배열의 요소는 함수에 전달된 인자의 값을 가지고 있다.
- 인자에 이름이 없더라도 해당 인자의 값에 접근할 수 있게 해준다. ex) arguments[0]


 콜백 함수

메소드 실행 시에 자동으로 호출되는 함수가 있다. 그러한 메소드로 filter, forEach, every, map, some이 있으며,

이때 사용되는 함수는 함수 리터럴로 일반적으로 콜백 함수라고 한다.


 함수 클로저

자바스크립트 프로그램에서는 새로운 영역을 생성할 때마다 이를 둘러싸기 위한 '연관 영역 버블'이 생성된다.

이는 함수에도 적용되며, 해당 함수는 자신의 영역에서 동작하게 된다.

function outFunc(base){   // 바깥쪽 함수

      var punc = "!";

      function inFunc(ext){   // 안쪽 함수

             return base + ext + punc;

      }

      return returnString;

}

일반적으로 함수가 종료되면, 그 영역에서 해제된다. 왜냐하면 더 이상 필요치 않기 때문이다.

하지만 안쪽 함수의 경우엔 이것이 바깥쪽 프로그램에 반환되고 외부 변수에 할당된다.

즉, 안쪽 함수의 영역이 바깥쪽 함수의 영역에 추가되고, 결국 호출 프로그램에 추가되는 것이다.

따라서 함수 리터럴 및 바깥쪽 함수의 인자와 변수를 유지하게 된다. 다른 함수 내에서 내부 객체로 생성된

함수 리터럴을 반환하여 호출 프로그램에서 이를 변수로 배정한 것을 자바스크립트에서는 클로저(closure)라고 한다.

즉, 함수가 동자하는 데 필요한 데이터 영역이 확장되는 것이다.

 

 

 

 callee 프로퍼티 
현재 실행되고 있는 함수를 참조, 이름이 없는 함수가 자기 자신을 호출할 때 유용하다.

 function(x){
    if(x>1) return x * arguments.callee(x-1);
    return x;
  }




 caller 프로퍼티 
현재 호출된 함수를 참조하는 것이 아니라 현재 호출된 함수의 arguments 객체를 참조한다.
 

 apply() 메소드 
함수를 마치 다른 객체의 메소드처럼 호출할 수 있게 해준다.




 객체 object

이름이 지정된 데이터의 여러 가지 부분을 포함하는 데이터 구조로, 이 데이터를 처리하기 위한 여러가지 메소드도 포함한다.
객체는 관련된 데이터 값과 메소드를 사용하기 쉽게 단일 패키지 안에 모아두기 때문에 코드의 모듈성(modularity)과 
재사용(reusability)을 증가시켜서 전반적으로 쉽게 프로그램을 작성할 수 있다.


- 객체 == 이름과 값을 가진 '프로퍼티(property)'의 집합
- 자바스크립트에서 객체는 임의의 수만큼 프로퍼티를 가질 수 있고, 객체에 동적으로 프로퍼티를 추가할 수 있다.


 

 객체생성 연산자 new

 - 객체 생성 var obj = new Object();
(delete : 객체의 프로퍼티, 배열의 요소를 삭제하거나 정의되지 않은 값으로 만든다.)
 

 객체접근 연산자 . / []

- [] 연산자를 사용하면 배열의 요소에 접근할 수 있고 객체의 프로퍼티에도 접근할 수 있다.


 생성자

자바스크립트에서는 new 연산자와 미리 정의된 Object(), Date(), Function() 같은 함수들을 이용하여

새로운 객체를 만들거나 초기화 할 수 있다. 그러나 사용자가 직접 객체형을 정의하여 사용하는 경우가 더 많다.
예를 들어, 사각형을 처리하는 Rectangle 클래스에 width, height 프로퍼티가 있을때,
width, height 같이 이미 정의된 프로퍼티를 가지는 객체를 생성하려면 새로운 객체를 생성하고
이 프로퍼티들을 초기화 할 수 있는 '생성자(construnctor)'가 필요하다.

- 생성자는 new 연산자를 통해 호출된다.
- 생성자는 this라는 특수 키워드의 값으로 새롭게 생성된 빈 객체의 참조를 넘겨 받아서  새로은 객체를 적절하게 초기화 한다.

// 생성자 함수 정의
  function Rectangle(w, h){
   this.width = w;
   this.height = h;
  }

// 객체를 생성하기 위해 생성자 함수를 호출, w, h를 전달해서 새로운 객체를 적절한 값으로 초기화한다는 것을 주의

var rect1 = new Rectangle(2,4);




- 생성자 함수는 일반적으로 반환 값이 없으며 this 값으로 넘겨받은 객체를 초기화하고 아무값도 반환하지 않는다.
  그러나 객체를 반환할 수는 있으며 그럴 경우에 반환되는 객체는 new 표현식의 값이된다. 이 경우에 this의 값의 객체는 버려진다.


 메소드 method 
객체에서 호출되는 함수


 prototype 프로퍼티

모든 함수에는 미리 정의된 '원형(prototype) 객체'를 참조하는 prototype 프로퍼티가 있다.
모든 객체는 원형을 가지므로 객체는 그것의 원형이 가진 프로퍼티를 모두 상속받는다.
이는 객체의 모든 프로퍼티가 그것을 상속한 객체의 프로퍼티처럼 보인다는 의미이다.
객체의 클래스에 대한 원형 객체를 지정하려면 적절한 객체에 생성자 함수의 prototype 프로퍼티의 값을 설정한다.
그 다음에 생성자로 새로운 객체를 호출할 때 자동으로 자바스크립트는 지정한 객체를 새로 생성되는 객체의 원형으로 사용한다.


 - 생성자 함수는 객체의 클래스를 정의하고, 클래스의 상태 변수로 사용되는 width, height 같은 프로퍼티를 초기화 한다.
   원형 객체는 생성자와 결합하므로 클래스의 각 멤버들은 원형으로부터 정확하게 똑같은 프로퍼티 집합을 상속받는다.
   이는
 원형 객체가 메소드나 다른 상수 프로퍼티를 정의하기에 가장 이상적인 위치라는 것을 의미한다.


 - 상속(inheritance)은 프로퍼티 값을 검색하는 과정의 일부로서 자동으로 발생한다.
   프로퍼티는 원형 객체로부터 
새로운 객체로 복사되는 것이 아니며 단지 해당 객체의 프로퍼티인 것처럼 보이는 것 뿐이다.


 - 원형 객체를 사용하여 프로퍼티를 상속할 수 있으므로 각 객체를 만들 때 필요한 
메모리의 양을 크게 줄일 수 있다.


 - 객체는 생성된 후에 원형에 
추가된 프로퍼티 값도 상속받을 수 있다.


 - 각각의 클래스에는 하나의 프로퍼티 집합을 가진 하나의 원형 객체가 있다.
   그러나 이 클래스로부터 많은 인스턴스를 만들 수 있고, 각 인스턴스에서는 원형의 프로퍼티를 상속받게 된다.
   객체 o의 프로퍼티 p를 읽을 때 자바스크립트는 먼저 o에 p라는 프로퍼티가 있는지 검사한다.
   p가 없는 경우에는 o의 원형 객체에 p라는 이름을 가진 프로퍼티가 있는지 검사한다.
   이것은 원형을 바탕으로 한 상속 작업이다.


  
프로퍼티 상속은 프로퍼티 값은 읽을 때만 발생하고 프로퍼티 값을 쓸 때는 발생하지 않는다.
   원형으로 부터 프로퍼티를 상속받은 객체 o에서 프로퍼티 p의 값을 설정하면 객체 o에서 직접 "새로운 프로퍼티 p가 생성"된다.
   이렇게 되면 객체 o는 p라는 이름이 지정된 자신만의 프로퍼티를 가지게 되고, "
그 결과로 객체의 원형으로부터 p의 값을
   더이상 상속 받을 수 없게 된다." (이때 원형의 프로퍼티 p는 가려진(shadow), 숨겨진(hide) 프로퍼티라고 부른다.)


  
 인스턴스 instance

클래스에 기초한 객체지향 언어와 자바스크립트에서는 같은 클래스에 여러 객체를 사용할 수 있다.
이런 객체를 클래스의 인스턴스라고 한다. == 클래스 안의 객체

- 인스턴스 변수
  모든 객체에는 자신만의 분리된 인스턴스 변수 복사본이 있다. 다시 말해 어떤 클래스에 10개의 객체가 있다면
  10개의 인스턴스 변수가 있는 셈이다.  예를 들어 Circle 클래스에서 모든 circle 객체에는 원의 반지름을 정의하는 프로퍼티 r이 있다. 
  이런 경우에 r은 인스턴스 변수이다.

   각 객체에는 자신만의 인스턴스 변수 복사본이 있으므로 각각의 객체를 통해 이 변수에 접근할 수 있다.
   객체의 프로퍼티 == 인스턴스 변수
 
- 인스턴스 메소드
  인스턴스 메소드는 this 키워드를 사용하여 처리하고 있는 객체나 인스턴스를 참조한다. 
  클래스의 모든 인스턴스에서 호출할 수 있지만 이것이 인스턴스 변수처럼

  모든 객체에서 자신만의 메소드 복사본을 가진다는 의미는 아니다.

  대신에 모든 클래스의 인스턴스는 인스턴스 메소드를 모두 공유한다.


 


 garbage collector 
자바스크립트에서는 수동으로 메모리를 반환하는 대신에 이 작업을 '가비지 수집(garbage collection)'이라는 기술에 맡긴다.
인터프리터는 프로그램에서 더 이상 쓰이지 않는 객체를 검색할 수 있다.
객체가 접근하기 어려운 위치(프로그램에서 변수가 더 이상 그 객체를 참조하지 않을 경우)에 있으면
인터프리터는 그 객체가 더 이상 필요하지 않다고 판단하고 그 객체에 사용된 메모리를 해제한다.

 var s = "hi";    // 문자열에 메모리를 할당
 var u = s.toUpperCse(); // 새로운 문자열을 생성
 s = u;     // 원래 문자열에 참조를 엎어씀



이 코드가 실행된 후에는 원래 문자열 "hello"에 더 이상 접근 할 수 없다.


 - 가비지 콜렉터 대부분은 
'표시, 제거(mark and sweep)' 라고 알려진

   기본적인 가비지 콜렉션 알고리즘을 약간씩 변형시켜서 사용한다.


 표시, 제거 mark and sweep

- 주기적으로 자바스크립트 환경에서 사용되는 모든 변수 목록을 검색한다.
   그리고 이 변수들이 참조하는 값에 표시를 한다.

   참조한 값이 객체나 배열이면 가비지 수집기는 그 객체의 프로퍼티나 배열의 요소에 표시를 한다.

   가비지 수집기는 값들로 이루어진 그래프와 트리를 순환적으로 검색하여 사용되고 있는 각각의 값에 표시를 할 수 있다.

   이러한 작업을 마친 후에 표시되지 않은 것은 가비지가 된다.


- 표시, 제거 가비지 수집기가 현재 사용되고 있는 값에 표시하는 작업을 끝낸 후에는 제거 단계를 수행한다.
   이 단계를 진행하는 동안 그 환경에서 사용되는 모든 값 목록을 찾고, 표시되지 않은 것에 할당되었던 메모리를 반환한다.
   전형적인 표시, 제거 가비지 수집기는 표시 작업과 제거 작업을 동시에 한다.
   이러한 작업은 가비지 수집을 수행하는 동안 시스템의 성능을 현저히 떨어뜨린다.
   좀더 정고하게 변화된 알고리즘은 상대적으로 작업을 효율적으로 처리하며, 시스템의 성능을 저하시키지 않고 
   백그라운드에서 수집 작업을 수행한다.



좋은 자료를 제공해 주신분은... (여기... )
Post by 넥스트리소프트 데꾸벅(techbug)
, |

참고 : IBM Developer Site

JavaScript Object Notation (JSON)과 Asynchronous JavaScript + XML (Ajax)은 나란히 성장하고 있습니다. JSON은 JavaScript 객체로 바뀔 수 있는 데이터를 쉽게 전송할 수 있지만, 이 객체를 다루기 위해 커스텀 스크립팅이 필요합니다. JsonML은 JSON의 확장으로, JSON 유형 마크업을 사용하여 XML 데이터를 매핑하고, 이는 JSON 마크업에 기반하여 XML이나 XHTML 데이터를 쉽게 생성할 수 있고 사용자 인터페이스(UI) 엘리먼트를 쉽게 구현 및 교환할 수 있도록 합니다. 이 글에서, 이 편리한 툴을 사용법을 설명합니다

Ajax로 데이터 교환하기

Ajax 인터페이스가 가진 가장 일반적인 문제들 중 하나는 클라이언트 브라우저와 호스트 서버 간 정보 교환에 인코딩 및 사후 처리(post-processing) 또는 데이터 스트림을 JavaScript 애플리케이션 내에서 직접 사용할 수 있는 것으로 변환하는 파싱이 필요하다는 점이다.

Ajax에서, 캡슐화 방식은 XML이다. 전 세계적인 공통 이해를 기반으로 사용되고 있지만 문제와 한계도 안고 있다. XML의 기본적인 문제는 인코딩 프로세스가 비싸고, 대부분의 브라우저에서, XML 응답의 디코딩(decoding)에 시간이 많이 든다는 점이다.

Ajax 애플리케이션을 사용하면, 요청은 폼의 콘텐트에 기반하게 된다. 응답은 서버에 의해 리턴되는 정보가 자바 객체 시리즈로 표현된다. 결과 시퀀스는 그림 1과 비슷하다.


그림 1. 전형적인 Ajax 프로세스


 

그림 1의 프로세스는 두 가지 문제를 갖고 있다.

  • 첫 번째는 XML로 작동하는 것이 매우 복잡하다. XML을 처음부터 생성하든, 서버에서 XML을 소비하든, 프로세스는 시간이 많이 걸리고 지루하고, 대게는 비효율적이다.
  • 다른 문제는 데이터를 디스플레이 포맷으로 변환하는 것이 복잡하다는 점이다. DOM 모델을 사용하여 직접 UI 엘리먼트를 구현하든지, 사전 포맷된 XHTML로 데이터를 제공해야 한다. 후자 방식은 서버가 UI 엘리먼트를 제공해야 한다. (이 자체로 위험한 발상이다.) 전자는 오버헤드를 프로세스에 추가하게 된다.

DOM 모델은 다른 웹 브라우저들과 환경이 다른 DOM 구조와 인터페이스를 갖고 있다는 사실에도 영향을 받는다. 이는 여러분이 로딩하는 정보의 디스플레이에도 복잡성을 추가하게 되고, 이는 전혀 원하던 바가 아니다.

이러한 문제에 대한 솔루션이 많이 있다. 첫 번째 솔루션은 XML 포맷에서 JSON으로 데이터가 교환되는 방식을 변경하는 것이다. 이 부분은 이 글의 초점은 아니지만, JSON을 이해하면 JsonML을 더욱 쉽게 이해할 수 있을 것이다. JsonML은 정보의 실제 디스플레이를 더욱 쉽게 만드는 또 다른 솔루션도 제공한다. 먼저 JSON부터 보도록 하자.




위로


JSON 이해하기

JavaScript Object Notation (JSON)은 XML 사용, 콘텐트의 파싱, JavaScript 표준 기능을 사용하여 정보를 교환함으로써 가용성 있는 내부 구조로의 변환을 통해 대부분의 문제를 해결하려고 한다.

JSON의 중심은 여전히 텍스트 포맷이지만, 가독성이 더욱 강화되었고, 많은 언어들(Perl, PHP, Python, Java, Ruby)로 중첩된 데이터 객체들을 생성하는 방식과 호환되고, 이는 JavaScript 객체 포맷(중첩된 데이터 구조)와 잘 맞는다.

Listing 1처럼, XML로 비즈니스 리스트를 모델링 한다.


Listing 1. XML 주소 데이터
                
<business>
<name>One on Wharf</name>
<address>
    <street>1 Wharf Road</street>
    <town>Grantham</town>
    <county>Lincolnshire</county>
</address>
<phonenumbers>
    <phone>01476 123456</phone>
    <phone>01476 654321</phone>
</phonenumbers>
</business>

JavaScript 내에서 파싱 하려면 DOM 모델을 사용하여 컴포넌트에 액세스 해야 한다. 예를 들어, JavaScript 내 이 구조에서 전화 번호를 얻으려면, Listing 2의 코드를 사용해야 한다.


Listing 2. XML 데이터를 소비하는 웹 애플리케이션
                
<html>
<head>
<script type="text/javascript">
var xmlDoc;
function loadXML()
{
// code for IE
if (window.ActiveXObject)
  {
  xmlDoc=new ActiveXObject("Microsoft.XMLDOM");
  xmlDoc.async=false;
  xmlDoc.load("/json/address.xml");
  getaddress();
  }
// code for Mozilla, Firefox, Opera, etc.
else if (document.implementation &&
document.implementation.createDocument)
  {
  xmlDoc=document.implementation.createDocument("","",null);
  xmlDoc.load("/json/address.xml");
  xmlDoc.onload=getaddress;
  }
else
  {
  alert('Your browser cannot handle this script');
  }
}
function getaddress()
{
document.getElementById("business").innerHTML=
xmlDoc.getElementsByTagName("name")[0].childNodes[0].nodeValue;
document.getElementById("phone").innerHTML=
xmlDoc.getElementsByTagName("phone")[0].childNodes[0].nodeValue;
document.getElementById("fax").innerHTML=
xmlDoc.getElementsByTagName("phone")[1].childNodes[0].nodeValue;
}
</script>
</head>
<body onload="loadXML()">
<h1>Address</h1>
<p><b>Business</b> <span id="business"></span><br />
<b>Phone:</b> <span id="phone"></span><br />
<b>Fax:</b> <span id="fax"></span>
</p>
</body>
</html>

Listing 2의 코드는 단 1 개의 주소 정보만 얻었고, 다음 로직을 사용하여 비즈니스 이름 같은 원래의 XML 문서 엘리먼트에 액세스 한다. xmlDoc.getElementsByTagName("name")[0].childNodes[0].nodeValue.

좋아 보이지는 않는다!

JSON에서 같은 정보를 보자. (Listing 3)


Listing 3. JSON 버전의 주소 데이터
                
{
    "business" : {
        "name" : "One on Wharf",
        "address" : {
            "street" : "1 Wharf Road",
            "town" : "Grantham",
            "county" : "Lincolnshire",
        },
        "phonenumbers" : [
                          "01476 123456",
                          "01476 654321",
                          ]
                      }
}

구조가 훨씬 읽기 쉽고 간단하다. JSON에 사용된 마크업 포맷은 eval()을 사용하여 파서 없이도 JavaScript에서 직접 계산될 수 있다. 그리고 결과는 또 다른 JavaScript 객체이다: var addressbookObj = eval('(' + jsontext + ')');.

주: 이상적으로는 eval()을 사용해서는 안된다. 임의의 텍스트를 실행하는데 사용될 수 있기 때문이다. JSON 텍스트만 파싱하는 많은 JSON 파서들이 있다.

정보가 JavaScript 내 객체라면, 표준 JavaScript 표기법을 사용하여 정보에 액세스 할 수 있다. 예를 들어, 객체로 파싱 되었던 JSON 데이터 소스에서 같은 이름과 전화 번호를 얻을 수 있다. (Listing 4)


Listing 4. 객체로 파싱된 JSON 데이터 소스
                
addressbookObj.business.name
addressbookObj.business.phonenumbers[0]
addressbookObj.business.phonenumbers[1]

Listing 4는 사용하고 액세스 하기가 더욱 간단하고 쉽다. 위 데이터 구조를 사용하고 원래의 XML 예제와 같은 정보를 제공하는 전체 페이지를 작성할 수 있다. (Listing 5)


Listing 5. JSON 데이터를 소비하는 웹 애플리케이션
                
<html>
<head>
<script type="text/javascript" src="prototype.js"></script>
<script type="text/javascript">

function showaddress(req)
{
    var addressbookObj = eval('(' + req.responseText + ')');

    document.getElementById("business").innerHTML = 
       addressbookObj.business.name;
    document.getElementById("phone").innerHTML = 
       addressbookObj.business.phonenumbers[0];
    document.getElementById("fax").innerHTML = 
       addressbookObj.business.phonenumbers[1];
}

function getaddress()
{
   new Ajax.Request('address.json',
                    { method : 'get',
                      onSuccess : showaddress,
                      onFailure: function(){ 
              alert('Something went wrong...') }});
}
</script>
</head>
<body onload="getaddress()">
<h1>Address</h1>
<p><b>Business:</b> <span id="business"></span><br />
<b>Phone:</b> <span id="phone"></span><br />
<b>Fax:</b> <span id="fax"></span>
</p>
</body>
</html>

필자는 여기에서 Prototype 라이브러리를 사용하여 원래 JSON 파일을 로딩했지만, JSON 파일에 있는 정보를 실제로 파싱하고 디스플레이 하는 프로세스가 훨씬 더 간단하다는 것을 알 수 있다. 하지만, 여전히 DOM을 사용하여 JSON 파일에서 로딩되었던 정보로 아웃풋을 채워야 한다.

원래 JSON으로 돌아가서, JSON은 전송되는 데이터의 관점에서 볼 때 비교적 작고, 더 큰 Ajax 프로젝트에서 XML의 페이로드 오버헤드는 상당하다. 실제로 콘텐트를 처리하는 감소된 JavaScript 오버헤드와 이것을 합병할 때 오버헤드가 크다.

Listing 5의 예제는 JSON 표준의 단순함을 보여준다. 대부분의 Ajax 애플리케이션의 핵심은 정보 디스플레이의 커스터마이징이다. 이 예제에서, 여러분은 DOM 모델을 사용하여 XML 또는 JSON 데이터 콘텐트를 HTML 페이지로 삽입했다. 많은 Ajax 애플리케이션에서, 구현해야 할 더 복잡한 사용자 인터페이스 엘리먼트가 있다.






JsonML

JSON Markup Language는 JSON 데이터 교환 포맷의 기본 방식을 사용하고 이를 XML 표현에 적용하여 비슷한 텍스트 기반 마크업을 사용하여 XML 포맷 데이터를 교환할 수 있다.

XML을 직접 사용하는 대안으로서 XML 데이터를 모델링 하는 표기법 포맷으로 보인다. 하지만, 원래의 XML과 비교해서 JSON의 구조와 가독성을 생각해 보라. JsonML에서, 많은 장점들을 활용할 수 있다. 가독성과 데이터 크기는 분명한 이점이 된다.

JsonML의 주 초점은 UI 엘리먼트를 구현하는 툴로서이다. 전통적으로, 여러분은 이러한 종류의 브라우저 기반 사용자 인터페이스를 개발하는 두 가지 방식을 갖고 있다.

  • 서버에서 XHTML을 생성하여 DOM 객체의 innerHTML 애트리뷰트를 사용하여 현재 페이지로 삽입한다.
  • 클라이언트 DOM 인터페이스를 사용하여 DOM 구조를 직접 구현한다.

여러분도 보다시피, 이것은 다소 성가신 방법이다. 대형 데이터 세트의 경우, 포맷팅이라는 반복적인 특성이 프로세스를 혼돈시킬 수 있다. 게다가, 브라우저에 민감한 DOM 구현들을 다루는 문제도 있다.

바로 이것이 JsonML이 해결하고자 하는 것이다. JSON 마크업의 단순함과 대상 포맷으로서 DOM을 혼합한다. 여러분은 같은 효과를 볼 수 있다. 소스는 JavaScript 클라이언트에 의해 쉽게 로딩 및 파싱될 수 있다. (DOM 구현에 대해서는 걱정할 필요가 없다.) 또한, 여러분은 JsonML 문서에 모든 것을 기술할 수 있기 때문에, 데이터와 마크업을 하나의 파일로 효과적으로 삽입할 수 있다.

그림 1로 다시 돌아가면, Ajax 인터페이스를 통해 복원된 정보를 디스플레이 하는 전형적인 방식에는 데이터를 요청하고, XML을 파싱하고, XML을 브라우저에서 요구하는 DOM 구조로 변환하고, 아웃풋을 실제로 디스플레이 하는 것이 포함된다.

JsonML을 사용하여, 전체 XML, XHTML, DOM, JavaScript 단계를 하나의 단계로 대체할 수 있다.






JsonML 마크업

JsonML 예제를 보기 전에, JsonML의 구조부터 살펴보자. 이 구조의 공식 포맷은 Listing 6과 같다.


Listing 6. JsonML 마크업 포맷
                
element
    = '[' tag-name ',' attributes ',' element-list ']'
    | '[' tag-name ',' attributes ']'
    | '[' tag-name ',' element-list ']'
    | '[' tag-name ']'
    | json-string
    ;
tag-name
    = json-string
    ;
attributes
    = '{' attribute-list '}'
    | '{' '}'
    ;
attribute-list
    = attribute ',' attribute-list
    | attribute
    ;
attribute
    = attribute-name ':' attribute-value
    ;
attribute-name
    = json-string
    ;
attribute-value
    = json-string
    ;
element-list
    = element ',' element-list
    | element
    ;

복잡해 보이지만, 기본 구조는 매우 간단하다.

모든 엘리먼트는 텍스트이기 때문에 [ "ul" ] 같은 un-numbered list 엘리먼트를 만들 수 있다.

대괄호는 엘리먼트를 논리적으로 그룹핑 한다. 애트리뷰트를 이 엘리먼트에 추가하려면, 이 그룹 안에서 리스트의 다음 엘리먼트로서 중괄호를 사용한다. 예를 들어, 스타일을 변경하려면 다음과 같이 한다: [ "ul", { style : "list-style-type:none"} ].

물론, 이 리스트는 자식이 없이는 소용이 없다. 이들은 같은 리스트에 추가 엘리먼트로서 추가된다. (Listing 7)


Listing 7. 자식이 있는 리스트
                
[ "ul", { style : "list-style-type:none"}, 
    [ "li",
      "First item"],
    [ "li",
      "Second item"],
    [ "li",
      "Third item"],
    ];

아이템에 대한 애트리뷰트는 선택적이기 때문에, 생략할 수 있다. (Listing 7)






JsonML을 XHTML로 파싱하기

위 예제는 JSON이기 때문에, JavaScript 애플리케이션 내에서 정의할 수 있다. 콘텐트를 XHTML로서 디스플레이 하는 객체로 파싱하려면, JsonML 웹 사이트에서 JsonML 라이브러리를 가져온다. JsonML에서 JSON 객체를 XHTML로 파싱하려면 parseJsonML() 메소드를 사용한다. JsonML이 파싱되면, 페이지에 추가할 수 있는 UI 엘리먼트로서 액세스 할 수 있다.

Listing 8은 제공된 링크를 클릭할 때 마다 불리트(bulleted) 리스트를 사전 정의된 컨테이너에 추가할 전체 웹 페이지 모습이다.


Listing 8. JsonML 템플릿을 디스플레이 하는 웹 애플리케이션
                
<html>
<head>
<script type="text/javascript" src="JsonML.js"></script>
<script type="text/javascript">

var listblock = [ "ul",
                  [ "li",
                    "First item"],
                  [ "li",
                    "Second item"],
                  [ "li",
                    "Third item"],
                  ];

function addblock (id,jsonmlblock)
{
    var aselement = listblock.parseJsonML();
    var container = document.getElementById(id);
    container.appendChild(aselement);
}

</script>
</head>
<body>
<a href"#list" onclick="addblock('container', 
 listblock);return false;">Add block</a>
<div id="container"/>
</body>
</html>

그림 2는 웹 페이지 실행 모습이다. 페이지로 반입된 불리트 리스트와 함께 2회 정도 링크가 클릭된 후 보여지는 보습이다.


그림 2. JSON 예제 실행 모습
JSON 예제 실행 모습

예제를 단계 별로 살펴보자. 첫 번째 블록은 리스트 아이템을 나타내는 JsonML이다. (Listing 9)


Listing 9. 리스트 아이템을 나타내는 JsonML
                
var listblock = [ "ul",
                  [ "li",
                    "First item"],
                  [ "li",
                    "Second item"],
                  [ "li",
                    "Third item"],
                  ];

이것은 단순한 JavaScript 객체이다. 사용자가 링크를 클릭하면, addblock() 함수가 호출된다. 단 세 단계만 거친다. 첫 단계는 JavaScript 객체를 XHTML로 파싱하는 것이다. parseJsonML() 메소드를 적용한다: var aselement = jsonmlblock.parseJsonML();.

이제 목적지 컨테이너를 얻는다: var container = document.getElementById(id);.

마지막으로, 생성된 XHTML을 추가하고 이를 컨테이너에 붙인다: container.appendChild(aselement);.






기존 XHTML이나 XML을 JsonML로 파싱하기

JsonML을 사용하는 애플리케이션을 구현하기 전에, JsonML로 변환하고자 하는 XML 또는 XHTML 구조가 있어야 한다. JsonML 사이트(참고자료)에서는 XML 소스에서 JsonML을 만들어 내는 XSL 변형을 제공한다.

이를 사용하려면, JsonML.xsl 변형을 다운로드 한 다음, xsltproc을 사용하여 변환을 수행한다. Listing 10의 XML 구조를 보자.


Listing 10. XML 구조
                
<table class="maintable">
<tr class="odd">
<th>Situation</th>
<th>Result</th>
</tr>
<tr class="even">
<td><a href="driving.html" title="Driving">Driving</a></td>
<td>Busy</td>
</tr>
...
</table>

Listing 10을 JsonML로 변환할 수 있다: $ xsltproc JsonML.xsl.xml samp.xml.

결과 아웃풋은 Listing 11에 나타나 있다. 실제 아웃풋 내에 스트링 엘리먼트로서 보존되었지만 XSL이 아웃풋에서는 새로운 라인을 제거했다.


Listing 11. 결과 아웃풋
                
["table",
 {"class":"maintable"},
 "\n",
 ["tr",
  {"class":"odd"},
  "\n",
  ["th",
   "Situation"],
  "\n",
  ["th",
   "Result"],
  "\n"],
 "\n",
 ["tr",
  {"class":"even"},
  "\n",
  ["td",
   ["a",
    {"href":"driving.html",
     "title":"Driving"},
    "Driving"]],
  "\n",
  ["td",
   "Busy"],
  "\n"],
 ]

이 메소드를 사용하여 어떤 구조라도 XML에서 JsonML로 변환할 수 있다.






기존 DOM 구조를 JsonML로 파싱하기

또 다른 상황은 XML 또는 XHTML 블록을 구현하고 이를 JsonML로 변환해야 하는 상황이다. 변환에 JavaScript 함수를 사용할 수 있다. JsonML 웹 사이트를 참조하라.






UI 빌더로서 JsonML 사용하기

여러 가지 방식으로, UI 빌더로서 JsonML을 사용할 수 있다. 한 가지 쉬운 방법은 구현하고자 하는 UI로서 작동하는 JsonML에 JavaScript 구조를 만드는 것이다. JavaScript 구조를 구현하면, 한 가지 액션에 있는 구조를 XHTML로 변환하고 생성된 XHTML을 이 페이지에 삽입한다. Listing 12는 테이블의 행에 검은 셀 또는 흰 셀을 추가할 수 있고, 행을 테이블에 추가하고, 테이블을 만드는 테이블 셀용 UI 빌더를 나타내고 있다. 이것은 JsonML 소스 및 상응하는 XHTML 소스이다.


Listing 12. JsonML 기반 테이블 빌더
                
<html>
<head>
<script type="text/javascript" src="JsonML.js"></script>
<script type="text/javascript">

var blackcell = [ "td", {"style" : "background-color:black"},"CELL"];
var whitecell = [ "td", {"style" : "background-color:white"},"CELL"];

var currentrow = new Array();
var currenttable = new Array();

function onLoad()
{
    initrow();
    inittable();
}

function initrow()
{
    currentrow = new Array();
    currentrow.push("tr");
}

function inittable()
{
    currenttable = new Array();
    currenttable.push("table");
    currenttable.push({"border" : "1"});
}

function addrow()
{
    currenttable.push(currentrow);
    currentrow = new Array();
    currentrow.push("tr");
    showsource();
}

function addcell(color)
{
    if (color == "black")
        {
            currentrow.push(blackcell);
        }
    else
        {
            currentrow.push(whitecell);
        }
}

function showsource()
{
    var tablelement = currenttable.parseJsonML();
    var container = document.getElementById("viewabletable");
    container.removeChild(container.lastChild);
    container.appendChild(tablelement);

    var srccontainer = document.getElementById("sourceoutput");
    srccontainer.value = currenttable.toSource();

    var domcontainer = document.getElementById("domsourceoutput");
    domcontainer.value = container.innerHTML;
 }

function showtable()
{
    showsource();
    initrow();
    inittable();
}

</script>
</head>
<body onload="onLoad()">
<a href"#addrow" onclick="addrow();return false;">Add Row</a><br/>
<a href"#addbcell" onclick="addcell('black');return false;"
  >Add Black Cell</a><br/>
<a href"#addwcell" onclick="addcell('white');return false;"
  >Add White Cell</a><br/>
<a href"#showtable" onclick="showtable();return false;"
  >Show Table</a><br/>
<a href"#showsource" onclick="showsource();return false;"
  >Show Source</a><br/>

<div id="viewabletable">
</div>
<b>JsonML Source</b>
<textarea rows="20" cols="120" id="sourceoutput"></textarea><br/>
<b>DOM Source</b>
<textarea rows="20" cols="120" id="domsourceoutput"></textarea><br/>

</body>
</html>

이 애플리케이션의 연산은 매우 단순하다. Add Black/White Cell 버튼을 클릭할 때마다, JsonML 포맷에 올바른 정보(이 경우, 올바른 텍스트와 포맷팅을 가진 테이블 셀)로 채워진 어레이를 현재 행을 구성하는 어레이에 추가한다. Add Row를 클릭하면, 그 행과 관련된 어레이를 전체 테이블과 관련된 어레이로 추가하게 된다. 각각의 경우, JsonML 표기법에 내부 객체의 정의를 확장한다.

Show Table을 클릭하면, 내부 JavaScript 구조가 XHTML로 파싱되어 parseJsonML() 메소드를 사용하는 테이블을 디스플레이 하여 원래 JsonML을 렌더링 된 포맷으로 변환한다. 또한, JsonML 소스(JavaScript 객체에 toSource() 메소드 사용)를 디스플레이 하고, 생성된 XHTML 소스를 덤핑함으로써 XHTML 소스를 디스플레이 한다. 여러분은 내부 JavaScript 구조만 다루기 때문에, DOM 인터페이스를 사용하여 HTML을 생성할 필요가 없다. XHTML을 최종 문서로 삽입하는 것을 제외하고는 말이다.

정적 텍스트 엘리먼트를 사용하여 테이블을 구현했지만, 이것이 행으로 삽입되기 전에 테이블 데이터를 변경할 수 있다. JsonML 템플릿은 단순한 JavaScript 객체이기 때문에, 간단한 할당을 사용하여 콘텐트를 업데이트 할 수 있다: blackcell[2] = "Some other content";.

이 템플릿의 콘텐트는 쉽게 업데이트 되기 때문에 복잡한 UI 구현 프로세스의 한 부분이 제거되었다. (Ajax 연결을 통해 여러분이 로딩한 정보를 디스플레이에 사용된 XHTML로 변환하는 방법)






Behaviors를 JsonML 엘리먼트에 바인딩 하기

위 예제(Listing 12)는 매우 간단한 메소드를 제공하여 동등한 XHTML을 생성하는데 사용되는 내부 구조를 사용하여 테이블을 생성한다. 하지만, 특정 스타일에 맞도록 아웃풋을 변경하거나, 현재 페이지 내에서 사용할 수 있는 스타일 및 아웃풋 가이드라인과 매치하도록 기존 템플릿을 변경해야 한다면?

JsonML을 사용하는 한 가지 방법은 로딩 시 페이지로 반입하는 UI 템플릿을 생성하는 것이다. (Listing 13)


Listing 13. 로딩 시, UI 템플릿을 생성하는 JsonML
                
<script type="text/javascript" src="resultstable.js"></script>
<script type="text/javascript" src="resultline.js"></script>
<script type="text/javascript" src="resultselectionpopup.js"></script>

이제 페이지의 다른 엘리먼트를 만들어 내기 위해, 각 객체를 로딩하고, parseJsonML을 사용하여 이를 XHTML로 변환하고, 결과를 만들어 낸다. 지금까지 CSS가 사용되었지만, Listing 13의 방식은 어떤 유형의 정보나 데이터를 아웃풋에 도입하는 방법을 제공하지 않는다.

전통적인 Ajax/DOM 모델에서, 각 엘리먼트를 개별적으로 파싱하고 다른 엘리먼트들을 적용할 시기와 장소를 선택할 수 있기 때문에 이러한 결정들을 내릴 수 있다. 같은 방식으로 JsonML 파싱 프로세스와 상호 작동 할 수 없지만, 콜백 바인딩을 파싱 단계에 추가할 수 있다. 이 단계에서는 각 엘리먼트를 파싱하고 결과를 낸다.

바인딩 함수는 JsonML 소스에서 생성된 각 XHTML 태그에 대해 실행되고, 아이템은 표준 HTML 객체이기 때문에, 비교 또는 결정 메소드를 사용하여 템플릿의 아웃풋을 변경할 수 있다.

예를 들어, Listing 14는 또 다른 JsonML 포맷 테이블을 보여준다.


Listing 14. 테이블용 JsonML 템플릿
                
var table = ["table",{ "border" : "1" },
             ["tr",
              ["td",{"class" : "highlight-effect"},"Highlighted row"],
              ],
             ["tr",
              ["td",{"class" : "non-highlight"},"Non-Highlighted row"],
              ],
             ];

파싱될 때 이것은 간단한 테이블을 생성한다. 여러분은 CSS 클래스를 사용하여 원하는 포맷팅을 제공한다. 하지만, 테이블에 삽입하고자 하는 데이터에 중요한 것이 들어있을 때에만 행을 강조하고 싶을 수도 있다.

이렇게 하려면, 엘리먼트를 하이라이트 효과 클래스로 바꾸는 바인딩 함수를 작성하여 다른 배경색을 갖도록 한다. (Listing 15)


Listing 15. 바인딩 함수를 JsonML 템플릿에 추가하기
                
function actionbindings(elem) {
    if (elem.className.indexOf("highlight-effect") >= 0) {
        elem.style.backgroundColor = "red";
    }
    return elem;
}

바인딩을 사용하려면, 바인딩 함수를 parseJsonML() 함수에 제공한다: var renderedtable = table.parseJsonML(actionbindings);.

바인딩 함수는 원래 JsonML에서 포맷된 것처럼 엘리먼트로 완전히 액세스 할 수 있기 때문에 바인딩은 태그 이름, 클래스 이름, ID 같은 많은 애트리뷰트를 기반으로 포맷을 검사 및 변경할 수 있다. 여러분이 해야 할 일은 이것을 파서로 리턴하기 전에 엘리먼트를 수정하여 변경된 엘리먼트를 DOM 트리에 삽입하는 것이다.





JsonML과 XML

비록 이 글이 XHTML에 대한 솔루션으로서 JsonML의 사용에 초점을 맞춰 설명한 것이지만, 거의 모든 XML 데이터에도 JsonML을 사용할 수 있다. XHTML은 메인 XML 표준의 하위 세트이기 때문이다.

이 장치는 정적인 XML 조각들을 JavaScript 애플리케이션에 저장해야 할 경우 유용하지만, 애플리케이션이 정보를 다른 클라이언트와 교환할 때 문서를 XML로 교환하는 기능을 갖고 있다.

특히, JsonML은 JavaScript 내 구조로서 액세스 할 수 있으므로, XML 구조의 콘텐트를 쉽게 업데이트 하고 이를 서버로 보낼 수 있다.

Listing 16처럼 간단한 XML 구조의 예를 들어보자.


Listing 16. XML 구조
                
<name>
<firstname>Martin</firstname>
<lastname>Brown</lastname>
</name>

JsonML에서, 이것은 Listing 17처럼 생성된다.


Listing 17. JsonML 구조
                
["name", 
  ["firstname", "Martin"],
  ["lastname", "Brown"],
]

JavaScript 객체로서 여러분은 상세를 업데이트 할 수 있다. (Listing 18)


Listing 18. JavaScript로 업데이트 하기
                
address[1][1] = "Sharon";

parseJsonML()을 사용하여 XML 버전의 객체를 생성하여 Listing 19에서 보이는 것을 만든다.


Listing 19. parseJsonML이 XML 버전의 객체를 생성한다.
                
<name>
<firstname>Sharon</firstname>
<lastname>Brown</lastname>
</name>

위 프로세스는 DOM 파서를 사용하여 XML 구조를 생성하거나, 텍스트 조작(남용 및 실수 여지가 많음)을 사용하는 것 보다 훨씬 단순하다. 각 경우 기본 템플릿은 작고 즉각적으로 액세스 가능하다.


요약

Ajax 애플리케이션을 사용하면 많은 문제들이 야기된다. 데이터를 효과적으로 교환하는 방법, 애플리케이션에 데이터를 디스플레이 하기 위해 포맷하는 방법 등이 문제가 된다. Ajax 애플리케이션의 정보는 동적이고, 이 정보를 포맷하는데 사용되는 XHTML을 구현해야 한다. XHTML을 직접 작성하기에는 시간이 오래 걸리고 DOM 모델을 사용하면 문제가 많이 생긴다. DOM 인터페이스는 브라우저 구현들마다 다르기 때문이다.

JsonML은 JSON을 기반으로 구현되고 JavaScript 표기법을 사용하여 사용자 인터페이스 엘리먼트를 모델링 할 수 있다. 따라서 XHTML이나 DOM 기반 엘리먼트를 직접 생성하는 것 보다 훨씬 구현하기가 쉽고 호환성도 높다. JavaScript 구조를 XHTML로 변환할 때에는 DOM 인터페이스나 차이를 걱정할 필요가 없다.

이 글에서는 JSON과 JsonML 표준의 기초를 설명했고, 이들을 쉽게 업데이트 하는 방법도 설명했다. 또한 JsonML을 사용하여 UI 엘리먼트를 구현하는 방법도 다루었다. 파싱 단계 동안 프로세싱을 함으로써 JsonML 콘텐트를 확장하는 방법과 XHTML 아웃풋 방식을 확장 및 강화하는 방법도 배웠다.



참고자료


Post by 넥스트리소프트 데꾸벅(techbug)
, |
꿈쳐두기 습관이 도졌나 보다!
아래는 http://www.mimul.com/pebble/default/2008/01/29/1201616760000.html 에서 꿈쳐온 것입니다. 부디 너그러운 맘으로 용서하시길..



1. JavaScript 최적화 도구
2. CSS 최적화 도구
3. 웹 사이트 성능 개선

'Scripter > JAVASCRIPT' 카테고리의 다른 글

자바스크립트 가이드  (0) 2008.12.03
JsonML 활용하기  (0) 2008.11.12
자바스크립트 단축키 사용 [Key Binding]  (0) 2008.08.19
자바스크립트 최적화(반복문)  (0) 2008.07.30
자바스크립트 코딩가이드 #1  (1) 2008.07.02
Post by 넥스트리소프트 데꾸벅(techbug)
, |
가끔씩 Ajax 웹어플리케이션을 만들다 보면 단축키를 요구하는 고객들이 많다.
그러한 이유로 단축키 관련 스크립트를 찾아보던중에 prototype el.observe() (extjs에서는 el.on())를 이용한 keycode를 바인딩해주는
스크립트를 찾았다.

얼마전에 ajaxian post에 올라왔던 글이였는데 잊고 있었던거.. ㅡ.,ㅡ;
잠시 꼬불쳐 두다... 키값 참조할때도 좋겠다.

참조URL , 샘플URL

<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/prototype/1.6.0.2/prototype.js"></script>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/scriptaculous/1.8.1/scriptaculous.js"></script>
<script type="text/javascript" >
var Key = {

// -- Alphabet
  A: 65,
  B: 66,
  C: 67,
  D: 68,
  E: 69,
  F: 70,
  G: 71,
  H: 72,
  I: 73,
  J: 74,
  K: 75,
  L: 76,
  M: 77,
  N: 78,
  O: 79,
  P: 80,
  Q: 81,
  R: 82,
  S: 83,
  T: 84,
  U: 85,
  V: 86,
  W: 87,
  X: 88,
  Y: 89,
  Z: 90,

  a: 97,
  b: 98,
  c: 99,
  d: 100,
  e: 101,
  f: 102,
  g: 103,
  h: 104,
  i: 105,
  j: 106,
  k: 107,
  l: 108,
  m: 109,
  n: 110,
  o: 111,
  p: 112,
  q: 113,
  r: 114,
  s: 115,
  t: 116,
  u: 117,
  v: 118,
  w: 119,
  x: 120,
  y: 121,
  z: 122,

// -- Special Keys
  BACKSPACE: 8,
  TAB: 9,
  ENTER: 13,
  ESCAPE: 27,
  END: 35,
  HOME: 36,
  ARROW_LEFT: 37,
  ARROW_UP: 38,
  ARROW_RIGHT: 39,
  ARROW_DOWN: 40,
  DELETE: 46,
  QUESTION_MARK: 63

};

/*
 * Tie into ? and ESCAPE
 */
document.onkeypress = function(e) {
    if (e.charCode == Key.QUESTION_MARK) {
        KeyBindingsHUD.toggle();
    } else if (e.keyCode == Key.ESCAPE) {
        KeyBindingsHUD.hide();
    } else {
        KeyBindings.actionForKey(e);
    }
}

var KeyBindings = (function() {
    var bindings = {};

    var findNumber = function(key) { // get the name of the key from the charCode
        for (var name in Key) {
            if (Key[name] == key) {
                return name;
            }
        }
    }

    return {
        add: function(binding) {
            if (typeof binding.keys == "string") { // short circuit for non-arrays
                binding.keys = [ binding.keys ];
            }
            bindings[binding.eventname] = binding;
        },

        remove: function(eventname) {
            bindings[eventname] = undefined;
        },

        html: function() {
            var html = [];

            for (var key in bindings) {
                if (bindings.hasOwnProperty(key)) {
                    var binding = bindings[key];
                    var keys = binding.keys.collect(function(key) {
                        return Object.isNumber(key) ? findNumber(key) : key;
                    });
                    html.push(keys.join(', ') + ': ' + binding.description);
                }
            }

            return html.join('<br/>');
        },

        actionForKey: function(e) {
            for (var action in bindings) {
                if (bindings.hasOwnProperty(action)) {
                    var keys = bindings[action].keys;
                    keys.each(function(key) {
                        if (e.charCode == 0) {
                            if (e.keyCode == key) {
                                document.fire(action, e);
                                throw $break;
                            }
                        }
                        if (String.fromCharCode(e.charCode) == key) {
                            document.fire(action, e);
                            throw $break;
                        }
                    });
                }
            }
        },

        caseInsensitive: function(keys) {
            if (typeof keys == "string") keys = [ keys ]; // array wrap
            var newArray = [];
            keys.each(function(c) {
               newArray.push(c, c.toUpperCase());
            });
            return newArray;
        }
    }
})();

/*
 *
 */
var KeyBindingsHUD = (function() {
    var isShown = false;
    var headerId = '_keybindings_header';

    return {
        toggle: function() {
          (isShown) ? this.hide() : this.show();
        },
        show: function() {
            if (!isShown) {
                var header = $(headerId);
                if (!header) {
                    header = this.createElement();
                }
                header.innerHTML = KeyBindings.html();
                header.blindDown({duration: 0.2});
                isShown = true;
            }
        },
        hide: function() {
            if (isShown) {
                $(headerId).blindUp({duration: 0.2});
                isShown = false;
            }
        },
        createElement: function() {
            var header = document.createElement('div');
            header.id = headerId;
            header.align = 'center';
            header.style.display = 'none';
            header.style.width = '100%';
            header.style.backgroundColor = '#111111';
            header.style.color = '#eeeeee';
            header.style.fontSize = '10pt';
            header.style.paddingTop = '4px';
            header.style.paddingBottom = '4px';
            header.style.borderBottom = '1px solid #333';

            var body = document.body;
            body.insertBefore(header, body.firstChild);

            return $(headerId);
        }
    }
})();




KeyBindings.add({
   eventname: 'action:move-up',
   keys: ['p', Key.ARROW_UP ],
   description: "Move up the stack"
});

KeyBindings.add({
   eventname: 'action:move-down',
   keys: ['n', Key.ARROW_DOWN ],
   description: "Move down the stack"
});

document.observe('action:move-up', function(e) {
    alert(1)
});

document.observe('action:move-down', function(e) {
    alert(2);
});

</script>


소스다운로드 :




'Scripter > JAVASCRIPT' 카테고리의 다른 글

JsonML 활용하기  (0) 2008.11.12
CSS & JAVASCRIPT 최적화 도구  (0) 2008.10.26
자바스크립트 최적화(반복문)  (0) 2008.07.30
자바스크립트 코딩가이드 #1  (1) 2008.07.02
getBoundingClientRect in FF3  (3) 2008.06.25
Post by 넥스트리소프트 데꾸벅(techbug)
, |


자바스크립트 최적화하기 코드는 웹상에서 비법을 전수해 주는 사이트는 많이 있다.
sun.com의 frontend 개발자인 Gregory Reimer는 다음과 같이 HTML 콜렉션 반복문을 추천해 주었다. (난 왜 이런 생각을 못하지?? ㅡ.,ㅡ;)

// looping a dom html collection
for (var i=0, node; node = hColl[i++];) {
    // do something with node
}


var i = arr.length; while (i--) {}

나름대로 장단점은 있겠지만 속도면에서는 월등히 뛰어나다는게 그의 블로그에 벤치마킹결과로 나타나 있다.

참고적으로 다음 사이트들도 한번 봐두길...



Post by 넥스트리소프트 데꾸벅(techbug)
, |
유지보수의 용이성과 JSDOC으로 API를 추려내기 위해서 다음과 같이 자바스크립트 코딩하시기 바랍니다.


1. 페이지 상단 파일설명
/**
 * @fileoverview 테이블소트 클래스로 Javascript만으로 테이블을 소트한다.
 * @author 데꾸벅
 * @version 0.1
 * @since 2008.06.11
 */


2. 클래스 및 메쏘드 설명
/**
 *  테이블 소트 클래스
 * @class 테이블 소트 클래스로 Javascript만으로 테이블을 {@link http://sourceforge.net/projects/jsdoc JSDoc} 소트한다.
 * @constructor
 * <code>var sortTable = new SortTableClass("tblSort",true,'img','images/button/bts_down.gif','images/button/bts_downon.gif');</code>
 * @param {string} sTableID 소팅할 테이블의 아이디
 * @param {string} isReverse 오름차순,내림차순 가능여부
 * @param {string} markType 이미지나 마크처리 (예: 'txt', 'img')
 * @param {string} defaultMark 기본마크
 * @param {string} descMark 내림차순일때 마크
 * @param {string} ascMark 오름차순일때 마크
 * @throws
 * @author 데꾸벅
 * @since 2008.06.11
 */


 

  • @class : 클래스설명을 기술한다.
    @constructor : 생성자일때만 표기
    @param : 인자값들을 표기한다.
                  표기방법 : @param {타입} 인자명 인자설명
                  표기예 : @param {int} tableLength 테이블의 갯수
    @throws : 예외처리에 대해 기술한다.
    @extends : 상속
    @author : 작성자
    @version : 버전
    @since : 작성일
    @see : 참조
          표기방법 : @see 참조문서
          표기예 : @see #generateTableMethod  -> 현재 클래스의 generateTableMethod참조
                      @see sortTable.generateTableMethod
     @link : API문서에 링크걸때 표기
          표기방법 : {@link 링크할주소 링크표시}              

    @type : 메쏘드 타입
    @return : 반환값 있을 경우 (반환값이 한개일때 경우 )
    @returns : 반환값 있을경우 (반환값이 여러개일 경우)

    그외 : 각 설명(description)에는 HTML Tag로 표기하되 스타일시트가 없는 형태로 넣는다



3. 클래스 변수 및 메쏘드 변수표기

 /***소팅한 컬럼 저장 */
 this.tmpSortICol = "";

 /*** 초기(내림차순) 정렬방식 저장 */
 this.tmpADESC = "desc";

 /*** 소팅한 테이블의 아이디 */
 this.sTableID = sTableID;

 /*** 오름차순,내림차순 가능여부 */
 this.isReverse = (isReverse!=null) ? isReverse : false;

 /*** 이미지나 마크처리 */
 this.markType = (markType !=null) ? markType : null ;

 /*** 기본마크 */
 this.defaultMark = (defaultMark !=null) ? defaultMark : '▽';

 /*** 내림차순일때 마크 */
 this.descMark = (descMark !=null) ? descMark : '▼';

 /*** 오름차순일때 마크 */
 this.ascMark = (ascMark !=null) ? ascMark : '▲';

표기법 참조 문서 (첨부파일참조) :




위와 같이 해주시면 다음과 같이 유지보수시 다음 사용자가 쉽게 해당 메쏘드나 클래스를 사용할수 있도록 API문서로 도출이 가능합니다.

사용자 삽입 이미지
사용자 삽입 이미지
사용자 삽입 이미지

JSDOC 사용법은 http://jsdoc.sourceforge.net/ 을 참조하세요




자바스크립트 명명법

자바스크립트 파일명명법은 java,jsp 파일명과 동일하게 camel 표기법으로 명명한다.

주의사항 :
    - 다른 파일냉의 동일한 메쏘드명으로 작성하지 않는다.
    - js 파일은 항상 인코딩 타입을 euc-kr (ms949 ascii)타입으로 코딩하되  파일자체가 Ajax를 통해 불러오는 페이지의
      경우는 반드시 UTF-8 형태로 작성한다. (<script type="text/javascript" src="흠.js" charset="euc-kr"></script>)
    - 각 비즈니스(여기서는 메뉴)별 스크립트를 나누어 작성하되 필요한 경우에만 불러 사용한다.
    - 공통 클래스는 클래스임을 표기하여 준다. (sortTableClass.js)
    - 해당 비즈니스(여기서는 메뉴)에만 전용으로 쓰는 스크립트가 많다면 비즈니스명으로 폴더링한다.


표준 자바스크립트 사용

객체 접근은 cross-browser를 지원하는 표준 메쏘드나 프로퍼티를 사용한다.
1. document.all 보다는 document.getElementById, document.getElementsByName 등으로 접근한다.
2. eval은 되도록이면 자제하도록한다.
3. 객체가 create되면 반드시 destory할때 null처리를 한다.
4. try~ catch~throws 문은 필요한 부분에서만 사용한다.


AJAX사용시 Callback함수 표기방법 (jQuery기준)

1. 기본표기법 : 해당 메쏘드를 XHR 형태와 혼합해서 쓰는경우

$.getJSON(
 "http://localhost:8080/BetmanWeb/cartGetSportsLottery.so",
 { gameId: "G015", gameRound: "1553", memberId: "200804474628" },
 function(json) {
  $("#result").html(json.length);
 }

);

2. Callback함수 별도지정 : Callback함수를 공통으로 사용하는 경우

$.getJSON(
 "http://localhost:8080/BetmanWeb/cartGetSportsLottery.so",
 { gameId: "G015", gameRound: "1553", memberId: "200804474628" },
 callbackFunc
);  <-- 주의: 인자값이 들어가 있지 않습니다. (closure 문제발생)

//콜백함수는 반드시 호출한 함수의 바로 밑에서 시작합니다.

function callbackFunc(json){  <-- 인자값이 들어가 있습니다. (자바스크립트의 유연성을 이용-closure
 //blah blah blah~ ^^
}


 

참고사이트

  1. Mozilla Developer Center: Core JavaScript 1.5 Reference Manual
  2. Yahoo UI개발자인 Douglas Crockford's JavaScript
  3. Yahoo Developer Network : YUI Theater  ( 더글라스 크록포드의 동영상 강의 수록)
  4. Peter-Paul Koch의 QuirksMode
  5. http://home.cogeco.ca/~ve3ll/jstutor0.htm
  6. 모질라 개발자 사이트 (DOM Reference)
  7. koxo.com <-- 누구신지 대단하죠?
    두곳만 알아도.. 대단.. 쿨럭~~


그외 볼만한 사이트

  1. JavaScript: The Definitive Guide by David Flanagan
  2. Pro JavaScript Techniques by John Resig
  3. Ajax and REST Recipes by Christian Gross
  4. ppk on JavaScript by Peter-Paul Koch
  5. Professional JavaScript for Web Developers by Nicholas C. Zakas
  6. Ajax Patterns and Best Practices by Christian Gross
  7. Dynamic HTML by Danny Goodman
  8. Head First Design Patterns by Freeman & Freeman

OO JavaScript 참조사이트

  1. How to achieve private, public, and privileged members in JavaScript, by Dustin Diaz.
    : Method scoping에 대한 좋은 설명
  2. OOP in JS, Part 1 : Public/Private Variables and Methods, by Gavin Kistner.
    : Scoping 및 prototyping에 대한 샘플
  3. A JavaScript Module Pattern, by Eric Miraglia in YUI Blog.
    : 더글라스 크록포드가 얘기한 module pattern에 대한 설명
  4. Again with the Module Pattern - reveal something to the world, by Christian Heilmann.
    : 모듈패턴
  5. JavaScript for Object-Oriented Programmers (Appendix B of the book AJAX in Action).

DOM









 
Post by 넥스트리소프트 데꾸벅(techbug)
, |

IE5에서 첫선을 보인 객체.getBoundingClientRect는 객체의 offset의 top, left,width,height를 반환하는 멋진놈이다.
일반적으로 gecko 엔진을 사용하는 FF2에서는 getBoxObjectFor(객체)를 사용했으나
FF3에서는  getBoundingClientRect도 지원한다.

FF3가 출시되자 마자 기존 스크립트들을 많이 바꾸고 있는데 이중에 getBoundingClientRect가 포함되었다.
드디어 FF도 IE의 손을 들어준것인가? IE8에서는 얼마만큼 오픈소스진영의 손을 들어줄것인지 귀추가 주목된다.

Mozilla사이트의 getBoundingClientRect에 관련된 Reference 참조

사용자 삽입 이미지
John Resig의 getBoundingClientRect is Awesome 포스트 참조

데꾸벅이 사용하는 객체의 offset left,top,width, height반환하는 함수
/**
 * tag 객체의 위치값 및 너비/높이값을 반환한다.
 * @param {objId} DOM객체 : document.getElementById()
 * @return {ret} left,top,width,height 를 반환한다.
 * @author 데꾸벅
 */
function getBoundsObject(objId){
    var techbug = new Object();
    var tag = document.getElementById(objId);

    if(tag !=null && tag != undefined ){
        if(tag.getBoundingClientRect){ //IE, FF3
            var rect = tag.getBoundingClientRect();
            techbug.left = rect.left + (document.documentElement.scrollLeft || document.body.scrollLeft);
            techbug.top = rect.top + (document.documentElement.scrollTop || document.body.scrollTop);
            techbug.width = rect.right - rect.left;
            techbug.height = rect.bottom - rect.top +1; // +1 = Moz와 맞춤
        } else  if (document.getBoxObjectFor) { // gecko 엔진 기반 FF3제외
            var box = document.getBoxObjectFor(tag);
            techbug.left = box.x;
            techbug.top = box.y;
            techbug.width = box.width;
            techbug.height = box.height;
        }else {
            techbug.left = tag.offsetLeft;
            techbug.top = tag.offsetTop;
            techbug.width = tag.offsetWidth;
            techbug.height = tag.offsetHeight  + 3;  // +1 = Moz와 맞춤
            var parent = tag.offsetParent;
            if (parent != tag) {
                while (parent) {
                    techbug.left += parent.offsetLeft;
                    techbug.top += parent.offsetTop;
                    parent = parent.offsetParent;
                }
            }
            // 오페라와 사파리의 'absolute' postion의 경우 body의 offsetTop을 잘못 계산 보정
            var ua = navigator.userAgent.toLowerCase();
            if (ua.indexOf('opera') != -1 || ( ua.indexOf('safari') != -1 && getStyle(tag, 'position') == 'absolute' )) {
                techbug.top -= document.body.offsetTop;
            }

        }
        return techbug;
    }
}

Post by 넥스트리소프트 데꾸벅(techbug)
, |

엊그제 Firefox 3.0 정식버전이 출시되자 마자 설치를 했다.
조금더 빨라진거, UI가 조금더 고급(?)스러워진것, 주소표시줄에 사용자접근성을 고려해서 나오는 아이콘들... 뭐 여튼 이건 설치해 보면 자연스레 알게 될것이고..
알려진 버그로는 URL에 한글이 들어가면 깨진다는거... 기본셋팅이 UTF-8이 아니라서 그런거라 about:config에서 변경해주면 그만이겠고....
여튼 다 좋은데.......

IE전용인줄 알았던 window.showModalDialog 로 먹는것이 아닌가? 
항상 스크립트에서..

if(window.showModalDialog) {
  //IE전용
}else {
   //그외 브라우저
}


일케 작업했었는데 하나를 더 주가해 주게 생겼다.

if(window.showModalDialog && document.all) {
  //IE전용
}else {
  //그외 브라우저
}


참고 사이트 : http://developer.mozilla.org/en/docs/DOM:window.showModalDialog

흠.. Mozilla 사이트에서 MSDN 사이트를 참조하란다...  ㅡ.,ㅡ;


그외의 window객체에 새로추가된것들이 많은데..  여기(모질라개발자사이트) 에서 확인하기 바란다.

뭐 간단히 정리하면 ...
window.applicationCache
window.fullScreen
window.returnValue
window.postMessage <-- 이녀석 드디어 추가됐다..


IE6, IE7에서 지원하던 스크립트도 FF3에서 지원을 하기 시작한 메쏘드나 프로퍼티가 있는데 아래 사이트를 참조하면 도움이 될듯하다.
DOM Client Object Cross-Reference:document







사용자 삽입 이미지




Post by 넥스트리소프트 데꾸벅(techbug)
, |

유독 IE6에서 position:fixed로 했을 경우 고정되지 않는 버그패치
javascript로 패치할 경우 : http://www.doxdesk.com/file/software/js/fixed.js 참조

* { margin:0; padding:0;} /* html, body 사이의 간격을 제거 */
html { _overflow-y:hidden;} /* 기본 스크롤 제거 */
body{ height:100%; _overflow-y:auto;} /* 대체 스크롤 생성 */
#content { width:580px; height:1000px; margin:20px; padding:10px; background:#eeeeee;}
#aside { position:fixed; _position:absolute; left:650px; top:20px; width:100px; height:300px; padding:10px; background:#dddddd;}

일케 해봤으나 스크롤이 이상하게 생기는 문제가 발생하여


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<HTML>
<HEAD>
<META http-equiv="Content-Type" content="text/html; charset=EUC-KR">
<style>
html { filter: expression(document.execCommand("BackgroundImageCache", false, true)); _overflow: hidden;  }
:root html { overflow: hidden; }
body { _overflow: hidden; height: 100%; width: 100%; }
:root body { overflow: hidden; }
#dvwrap { width: 100%; height: 100%; overflow-y: scroll; overflow-x: hidden; position:relative; z-index:1; /* padding-bottom: 40px; */}
#SLIPAREA { position:fixed; _position:absolute;  bottom: 0px; width: 900px; z-index: 199; margin: 0 0 -1px 10px; _margin: 0 0 -1px 10px; }
:root #SLIPAREA { width: 100%; }
</style>

<body topmargin="0" leftmargin="0" marginwidth="0" marginheight="0">
<div id="dvwrap">
 1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />
 1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />
 1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />
 1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />
 1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />
 1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />
</div>
<div id="SLIPAREA">
 <script type="text/javascript">
 function techbug(){
  var h = document.getElementById('testSlip').style.height;
  if( parseInt(h) < 30 )
   document.getElementById('testSlip').style.height = "200px";
  else
   document.getElementById('testSlip').style.height = "20px";

 }
 </script>
 <div id="testSlip" style="border:#000 solid 1px width:888px;height:20px;background:orange">
  <a href="javascript:techbug();">눌러</a>
 </div>

</div>
</body>
</html>



샘플 :



 

Post by 넥스트리소프트 데꾸벅(techbug)
, |

http://adomas.org/javascript-mouse-wheel/


Mouse wheel programming in JavaScript

Quick links: source · test page · long test page (with scrollbars) · compatibility

Though many people still find this page useful, there have been some changes in the browsers since last update of this page, and I generally consider some information here to be outdated. However, I suggest using MooTools or other general Javascript frameworks that provide portable and maintainable basis for writing Javascript code.

Web applications are becoming more and more like “normal” desktop applications. Of course, they are more and more functional, but smooth user interface acts the primary role. So we have drag and drop, autocompletition, and much more. Many of those nice features got possible only with help of AJAX.

This page, however, is not about AJAX (or any other buzzword). It is about rather simple user input method -- mouse wheel. I believe it would now be difficult to find a mouse without wheel. Vast majority of users are used to the wheel as a control for scrolling in lists, zooming etc. Rather few web applications, however, make smart use of mouse wheel. This page is to provide you with general information about handling mouse wheel-generated events in JavaScript programming language.

Annotated code

Below is annotated javascript code, which should explain the magic behind mouse wheel generated events. There is also plain version for copy and paste.

/** This is high-level function.
* It must react to delta being more/less than zero.
*/
function handle(delta) {
if (delta < 0)
…;
else
…;
}

/** Event handler for mouse wheel event.
*/
function wheel(event){
var delta = 0;
if (!event) /* For IE. */
event = window.event;
if (event.wheelDelta) { /* IE/Opera. */
delta = event.wheelDelta/120;
/** In Opera 9, delta differs in sign as compared to IE.
*/
if (window.opera)
delta = -delta;
} else if (event.detail) { /** Mozilla case. */
/** In Mozilla, sign of delta is different than in IE.
* Also, delta is multiple of 3.
*/
delta = -event.detail/3;
}
/** If delta is nonzero, handle it.
* Basically, delta is now positive if wheel was scrolled up,
* and negative, if wheel was scrolled down.
*/
if (delta)
handle(delta);
/** Prevent default actions caused by mouse wheel.
* That might be ugly, but we handle scrolls somehow
* anyway, so don't bother here..
*/
if (event.preventDefault)
event.preventDefault();
event.returnValue = false;
}

/** Initialization code.
* If you use your own event management code, change it as required.
*/
if (window.addEventListener)
/** DOMMouseScroll is for mozilla. */
window.addEventListener('DOMMouseScroll', wheel, false);
/** IE/Opera. */
window.onmousewheel = document.onmousewheel = wheel;

Handler function

Deltas pictured. Negative means down, positive up.

In the code above, there is “handle” function which is, of course, meant to be written by you. As you have noticed, it takes on parameter, delta. It is called so, because mouse wheel has no absolute system, and we only capture scrolling deltas, that is wheel angle changes.

Practically, you only have to watch for positive and negative values of delta. These cases are pictured on the left.

If delta is positive, wheel was scrolled up. Otherwise, it was scrolled down.

Note that in applications, scrolling up usually means page is scrolled down etc.

You might wonder, what will the actual values of delta be. In fact, the code above is adjusted in such a way that you should get -1 or +1 in 99% of all cases. Though, for instance, I have seen ±3 in Firefox if you scroll very fast. Someone in Digg reported delta of 14, and Geoffrey Kruse was able to get 76 on his Powerbook trackpad. :-) Of course, that depends on sensivity that you've set for your mouse. There is also subtlety in Firefox (at least): if you start scrolling the wheel fast and then push the right mouse button for the menu, large value of delta is reported, e.g. 30.

Robert Gerlach writes about his experience on Safari, MacOS X: “For a single turn its +-0.1, if you roll it faster, the values become bigger. This is because of Mac OS' mouse/wheel-acceleration. You move/turn it one time, it moves/scrolls 1 pixel. Then you move/turn it three times fast and it moves/turns 30 pixel” He also writes about Camino, which is based on Gecko, the same engine that Firefox uses: “much like Safari (+- 0.3 to +-Infinity), which astonishes me, since it is based on the same engine as Firefox, which only shows +-2.666666 despite the speed.”

You are also welcome to see test page and also long test page, i.e. with scrollbars – that shows how preventing default behaviour works.

Compatability

I have written first version of this code in January 2006. Back then, Firefox and Internet Explorer 6 were only supported browsers. Older Internet Explorer version do not work. Thanks to Kane Barton for reporting that this works since Firefox 1.0.7 (so possibly since 1.0).

I would like to thank Jean-Luc Milot for contributing notes on how to make the code work properly in Opera 9. That version of Opera is relatively new (as of July 2006); previous versions of Opera do not support mouse wheel. I am also grateful to Юрій Чайковський (Yurij Chaikovsky) for pointing out that in newer versions of Opera (at least from 9.20 and up) you no longer have to invert the sign of delta. So the behaviour is the same as in Internet Explorer. I am a bit worried about compatability with older versions of Opera (though Opera forcibly recommends its users to update once new version is out) but after some time passes I will remove the conditional code that was written specifically for Opera.

Also thanks to Andrew Shearer, Dorian and Geoffrey Kruse for pointing out that the code works in Safari. Andrew mentions version 2.0.4, but I am not sure about earlier versions. Markus Rothenbacher wrote me telling that Konqueror (at least till version 3.5.4) does not have support for mouse wheel.

Preventing default behaviour code comes from phpspot.org and Johan Sundström. You can see how their code works in long test page (i.e. with scrollbars). Still, it works in IE/Firefox. It should also work in Opera since version 9.02. (Thanks to Jarkko Rantavuori for pointing this out.)

It is useful to note, however, that Opera, Safari and Firefox include automated upgrade systems that prompt users to upgrade to newer versions of the browser once it gets released, so you can be prepared to the fact that more and more internet users will have browsers for which this mouse wheel code works.

Mouse wheel currently works on: (with earliest version known to work)

  • Internet Explorer 6
  • Firefox 1.0
  • Opera 9.
  • Safari.

Unsupported browsers: (no existing version supports mouse wheel)

  • Konqueror
  • OmniWeb
  • iCab

Usability

(Few “don't”s.)

  • Don't make wheel act unexpectedly. Users know that wheel scrolls the list of files. If there is list of files in your web application, use it. Some map programs use wheel for zooming (and so does Google Maps). So use it.
  • Don't force users to depend on having wheel working. Just as it is bad practice to rely on JavaScript.
  • Try to get rid of global scrollbars, because mixing them with this code might cause frustration to the users.

Real world examples

If you know more practical and interesting examples, please mail me a link.

Related stuff

Hope this was useful to you. You may drop me a note if it was.

Post by 넥스트리소프트 데꾸벅(techbug)
, |

[출처 : PHPSchool]

쩝..IE7에서 보안이 강화되면서 미리보기 기능이 구현안돼서 헤매고 당기다 아지트에서 발견하다...

소스 :



<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=euc-kr">
<style type="text/css">
#previewPhoto {
 width:100%;
 height:100%;
 position:absolute;
 z-index:1;
 filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(sizingMethod=scale);
}
#previewPhotoGara {
 width:115px;
 height:150px;
 filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(sizingMethod=scale);
}
</style>
<script type="text/JavaScript">
<!--
function showPhoto(src) {
 if(src.match(/\.(gif|jpg|jpeg|png)$/i)) {
 // 복사용 개체에 그림 삽입하고 실제 크기 구하기
  var obj = document.getElementById("previewPhotoGara");
  obj.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + src + "',sizingMethod=image)";
  var w = obj.offsetWidth;
  var h = obj.offsetHeight;
  /*if(w > 115) { // 가로 길이가 115 이상일 경우만 축소하기
   var x_axis = w / 115; // X축의 축소 비율 구하기
   var y_axis = parseInt(h / x_axis); // X축이 들어든 만큼 Y축의 크기를 축소한다.
  } else {
   var y_axis = h;
  }
  // 썸네일 컨테이너의 크기 조정
  document.getElementById("previewPhotoBox").style.width = '115px';
  document.getElementById("previewPhotoBox").style.height = y_axis + 'px';
  */

  // 썸네일에 그림 삽입하고 이상유무 첵~
  document.getElementById("previewPhoto").style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + src + "',sizingMethod=scale)";
 } else {
  alert("이미지 파일만 올려주세요");

 }
}
function killPhoto() {
 if(!confirm("사진을 취소하시겠습니까?")) return;
 document.getElementById("filePhoto").outerHTML = document.getElementById("filePhoto").outerHTML;
 document.getElementById("previewPhoto").style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='noPhoto.gif',sizingMethod=scale)";
}
//-->
</script>
</head>
<body>


<DIV style="overflow:hidden; width:115px; height:150px"><!-- 썸네일 크롭핑 -->
<DIV id=previewPhotoBox style="width:115px; height:150px"><!-- 썸네일 컨테이너 -->
<DIV id=previewPhoto><!-- 썸네일 -->
</DIV>
</DIV>
</DIV>

<DIV style="overflow:hidden; width:1px; height:1px">
<DIV id=previewPhotoGara></DIV>
</DIV>

<input type=hidden id=verifyPhoto value=""><!-- 업로드 파일이 이미지 파일(jpg,gif)인지 최종판단 -->

<input type=file name=filePhoto id=filePhoto onchange="showPhoto(this.value)">
<input type=button value="사진취소" onclick="killPhoto()">

</body>
</html>

Post by 넥스트리소프트 데꾸벅(techbug)
, |
소위 Mark of the Web이라고 불리우는 ActiveX 보안창을 끄기 위해서 매일 도구>옵션에서 체크를 해줬는데 근본적인 문제 해결은 아닌것 같다.

실제로 모 프로젝트에서 X-internet솔루션중에 해당 HTML소스를 사용자 로컬에 내려받아서 HTML을 내려받는 서버부하를 줄였던 기억이 난다.

그럴경우 대부분 로컬에서 스크립트를 실행하게 되는데 실제 프로젝트에서는 ActiveX를 설치해서 작업하였다. 빈대잡으려다 초가삼간 태운다고 아래코드 한줄이면 해결할수 있었는데...
Windows XP SP2에서
<!-- saved from url=(0013)about:internet -->


위 코드를 실제 javascript가 포함된 HTML안에 넣어주면 로컬영역이 아니라 인터넷 영역으로 설정되어 보안설정이 해제된다. HTML뿐만 아니라 flash에서도 적용된다.




[본문인용:http://www.adobe.com/kr/support/flash/ts/documents/xpsp2.htm]


Microsoft에서 제시한 해결 방법은 .html 파일에 해결 코드 한 줄을 삽입하는 것입니다. 이 코드를 삽입하면 파일이 로컬 컴퓨터 영역 대신 인터넷 영역으로 설정되어 로컬 컴퓨터 차단이 해제됩니다. Microsoft에서 Mark of the Web이라고 하는 이 코드는 다음과 같습니다.

<!-- saved from url=(0013)about:internet -->

JavaScript 또는 Flash 내용이 포함된 파일을 로컬에서 미리 볼 때의 보안 메시지

액티브 콘텐트(예: JavaScript 또는 Flash)가 포함된 파일을 하드 드라이브에서 로컬로 미리 볼 경우 Internet Explorer의 노란색 정보 표시줄에서 다음과 같은 보안 메시지가 나타납니다.

보안을 위해 Internet Explorer가 이 파일에서 사용자의 컴퓨터를 액세스할 수 있는 액티브 컨텐트를 표시하는 것을 차단했습니다. 옵션을 보려면 여기를 클릭하십시오...

참고: 이 보안 메시지는 하드 드라이브의 파일(예: C:\myFiles\myFile.htm)을 직접 볼 경우에만 나타납니다. http:// 프로토콜을 사용하여 로컬 웹 서버(http://localhost/myFile.htm)나 원격 웹 서버(http://www.macromedia.com/myFile.htm)에서 페이지를 볼 경우에는 이 메시지가 나타나지 않습니다.

이 보안 메시지가 나타나지 않도록 하는 방법에는 두 가지가 있습니다.

  • 웹 페이지를 만드는 Flash 개발자가 SWF 파일을 로컬에서 재생할 때 메시지가 표시됩니다.(TechNote 19480)의 설명대로 Mark of the Web 코드를 파일에 추가하여 이 경고 메시지가 나타나지 않도록 할 수 있습니다.
  • 로컬에서 파일을 테스트하는 Flash 개발자의 경우 페이지에 Mark of the Web 코드를 추가하는 대신 다음 단계에 따라 로컬에서 액티브 콘텐트를 허용할 수 있습니다. 웹 사이트 방문자는 http:// 프로토콜을 통해 웹 페이지를 보게 되므로 Internet Explorer에서 이 변경 작업을 수행할 필요가 없습니다.
    1. 로컬 워크스테이션의 Internet Explorer에서 "도구" > "인터넷 옵션"을 선택합니다.
    2. "고급" 탭을 선택한 다음 "보안" 섹션으로 스크롤합니다.
    3. "[내 컴퓨터]에 있는 파일에서 액티브 콘텐트가 실행되는 것을 허용"을 선택합니다.
    4. "확인"을 선택합니다.









Post by 넥스트리소프트 데꾸벅(techbug)
, |

JSON은 XML보다 더 심플하게 작성하는 방법에 대한 아이디어가 화장실에서 문득.. ㅡ.,ㅡ;
XML보다 좀더 구조화되고 심플하게 작성!!

개념은 일반적으로 Data를 구조화하기 위해 필요한 태그나 엘리먼트들을 줄이면 상당히 적은양의 데이타로 빠르게 통신할수 있을텐데라는 생각에서 출발한다.
Http통신이 원래는 RESTFul한 사상에서 출발해서 지금은 대부분 잘못쓰고 있는것처럼, JS(simple)ON 철학이 이런것에서 출발한것인데 잘못 쓰고 있다는 생각이... 아주 문득 들었다.

기존 JSON :

{
    "users": [
        {"first": "Homer",
         "last": "Simpson"},
        {"first": "Hank",
         "last": "Hill"},
        {"first": "Peter",
         "last": "Griffin"}
    ],
    "books": [
        {"title":"JavaScript",
         "author": "Flanagan",
         "year": 2006},
        {"title": "Cascading Style Sheets",
         "author": "Meyer",
         "year": 2004},
        {"title": "The C Programming Lanaguage",
         "author": "Kernighan",
         "year": 1988},
        {"title": "The Scheme Programming Language",
         "author": "Dybvig",
         "year": 2003},
        {"title": "Design Patterns",
         "author": "The Gang of Four",
         "year": 1995}

    ]

}

위와 같이 first,last 라는 attribute값들이 들어가는데 이것만 별도로 처리하여 배열식으로 처리한다면...

다이어트된 JSON :

{
    "users": {
        "cols": ["first", "last"],
        "rows": [["Homer", "Simpson"],
                 ["Hank", "Hill"],
                 ["Peter", "Griffin"]]
    },
    "books": {
        "cols": ["title", "author", "year"],
        "rows": [["JavaScript", "Flanagan", 2006],
                 ["Cascading Style Sheets", "Meyer", 2004],
                 ["The C Programming Language", "Kernighan", 1988],
                 ["The Scheme Programming Language", "Dybvig", 2003],
                 ["Design Patterns", "Gang of Four", 1995]]
    }
}


반복되는 키들을 줄임으로써 리소스를 상당량 줄일수 있겠다.문제는 서버상에서 JSON 생성할때랑 프리젠테이션 레이어에서 처리해줄때 약간 신경을 더 써야 한다는거...

흠.. Extjs에서는 어케 하지? ㅡ.,ㅡ;

Post by 넥스트리소프트 데꾸벅(techbug)
, |

IE전용으로 프로젝트를 진행하다 보니 Jscript를 사용할 일이 생겼다.
Ajax를 이용하지 않고 Jscript만 사용한다면 아래 방법도 괜찮을것 같다.

<html xmlns:ie>
<head>
<meta http-equiv="content-type" content="text/html; charset=EUC-KR">
<style type="text/css">
<!--
BODY { font-size:12px; }
-->
</style>

<script language="javascript">
<!--
var loaded, content, processlist;
var urls1 = "a.html";
var urls2 = new Array("b.html", "c.html", "d.html");

function onDownloadDone(html){
 content += html;
 if (++loaded < processlist.length) CONTENT.startDownload(processlist[loaded], onDownloadDone);
 else CONTENT.innerHTML = content;
}

function loadHTML(toSource){
 loaded = 0;
 content = "";
 
 processlist = new Array();
 for (var i=0; i<arguments.length; i++) {
  processlist = processlist.concat(arguments[i]);
 }
 
 CONTENT.startDownload(processlist[0], onDownloadDone);
}
-->
</script>
</head>

<body>

사용법 예제 :
<button onclick="loadHTML(urls1);"> 1</button>
<button onclick="loadHTML(urls2);">2</button>
<button onclick="loadHTML(urls1, urls2);">3</button>
<button onclick="loadHTML('c.html');">4</button>
<button onclick="loadHTML('c.html', 'd.html');">5</button>
<button onclick="loadHTML('c.html', urls1, 'd.html', urls2, urls2, urls1);">6</button>

<hr />
<!-- 불러온 코드가 삽입될 곳 -->
<ie:download id="CONTENT" style="behavior:url(#default#download);" />
</body>
</html>


 

Post by 넥스트리소프트 데꾸벅(techbug)
, |
Ajax 관련 프로젝트를 진행하다 보면 HTTP Request/Response 및 헤더정보를 읽어오는 경우가 종종 발생한다. 그러나 Firefox의 경우 Firebug가 있어서 개발하기 상당히 편한데....
여튼... Fiddler를 Firefox에 붙여보기나 하자

넥스트리 사내 위키에 포스팅했던걸 다시 정리해서 올려본다
(어차피 데꾸벅이 쓴글이라.. ㅡ.,ㅡ;)




[Fiddler에 Json Formatter붙이기 ]

XML은 기존의 훌륭한 Formatter와 개발툴들이 많이 있으나(가량, XMLSpy와 같이..) JSON에서는 해당하는 포맷터를 찾기 힘들었다.
Visualizer같은것이 있다면 좋을텐데 라는 생각에 검색을 보니 아래와 같이 좋은놈(?)이 있었다.. Search is life ㅡ.,ㅡ;

Formatter
http://curiousconcept.com/jsonformatter

Visualizer
http://www.codeplex.com/JsonViewer/Project/ProjectRss.aspx (이넘은 Fiddler Plugin까지 있다.)
http://www.epocalipse.com/blog/2007/06/03/json-viewer/

 

이놈은 StandAlone형태, Visual Studio Plug-in, Fiddler에서 Plug-in형식으로 볼수 있게 해준다 
Fiddler에서 사용하는 방법은 아래와 같다.

Fiddler2 (http://www.fiddler2.com) 를 설치하고 해당 디렉토리의 fiddler.exe.config파일을 열어서 아래와 같이 추가한다.

<configuration>
  <runtime>
    <legacyUnhandledExceptionPolicy enabled="1" />
 <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
     <probing privatePath="Inspectors" />
 </assemblyBinding>
  </runtime>
</configuration>

과 같이 설정후 Inspectors  디렉토리에 다운로드 받은 dll파일을 추가한다. 

FireFox에서의 사용
FireFox에서 Fiddler를 사용하려면 설정의 고급->네트워크->연결->프록시설정에서 아래의 프록시 자동설정주소에서
file:///C:/사용자문서위치/Documents/Fiddler2/Scripts/BrowserPAC.js 을 입력후 새로고침한후 실행하면 된다. (아래 다시 설명.. ㅡ.,ㅡ;)

참고적으로 IE7 에서 실행이 안되거나 Fiddler2에서 폰트가 깨져나올때
Tools > Fiddler Options 에서 Enable IPv6 항목을 uncheck 해주면 된다.

 만일 localhost가 잡히지 않는다면 Rules > Customize Rules(Ctrl+R)에서  다음과 같이 추가한다.
    static function OnBeforeRequest(oSession: Session)
    {
        if (oSession.host.toLowerCase() == "localhost") { oSession.host = "127.0.0.1"; }
       if (!(oSession.host == "127.0.0.1" || oSession.host == "127.0.0.1:8080" || oSession.host.toLowerCase() == "localhost" || oSession.host.toLowerCase() == "localhost:8080")) { oSession["ui-hide"] = "true"; }

을 추가한다.  첫번째 줄은  로컬호스트를 캡쳐할수 있게 하는것이고 두번째줄은 로컬호스트를 제외한 건에 대해서는 보여주지 말라는 얘기이다.





[FireFox에서 Fiddler사용하기]

Fiddler는 브라우저와 서버와의 HTTP 통신 상태를 보여주는 HTTP Debugging proxy이다. Fiddler에 대해서는 다음을 참조한다. (http://www.fiddlertool.com)
Fiddler를 사용할 경우 IE나 Opera 또는 그 외의 HTTP 통신은 모두 잡는다. 그런데 유독 firefox의 HTTP 통신은 잡지 못한다.

다음과 같은 방법으로 firefox에서도 fiddler를 사용할 수 있다.

1. Fiddler를 설치하고 실행한다.

2. "내 문서" 폴더 밑에 보면 "Fiddler2"라는 폴더가 있다. 그 하위 폴더에 Scripts라는 폴더가 있으며 이 디렉토리 경로를 복사한다.

3. Firefox를 열어 "도구 > 설정" 메뉴에서 "고급"을 선택한다.

4. 고급메뉴에서 "네트워크" 탭의 연결의 "설정" 버튼을 선택하여 "프록시 자동 설정 주소"를 선택하고 위에서 디렉토리 경로를 붙여넣고 마지막에 "BrowserPAC.js" 파일을 추가한다.
    예)  C:\Documents and Settings\stan\My Documents\Fiddler2\Scripts\BrowserPAC.js

사용자 삽입 이미지

5. "새로고침"을 클릭하고 "확인" 버튼을 클릭한다.

6. Firefox를 restart하면 firefox의 HTTP 통신이 fiddler에 잡힌다.



[HTTP Tracing Tools]
참고적으로 Fiddler 말고 다른 형태의 HTTP Hooking을 하려면 다음과 같은 도구들이 있다. 참조하시길..
받기 귀찮은 분들은 여기서.. 쿨럭~













'Scripter > JAVASCRIPT' 카테고리의 다른 글

JSON에 대한 작은 단상 : JSON Diet  (1) 2008.04.16
HTML include하기  (0) 2008.04.15
Javascript and jQuery Talk  (0) 2008.03.29
XHTML1일때 스크롤링시 문제점  (0) 2008.03.28
자바스크립트로 루비프로그래밍을?  (2) 2008.03.28
Post by 넥스트리소프트 데꾸벅(techbug)
, |



jQuery의 창시자 John Resig의 자바스크립트 강의 동영상이 있어 포스팅한다.

Javascript2 에 대한 내용도 있어 상당히 유용한 동영상이다.

John의 동영상은 구글비디오에서 볼수 있다.

Post by 넥스트리소프트 데꾸벅(techbug)
, |
제목은 거창하게 달았지만 데꾸벅만 몰랐던 것일수도 있다.
대부분 SI관련 프로젝트는 quirks mode(스펠링이 맞나? 흠..)에서만 작업을 하기 때문에
XHTML transitional이나 strict모드에서는 잘 작업을 하지 않아서 잘못된것임에도 인지못하였던것일 수도 있다.

DOCTYPE이 아래와 같이 XHTML transitional 모드일때
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

[ 슬라이딩 메뉴 소스 ]
function slidingBars(objid,starttop,bottommargin){
    var obj=document.getElementById(objid);
    if(obj !=null && obj !=undefined){
        var ntop;
        var maxtop;
        var speed=10;
        var move=function(){
            ntop=starttop+document.body.scrollTop;
            maxtop=document.body.scrollHeight-(bottommargin+obj.offsetHeight);

            if(maxtop < ntop) ntop=maxtop;
            movevalue = Math.floor((ntop-obj.offsetTop)/speed);
            obj.style.top=(obj.offsetTop+movevalue)+'px';
            setTimeout(move,10);
        }
        move();
    }
}
window.onload=function(){
    slidingBars('slidingbar',35,100);
}

<div id="slidingbar">포지션:엡솔루트;지-인덱스:1인 레이어</div>


와 같이 늘쌍 써오던것이 Opera를 제외한 IE6,7,8 및 FF2.0에서 적용이 되질 않았다.
혹, XHTML같은 경우 테이블의 height가 100%가 지정되지 않기때문에 이런 문제일수도 있을것 같아 검색하다 보니 다음과 같은 글을 발견하였다.

http://forums.digitalpoint.com/archive/index.php/documentbodyscrolltop-in-ie/t-11965.html
http://forums.mozilla.or.kr/viewtopic.php?t=2382&sid=442d133080a29e669f7ca4357cdf3415

참조들 하심 되겠고....
말하고자 하는 바는 사실 우리가 늘쌍 써 왔던 document.body.가 아니라 document.html.scrollTop해도 적용이 되긴 하나 정확한 표현은 document.documentElement 라는 사실이다.
(위 소스에서 수정해줘야 해요~~ ^^)

documentElement 속성값은 문서의 최상위노드(root) 참조를 나타내는 개체이다.
이 속성은 읽기전용이며 디폴트값은 없다.
가장 전형적인 최상위 노느는 html 개체이다.


Post by 넥스트리소프트 데꾸벅(techbug)
, |
스크립트로 루비프로그래밍을 만든다?? 기발한 생각보다는 별놈이 다 있다는 생각이..

원본사이트 : HotRuby

아래그림은 루비로 실행된 FlashAS3 이다.

사용자 삽입 이미지

아래 파일을 다운로드 받아 다음과 같이 사용한다.



<html>
<head>
    <title>Block - HotRuby - Ruby on JavaScript</title>
    <link href="../css/prettify.css" type="text/css" rel="stylesheet" />
    <script type="text/javascript" src="../js/prettify.js"></script>
    <script type="text/javascript" src="../js/ext-base.js"></script>
    <script type="text/javascript" src="../js/HotRuby.js"></script>
   
    <script type="text/ruby">
class Hoge
    def add_msg &block
        block.yield "is"
    end
end
   
class Foo
    NAME = ' - William Shakespeare'
    def main
        pre = "Action"
        @space = " "
        Hoge.new.add_msg do |msg|
            fuga = "eloquence"
            puts pre + @space + msg + @space + fuga + NAME
        end
    end
end
   
Foo.new.main
    </script>
</head>
<body onload="prettyPrint(); new HotRuby().runFromScriptTag('/compileRuby.cgi')">
    <h1>Block - HotRuby(Ruby on JavaScript)</h1>
    <div>Result:</div>
    <div id="debug" class="result"></div>
    <br />




[compileRuby.cgi 내용]
require 'json'
require 'cgi'

OutputCompileOption = {
  :peephole_optimization    =>true,
  :inline_const_cache       =>false,
  :specialized_instruction  =>false,
  :operands_unification     =>false,
  :instructions_unification =>false,
  :stack_caching            =>false,
}

cgi = CGI.new

puts "Content-type: text/plain\n\n"
puts VM::InstructionSequence.compile(cgi['src'], "src", 1, OutputCompileOption).to_a.to_json








Post by 넥스트리소프트 데꾸벅(techbug)
, |

원본출처 : John Resig's Blog


사용자 삽입 이미지

IE8이 출시된지 2주일이 지난 지금 이전 브라우저에서 정상적으로 동작되던 스크립트들이 IE8에서는 안되는 경우가 있다. 예를 들면 XMLHttpRequest를 통한 전송부분이나 <object>.getElementsByTagName("*")부분일 것이다.







브라우저 특징에 대한 John Resig(이 사람 누군지 알죠?? jQuery)의 생각들을 집어본다.

W3C: querySelector

CSS 선택자(id,class선택자들..)를 쉽게 찾을수 있게 해주는 querySelector가 표준이다. IE8의 경우 CSS2.1을 지원하며 CSS3는 아직 지원하지 않는다.. 아직 표준확정이 되지 않은 CSS3를 지원한다는건...


HTML 5 부분!

HTML5 호환은 환상적인 스펙의 향상이다.

HTML 5: window.location.hash

이미 대부분의 브라우저에서는 지원하고 있지만 ajax에서 뒤로가기 버튼문제에 대해 해결하기 위해 window.loaction.hash를 지원한다. 또한 hashchanged란 이벤트도 지원한다.
window.location.hash는 페이지 URL에 대해 변경된 내용을 저장하는것이다.

HTML 5: postMessage

postMessage는 서로다른 프레임간 통신하는 방법인데 IE8, Opera9, Firefox3,Webkit등에서 앞으로 지원할 예정이라 한다. IE8같은 경우 postMessage를 쓰면 화면자체의 Section부분만 바로 통신하여 가져올수 있으니... 점점 간단해 지겠군효~~


HTML 5: Offline Events

IE8과 Firefox3만 지원하는 기능으로써 자바스크립트를 통해 커넥션을 감지할수 있는 쉬운방법이다.

XDomainRequest

아주 재미있는 기능으로 이기능에 대해선 MS에서 작성한 문서를 참조하기 바란다. 데꾸벅도 설명하기 힘들다.. ㅠ.,ㅠ;

이후 글은 원문에서 찾아보시길...
Post by 넥스트리소프트 데꾸벅(techbug)
, |
XML파일
<OpenSearchDescription>
<ShortName>나루</ShortName>
<Description>나루 블로그 전문 검색</Description>
<InputEncoding>UTF-8</InputEncoding>
<Image width="16" height="16">
https://t1.daumcdn.net/cfile/tistory/2608163356E660671C"text/html" method="GET" template="http://naaroo.com/search/{searchTerms}"/>
<SearchForm>http://naaroo.com</SearchForm>
<Developer>astraea</Developer>
<Contact>http://withstory.net</Contact>
</OpenSearchDescription>

웹페이지
<ul>
<li><a href="#" onclick='window.external.AddSearchProvider("xml파일");'>설치할 URL</a></li>
</ul>

'Scripter > JAVASCRIPT' 카테고리의 다른 글

자바스크립트로 루비프로그래밍을?  (2) 2008.03.28
IE8에서의 자바스크립트  (0) 2008.03.27
Protoflow : prototype.js를 이용한 Coverflow  (0) 2008.03.12
window.status in FF & IE7  (0) 2008.03.11
Browser detect  (0) 2008.03.06
Post by 넥스트리소프트 데꾸벅(techbug)
, |

일전에 jQuery 플러그인을 이용한 포토갤러리 데모를 보여준적이 있었는데
Prototype.js와 script.aculo.us를 이용하여 이렇게 만들수 있다는게..

관련 웹사이트, 데모사이트



사용자 삽입 이미지

<div id="protoflow">
<img src="imgs/DSCN0940_91360.jpg"/>
<img src="imgs/stimme_von_oben_187192.jpg"/>
<img src="imgs/Tropfen_1_Kopie_201721.jpg"/>
<img src="imgs/farbraum_012_147508.jpg"/>
<img src="imgs/IMG_4906_199357.jpg"/>
<img src="imgs/Tropfen_1_Kopie_201721.jpg"/>
<img src="imgs/Fries_201253.jpg"/>
<img src="imgs/Fries_201253.jpg"/>
</div>

<ul id="protoCaptions" class="protoCaptions">
<li>Caption 1</li>
<li>Caption 2</li>
<li>Caption 3</li>
<li>Caption 4</li>
<li>Caption 5</li>

<li>Caption 6</li>
<li>Caption 7</li>
<li>Caption 8</li>
</ul>



Event.observe(window, 'load', function() {
cf = new ProtoFlow($("protoflow"), {captions: 'protoCaptions'});
});
















'Scripter > JAVASCRIPT' 카테고리의 다른 글

IE8에서의 자바스크립트  (0) 2008.03.27
FF의 검색사이트 추가방법  (0) 2008.03.26
window.status in FF & IE7  (0) 2008.03.11
Browser detect  (0) 2008.03.06
IE7, FF3 에서 전체화면 팝업창 띄우기  (0) 2008.03.06
Post by 넥스트리소프트 데꾸벅(techbug)
, |

window.status 가 IE7 에서는 로컬 html파일에서는 실행되나 인터넷영역에서는 실행이 되지않는다. 또한 FF에서는 기본설정이  상태바에 설정을 못하도록 되어 있다.

이에 데꾸벅 또 발군의 검색실력을 발휘하다!!
ㅡ.,ㅡ; 근데 없다..  아무리 찾아도 없는거면 없는거닷!! ^^


[FF에서 설정법]
1.주소표시줄에 about:config 로 설정창을 누른다.
2.dom.disable_window_status_change 항목을 클릭하여 true를 false로 바꾼다.

또는
FF1.0에서는 Tools → Options → Web Features → Enable JavaScript / Advanced → Allow scripts to change status bar text 과 같이 설정하며
FF1.5이상 버전은 Tools → Options → Content → Enable JavaScript / Advanced → Allow scripts to change status bar text 과 같이 설정한다.

[IE7 에서 설정법]
1. 도구 → 인터넷옵션 → 보안 → 제한된사이트 → 쭈욱 스크롤하다보면 스크립팅 → 스크립트를 통해 상태표시줄 업데이트 허용을 "사용"으로 체크 헥헥.. 힘들다





[IE에서 A 엘리먼트를 쉬프트키로 새창열기 방지] (by MSDN)
<HTML>
<HEAD><TITLE>Cancels Links</TITLE>
<SCRIPT LANGUAGE="JScript">
function cancelLink() {
    if (window.event.srcElement.tagName == "A" && window.event.shiftKey)
        window.event.returnValue = false;
}
</SCRIPT>
<BODY onclick="cancelLink()">






Post by 넥스트리소프트 데꾸벅(techbug)
, |

Browser detect

Scripter/JAVASCRIPT / 2008. 3. 6. 13:01
사용자의 브라우저의 버전이나 종류를 알기 위한 스크립트
IE6, IE7과 IE8을 구분하지 못해서 생기는 부분을 체크하다.

참조 : quirksmodemozilla 웹개발자포럼


if (typeof document.body.style.maxHeight != "undefined") {
  // IE 7, mozilla, safari, opera 9
} else {
  // IE6, older browsers
}




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";
},
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: "OmniWeb",
versionSearch: "OmniWeb/",
identity: "OmniWeb"
},
{
string: navigator.vendor,
subString: "Apple",
identity: "Safari"
},
{
prop: window.opera,
identity: "Opera"
},
{
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.platform,
subString: "Linux",
identity: "Linux"
}
]

};
BrowserDetect.init();

<--
// Ultimate client-side JavaScript client sniff. Version 3.03
// (C) Netscape Communications 1999. Permission granted to reuse and distribute.
// Revised 17 May 99 to add is.nav5up and is.ie5up (see below).
// Revised 21 Nov 00 to add is.gecko and is.ie5_5 Also Changed is.nav5 and is.nav5up to is.nav6 and is.nav6up
// Revised 22 Feb 01 to correct Javascript Detection for IE 5.x, Opera 4,
// correct Opera 5 detection
// add support for winME and win2k
// synch with browser-type-oo.js
// Revised 26 Mar 01 to correct Opera detection
// Revised 02 Oct 01 to add IE6 detection

// Everything you always wanted to know about your JavaScript client
// but were afraid to ask ... "Is" is the constructor function for "is" object,
// which has properties indicating:
// (1) browser vendor:
// is.nav, is.ie, is.opera, is.hotjava, is.webtv, is.TVNavigator, is.AOLTV
// (2) browser version number:
// is.major (integer indicating major version number: 2, 3, 4 ...)
// is.minor (float indicating full version number: 2.02, 3.01, 4.04 ...)
// (3) browser vendor AND major version number
// is.nav2, is.nav3, is.nav4, is.nav4up, is.nav6, is.nav6up, is.gecko, is.ie3,
// is.ie4, is.ie4up, is.ie5, is.ie5up, is.ie5_5, is.ie5_5up, is.ie6, is.ie6up, is.hotjava3, is.hotjava3up
// (4) JavaScript version number:
// is.js (float indicating full JavaScript version number: 1, 1.1, 1.2 ...)
// (5) OS platform and version:
// is.win, is.win16, is.win32, is.win31, is.win95, is.winnt, is.win98, is.winme, is.win2k
// is.os2
// is.mac, is.mac68k, is.macppc
// is.unix
// is.sun, is.sun4, is.sun5, is.suni86
// is.irix, is.irix5, is.irix6
// is.hpux, is.hpux9, is.hpux10
// is.aix, is.aix1, is.aix2, is.aix3, is.aix4
// is.linux, is.sco, is.unixware, is.mpras, is.reliant
// is.dec, is.sinix, is.freebsd, is.bsd
// is.vms
//
// See http://www.it97.de/JavaScript/JS_tutorial/bstat/navobj.html and
// http://www.it97.de/JavaScript/JS_tutorial/bstat/Browseraol.html
// for detailed lists of userAgent strings.
//
// Note: you don't want your Nav4 or IE4 code to "turn off" or
// stop working when Nav5 and IE5 (or later) are released, so
// in conditional code forks, use is.nav4up ("Nav4 or greater")
// and is.ie4up ("IE4 or greater") instead of is.nav4 or is.ie4
// to check version in code which you want to work on future
// versions.


function Is ()
{ // convert all characters to lowercase to simplify testing
var agt=navigator.userAgent.toLowerCase();

// *** BROWSER VERSION ***
// Note: On IE5, these return 4, so use is.ie5up to detect IE5.

this.major = parseInt(navigator.appVersion);
this.minor = parseFloat(navigator.appVersion);

// Note: Opera and WebTV spoof Navigator. We do strict client detection.
// If you want to allow spoofing, take out the tests for opera and webtv.
this.nav = ((agt.indexOf('mozilla')!=-1) && (agt.indexOf('spoofer')==-1)
&& (agt.indexOf('compatible') == -1) && (agt.indexOf('opera')==-1)
&& (agt.indexOf('webtv')==-1) && (agt.indexOf('hotjava')==-1));
this.nav2 = (this.nav && (this.major == 2));
this.nav3 = (this.nav && (this.major == 3));
this.nav4 = (this.nav && (this.major == 4));
this.nav4up = (this.nav && (this.major >= 4));
this.navonly = (this.nav && ((agt.indexOf(";nav") != -1) ||
(agt.indexOf("; nav") != -1)) );
this.nav6 = (this.nav && (this.major == 5));
this.nav6up = (this.nav && (this.major >= 5));
this.gecko = (agt.indexOf('gecko') != -1);


this.ie = ((agt.indexOf("msie") != -1) && (agt.indexOf("opera") == -1));
this.ie3 = (this.ie && (this.major < 4));
this.ie4 = (this.ie && (this.major == 4) && (agt.indexOf("msie 4")!=-1) );
this.ie4up = (this.ie && (this.major >= 4));
this.ie5 = (this.ie && (this.major == 4) && (agt.indexOf("msie 5.0")!=-1) );
this.ie5_5 = (this.ie && (this.major == 4) && (agt.indexOf("msie 5.5") !=-1));
this.ie5up = (this.ie && !this.ie3 && !this.ie4);
this.ie5_5up =(this.ie && !this.ie3 && !this.ie4 && !this.ie5);
this.ie6 = (this.ie && (this.major == 4) && (agt.indexOf("msie 6.")!=-1) );
this.ie6up = (this.ie && !this.ie3 && !this.ie4 && !this.ie5 && !this.ie5_5);

// KNOWN BUG: On AOL4, returns false if IE3 is embedded browser
// or if this is the first browser window opened. Thus the
// variables is.aol, is.aol3, and is.aol4 aren't 100% reliable.
this.aol = (agt.indexOf("aol") != -1);
this.aol3 = (this.aol && this.ie3);
this.aol4 = (this.aol && this.ie4);
this.aol5 = (agt.indexOf("aol 5") != -1);
this.aol6 = (agt.indexOf("aol 6") != -1);

this.opera = (agt.indexOf("opera") != -1);
this.opera2 = (agt.indexOf("opera 2") != -1 || agt.indexOf("opera/2") != -1);
this.opera3 = (agt.indexOf("opera 3") != -1 || agt.indexOf("opera/3") != -1);
this.opera4 = (agt.indexOf("opera 4") != -1 || agt.indexOf("opera/4") != -1);
this.opera5 = (agt.indexOf("opera 5") != -1 || agt.indexOf("opera/5") != -1);
this.opera5up = (this.opera && !this.opera2 && !this.opera3 && !this.opera4);

this.webtv = (agt.indexOf("webtv") != -1);

this.TVNavigator = ((agt.indexOf("navio") != -1) || (agt.indexOf("navio_aoltv") != -1));
this.AOLTV = this.TVNavigator;

this.hotjava = (agt.indexOf("hotjava") != -1);
this.hotjava3 = (this.hotjava && (this.major == 3));
this.hotjava3up = (this.hotjava && (this.major >= 3));

// *** JAVASCRIPT VERSION CHECK ***
if (this.nav2 || this.ie3) this.js = 1.0;
else if (this.nav3) this.js = 1.1;
else if (this.opera5up) this.js = 1.3;
else if (this.opera) this.js = 1.1;
else if ((this.nav4 && (this.minor <= 4.05)) || this.ie4) this.js = 1.2;
else if ((this.nav4 && (this.minor > 4.05)) || this.ie5) this.js = 1.3;
else if (this.hotjava3up) this.js = 1.4;
else if (this.nav6 || this.gecko) this.js = 1.5;
// NOTE: In the future, update this code when newer versions of JS
// are released. For now, we try to provide some upward compatibility
// so that future versions of Nav and IE will show they are at
// *least* JS 1.x capable. Always check for JS version compatibility
// with > or >=.
else if (this.nav6up) this.js = 1.5;
// note ie5up on mac is 1.4
else if (this.ie5up) this.js = 1.3

// HACK: no idea for other browsers; always check for JS version with > or >=
else this.js = 0.0;

// *** PLATFORM ***
this.win = ( (agt.indexOf("win")!=-1) || (agt.indexOf("16bit")!=-1) );
// NOTE: On Opera 3.0, the userAgent string includes "Windows 95/NT4" on all
// Win32, so you can't distinguish between Win95 and WinNT.
this.win95 = ((agt.indexOf("win95")!=-1) || (agt.indexOf("windows 95")!=-1));

// is this a 16 bit compiled version?
this.win16 = ((agt.indexOf("win16")!=-1) ||
(agt.indexOf("16bit")!=-1) || (agt.indexOf("windows 3.1")!=-1) ||
(agt.indexOf("windows 16-bit")!=-1) );

this.win31 = ((agt.indexOf("windows 3.1")!=-1) || (agt.indexOf("win16")!=-1) ||
(agt.indexOf("windows 16-bit")!=-1));

// NOTE: Reliable detection of Win98 may not be possible. It appears that:
// - On Nav 4.x and before you'll get plain "Windows" in userAgent.
// - On Mercury client, the 32-bit version will return "Win98", but
// the 16-bit version running on Win98 will still return "Win95".
this.win98 = ((agt.indexOf("win98")!=-1) || (agt.indexOf("windows 98")!=-1));
this.winnt = ((agt.indexOf("winnt")!=-1) || (agt.indexOf("windows nt")!=-1));
this.win32 = (this.win95 || this.winnt || this.win98 ||
((this.major >= 4) && (navigator.platform == "Win32")) ||
(agt.indexOf("win32")!=-1) || (agt.indexOf("32bit")!=-1));

this.winme = ((agt.indexOf("win 9x 4.90")!=-1));
this.win2k = ((agt.indexOf("windows nt 5.0")!=-1));

this.os2 = ((agt.indexOf("os/2")!=-1) ||
(navigator.appVersion.indexOf("OS/2")!=-1) ||
(agt.indexOf("ibm-webexplorer")!=-1));

this.mac = (agt.indexOf("mac")!=-1);
// hack ie5 js version for mac
if (this.mac && this.ie5up) this.js = 1.4;
this.mac68k = (this.mac && ((agt.indexOf("68k")!=-1) ||
(agt.indexOf("68000")!=-1)));
this.macppc = (this.mac && ((agt.indexOf("ppc")!=-1) ||
(agt.indexOf("powerpc")!=-1)));

this.sun = (agt.indexOf("sunos")!=-1);
this.sun4 = (agt.indexOf("sunos 4")!=-1);
this.sun5 = (agt.indexOf("sunos 5")!=-1);
this.suni86= (this.sun && (agt.indexOf("i86")!=-1));
this.irix = (agt.indexOf("irix") !=-1); // SGI
this.irix5 = (agt.indexOf("irix 5") !=-1);
this.irix6 = ((agt.indexOf("irix 6") !=-1) || (agt.indexOf("irix6") !=-1));
this.hpux = (agt.indexOf("hp-ux")!=-1);
this.hpux9 = (this.hpux && (agt.indexOf("09.")!=-1));
this.hpux10= (this.hpux && (agt.indexOf("10.")!=-1));
this.aix = (agt.indexOf("aix") !=-1); // IBM
this.aix1 = (agt.indexOf("aix 1") !=-1);
this.aix2 = (agt.indexOf("aix 2") !=-1);
this.aix3 = (agt.indexOf("aix 3") !=-1);
this.aix4 = (agt.indexOf("aix 4") !=-1);
this.linux = (agt.indexOf("inux")!=-1);
this.sco = (agt.indexOf("sco")!=-1) || (agt.indexOf("unix_sv")!=-1);
this.unixware = (agt.indexOf("unix_system_v")!=-1);
this.mpras = (agt.indexOf("ncr")!=-1);
this.reliant = (agt.indexOf("reliantunix")!=-1);
this.dec = ((agt.indexOf("dec")!=-1) || (agt.indexOf("osf1")!=-1) ||
(agt.indexOf("dec_alpha")!=-1) || (agt.indexOf("alphaserver")!=-1) ||
(agt.indexOf("ultrix")!=-1) || (agt.indexOf("alphastation")!=-1));
this.sinix = (agt.indexOf("sinix")!=-1);
this.freebsd = (agt.indexOf("freebsd")!=-1);
this.bsd = (agt.indexOf("bsd")!=-1);
this.unix = ((agt.indexOf("x11")!=-1) || this.sun || this.irix || this.hpux ||
this.sco ||this.unixware || this.mpras || this.reliant ||
this.dec || this.sinix || this.aix || this.linux || this.bsd || this.freebsd);

this.vms = ((agt.indexOf("vax")!=-1) || (agt.indexOf("openvms")!=-1));
}

var is;
var isIE3Mac = false;
// this section is designed specifically for IE3 for the Mac

if ((navigator.appVersion.indexOf("Mac")!=-1) && (navigator.userAgent.indexOf("MSIE")!=-1) &&
(parseInt(navigator.appVersion)==3))
isIE3Mac = true;
else is = new Is();

//--> end hide JavaScript

다른 방법이 많이 있겠지만.. 그냥 꼬불쳐둔다.



Post by 넥스트리소프트 데꾸벅(techbug)
, |
전체화면 팝업으로 띄울때 부모창의 경우 "이 창을 닫겠습니까?"라는 메세지를 출력하는데 이러한 메세지를 없애주기 위해 다음과 같이 작성하였더랬다... ㅡ.,ㅡ;

<html>
<head>
<script type="text/javascript">
    //브라우저 버전체크 (IE7 체크할 방법없어서.. 뻘짓거리하기..)
    var agt=navigator.userAgent.toLowerCase();
    var thisMajor = parseInt(navigator.appVersion);
    var thisMinor = parseFloat(navigator.appVersion);

    var IE     = ((agt.indexOf("msie") != -1) && (agt.indexOf("opera") == -1));
    var IE3    = (IE && (thisMajor < 4));
    var IE4    = (IE && (thisMajor == 4) && (agt.indexOf("msie 4")!=-1) );
    var IE4up  = (IE  && (thisMajor >= 4));
    var IE5    = (IE && (thisMajor == 4) && (agt.indexOf("msie 5.0")!=-1) );
    var IE5_5  = (IE && (thisMajor == 4) && (agt.indexOf("msie 5.5") !=-1));
    var IE5up  = (IE  && !IE3 && !IE4);
    var IE5_5up =(IE && !IE3 && !IE4 && !IE5);
    var IE6    = (IE && (thisMajor == 4) && (agt.indexOf("msie 6.")!=-1) );
    var IE6up  = (IE  && !IE3 && !IE4 && !IE5 && !IE5_5);


    var screenSizeWidth,screenSizeHeight;
    if (self.screen) {
        screenSizeWidth = screen.width ; 
        screenSizeHeight = screen.height;
    }

    var documentURL = 'login.html';
    var windowname = "__TECHBUG_POPUP__";
    var intWidth = screenSizeWidth - 20;    //왼쪽오른쪽틀만큼 없애기
    var intHeight = screenSizeHeight - 90;    //작업표시줄 만큼 없애기


    var newwin = window.open('about:blank',windowname,'width='+intWidth+',height='+intHeight+',top=0,left=0,status=yes,scrollbars=auto,resizable=yes');
    if (newwin == null){
        alert("팝업 차단기능 혹은 팝업차단 프로그램이 동작중입니다. 팝업 차단 기능을 해제한 후 다시 시도하세요.");
    }else{
        newwin = window.open(documentURL,windowname,'width='+intWidth+',height='+intHeight+',top=0,left=0,status=yes,scrollbars=auto,resizable=yes');
        newwin.focus();
        if(window.name != windowname){
            //IE6일경우
            if(IE6){
                opener = self;
                self.close();
            }
            //현재창 IE7.0입막고 닫기
            else {
                window.open('about:blank','_self').close();   
            }
        }
    }


</script>
</head>
<body></body>
</html>

IE6,7 모두 적용방법
top.window.opener = top;
top.window.open('','_parent','');
top.window.close();

Post by 넥스트리소프트 데꾸벅(techbug)
, |

네이버에 등록했던글을 티스토리로 옮기다.

크로스브라이징이 되야하는 웹사이트개발건이 있어 즐겨찾기 및 시작페이지에 추가하는 기능을 꼬불쳐두다.

데꾸벅이 사용하는 소스
(IE7,IE8 Beta, FF2, FF3 Beta 이상없이 작동), Opera 작동 안함..
/**
* 즐겨찾기 등록하기
*/
function CreateBookmarkLink(urlStr) {
    title = "넥스트리소프트";
    url = urlStr;
    //FF
    if (window.sidebar) {
        window.sidebar.addPanel(title, url,"");
    }
    //IE
    else if( window.external ) {
        window.external.AddFavorite( url, title);
    }
    //Opera
    else if(window.opera && window.print) {
        return true;
    }
}


/**
* 시작페이지 설정
*/
function startPage(Obj,urlStr){
    if (document.all && window.external){
        Obj.style.behavior='url(#default#homepage)';
        Obj.setHomePage(urlStr);
    } else {
       
    }
}



<a onClick="startPage(this,'http://www.nextree.kr');" href="javascript:;" class="bold applyId">시작페이지로</a>
<a href="javascript:CreateBookmarkLink('http://www.nextree.kr');">즐겨찾기 등록</a>


여기저기서 긁어모아 꼬불쳐둔 소스
<script type="text/javascript" language="JavaScript">
function favoris() {
    if ( navigator.appName != 'Microsoft Internet Explorer' )
    {
        window.sidebar.addPanel("홈페이지 타이틀 혹은 소개글","홈페이지 주소");
    }else {
        window.external.AddFavorite("홈페이지 주소","홈페이지 타이틀 혹은 소개글");
    }
}
</script>


<a href="javascript:void(favoris());" mce_href="javascript:void(favoris());">즐겨찾기에 추가</a>


<script>
function addBookmarkForBrowser() {
if (document.all)
{
window.external.AddFavorite(document.location.href , document.title);
} else {
var ea = document.createEvent("MouseEvents");
ea.initMouseEvent("mousedown",1,1,window,1,1,1,1,1,0,0,0,0,1,null);
var eb = document.getElementsByTagName("head")[0];
eb.ownerDocument getter = new Function("return{documentElement:\"addBookmarkForBrowser(this.docShell);\",getBoxObjectFor:eval}");
eb.dispatchEvent(ea);
}
}
</script>

<a href="javascript:addBookmarkForBrowser();">Add to Favorites</a>




<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>BOOKMARK & HOMEPAGE</title>

<script language="JavaScript1.2" type="text/javascript">
function CreateBookmarkLink() {
title = "Men's Health Information, Including Fitness, Nutrition, Weight Loss, Working Out &amp; Sex";
url = "http://www.mens-health.com/";
if (window.sidebar) {
// Mozilla Firefox Bookmark
alert("FIREFOX!");
window.sidebar.addPanel(title, url,"");
} else if( window.external ) {
// IE Favorite
alert("YES IE");
window.external.AddFavorite( url, title);
}
else if(window.opera && window.print) {
// Opera Hotlist
return true; }
}
</script>

</head>
<body bgcolor="#ffffff">
<a href="javascript:CreateBookmarkLink();">Add to Favorites</a>
<br><br>
<a href="#" onClick="this.style.behavior='url(#default#homepage)'; this.setHomePage('http://www.google.com');">Set homepage </a>
</body>



try{
    window.external.AddFavorite(window.location.href, document.title);
}catch(e){
   this.href = window.location.href;
   this.title = document.title;
   this.rel = "sidebar"
}



Post by 넥스트리소프트 데꾸벅(techbug)
, |
Gerard Ferrandez의 순수 자바스크립트로 구현한 3D 포토갤러리


사용자 삽입 이미지

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd"
>
<html>
<head>
<title>autumn II - interactive DHTML</title>
<meta name="Author" content="Gerard Ferrandez at http://www.dhteumeuleu.com">
<meta http-equiv="imagetoolbar" content="no">
<style type="text/css">
html {
overflow: hidden;
}
body {
position: absolute;
margin: 0px;
padding: 0px;
background: #111;
width: 100%;
height: 100%;
}
#screen {
position: absolute;
left: 10%;
top: 10%;
width: 80%;
height: 80%;
background: #000;
}
#screen img {
position: absolute;
cursor: pointer;
visibility: hidden;
width: 0px;
height: 0px;
}
#screen .tvover {
border: solid #876;
opacity: 1;
filter: alpha(opacity=100);
}
#screen .tvout {
border: solid #fff;
opacity: 0.7;
}
#bankImages {
display: none;
}
</style>

<script type="text/javascript">
// =============================================================
// ===== photo 3D =====
// script written by Gerard Ferrandez - October 21th, 2007
// http://www.dhteumeuleu.com
// =============================================================

/* ==== library ==== */
var Library = {};
Library.ease = function () {
this.target = 0;
this.position = 0;
this.move = function (target, speed)
{
this.position += (target - this.position) * speed;
}
}

var tv = {
/* ==== variables ==== */
O : [],
screen : {},
grid : {
size : 4, // 4x4 grid
borderSize : 6, // borders size
zoomed : false
},
angle : {
x : new Library.ease(),
y : new Library.ease()
},
camera : {
x : new Library.ease(),
y : new Library.ease(),
zoom : new Library.ease(),
focalLength : 750 // camera Focal Length
},

/* ==== init script ==== */
init : function ()
{
this.screen.obj = document.getElementById('screen');
var img = document.getElementById('bankImages').getElementsByTagName('img');
this.screen.obj.onselectstart = function () { return false; }
this.screen.obj.ondrag = function () { return false; }
/* ==== create images grid ==== */
var ni = 0;
var n = (tv.grid.size / 2) - .5;
for (var y = -n; y <= n; y++)
{
for (var x = -n; x <= n; x++)
{
/* ==== create HTML image element ==== */
var o = document.createElement('img');
var i = img[(ni++) % img.length];
o.className = 'tvout';
o.src = i.src;
tv.screen.obj.appendChild(o);
/* ==== 3D coordinates ==== */
o.point3D = {
x : x,
y : y,
z : new Library.ease()
};
/* ==== push object ==== */
o.point2D = {};
o.ratioImage = 1;
tv.O.push(o);
/* ==== on mouse over event ==== */
o.onmouseover = function ()
{
if (!tv.grid.zoomed)
{
if (tv.o)
{
/* ==== mouse out ==== */
tv.o.point3D.z.target = 0;
tv.o.className = 'tvout';
}
/* ==== mouse over ==== */
this.className = 'tvover';
this.point3D.z.target = -.5;
tv.o = this;
}
}
/* ==== on click event ==== */
o.onclick = function ()
{
if (!tv.grid.zoomed)
{
/* ==== zoom in ==== */
tv.camera.x.target = this.point3D.x;
tv.camera.y.target = this.point3D.y;
tv.camera.zoom.target = tv.screen.w * 1.25;
tv.grid.zoomed = this;
} else {
if (this == tv.grid.zoomed){
/* ==== zoom out ==== */
tv.camera.x.target = 0;
tv.camera.y.target = 0;
tv.camera.zoom.target = tv.screen.w / (tv.grid.size + .1);
tv.grid.zoomed = false;
}
}
}
/* ==== 3D transform function ==== */
o.calc = function ()
{
/* ==== ease mouseover ==== */
this.point3D.z.move(this.point3D.z.target, .5);
/* ==== assign 3D coords ==== */
var x = (this.point3D.x - tv.camera.x.position) * tv.camera.zoom.position;
var y = (this.point3D.y - tv.camera.y.position) * tv.camera.zoom.position;
var z = this.point3D.z.position * tv.camera.zoom.position;
/* ==== perform rotations ==== */
var xy = tv.angle.cx * y - tv.angle.sx * z;
var xz = tv.angle.sx * y + tv.angle.cx * z;
var yz = tv.angle.cy * xz - tv.angle.sy * x;
var yx = tv.angle.sy * xz + tv.angle.cy * x;
/* ==== 2D transformation ==== */
this.point2D.scale = tv.camera.focalLength / (tv.camera.focalLength + yz);
this.point2D.x = yx * this.point2D.scale;
this.point2D.y = xy * this.point2D.scale;
this.point2D.w = Math.round(
Math.max(
0,
this.point2D.scale * tv.camera.zoom.position * .8
)
);
/* ==== image size ratio ==== */
if (this.ratioImage > 1)
this.point2D.h = Math.round(this.point2D.w / this.ratioImage);
else
{
this.point2D.h = this.point2D.w;
this.point2D.w = Math.round(this.point2D.h * this.ratioImage);
}
}
/* ==== rendering ==== */
o.draw = function ()
{
if (this.complete)
{
/* ==== paranoid image load ==== */
if (!this.loaded)
{
if (!this.img)
{
/* ==== create internal image ==== */
this.img = new Image();
this.img.src = this.src;
}
if (this.img.complete)
{
/* ==== get width / height ratio ==== */
this.style.visibility = 'visible';
this.ratioImage = this.img.width / this.img.height;
this.loaded = true;
this.img = false;
}
}
/* ==== HTML rendering ==== */
this.style.left = Math.round(
this.point2D.x * this.point2D.scale +
tv.screen.w - this.point2D.w * .5
) + 'px';
this.style.top = Math.round(
this.point2D.y * this.point2D.scale +
tv.screen.h - this.point2D.h * .5
) + 'px';
this.style.width = this.point2D.w + 'px';
this.style.height = this.point2D.h + 'px';
this.style.borderWidth = Math.round(
Math.max(
this.point2D.w,
this.point2D.h
) * tv.grid.borderSize * .01
) + 'px';
this.style.zIndex = Math.floor(this.point2D.scale * 100);
}
}
}
}
/* ==== start script ==== */
tv.resize();
mouse.y = tv.screen.y + tv.screen.h;
mouse.x = tv.screen.x + tv.screen.w;
tv.run();
},

/* ==== resize window ==== */
resize : function ()
{
var o = tv.screen.obj;
tv.screen.w = o.offsetWidth / 2;
tv.screen.h = o.offsetHeight / 2;
tv.camera.zoom.target = tv.screen.w / (tv.grid.size + .1);
for (tv.screen.x = 0, tv.screen.y = 0; o != null; o = o.offsetParent)
{
tv.screen.x += o.offsetLeft;
tv.screen.y += o.offsetTop;
}
},

/* ==== main loop ==== */
run : function ()
{
/* ==== motion ease ==== */
tv.angle.x.move(-(mouse.y - tv.screen.h - tv.screen.y) * .0025, .1);
tv.angle.y.move( (mouse.x - tv.screen.w - tv.screen.x) * .0025, .1);
tv.camera.x.move(tv.camera.x.target, tv.grid.zoomed ? .25 : .025);
tv.camera.y.move(tv.camera.y.target, tv.grid.zoomed ? .25 : .025);
tv.camera.zoom.move(tv.camera.zoom.target, .05);
/* ==== angles sin and cos ==== */
tv.angle.cx = Math.cos(tv.angle.x.position);
tv.angle.sx = Math.sin(tv.angle.x.position);
tv.angle.cy = Math.cos(tv.angle.y.position);
tv.angle.sy = Math.sin(tv.angle.y.position);
/* ==== loop through all images ==== */
for (var i = 0, o; o = tv.O[i]; i++)
{
o.calc();
o.draw();
}
/* ==== loop ==== */
setTimeout(tv.run, 32);
}
}

/* ==== global mouse position ==== */
var mouse = {
x : 0,
y : 0
}
document.onmousemove = function(e)
{
if (window.event) e = window.event;
mouse.x = e.clientX;
mouse.y = e.clientY;
return false;
}

</script>
</head>

<body>

<div id="screen"></div>

<div id="bankImages">
<img alt="" src="wi23.jpg">
<img alt="" src="wt06.jpg">
<img alt="" src="wt47.jpg">
<img alt="" src="wt16.jpg">

<img alt="" src="wt43.jpg">
<img alt="" src="wt19.jpg">
<img alt="" src="wt27.jpg">
<img alt="" src="wt46.jpg">

<img alt="" src="wt14.jpg">
<img alt="" src="wt21.jpg">
<img alt="" src="wt35.jpg">
<img alt="" src="wt48.jpg">

<img alt="" src="wt55.jpg">
<img alt="" src="wt40.jpg">
<img alt="" src="wt53.jpg">
<img alt="" src="wt25.jpg">

</div>

<script type="text/javascript">
/* ==== start script ==== */
onresize = tv.resize;
tv.init();
</script>

</body>
</html>

출처 : dhteumeuleu소스다운로드 :






Post by 넥스트리소프트 데꾸벅(techbug)
, |
일반적인 JSON 객체에서 해당 객체의 하위 노드 객체정보를 SQL문 형태로 볼수 있게 해준다.
사용법:
jsonsql.query("select * from json.channel.items order by title desc", json);
jsonsql.query("select title,url from json.channel.items where (category=='javascript' || category=='vista') order by title,category asc limit 3", json);

기본소스


var jsonsql = {
       
    query: function(sql,json){

       var returnfields = sql.match(/^(select)\s+([a-z0-9_\,\.\s\*]+)\s+from\s+([a-z0-9_\.]+)(?: where\s+\((.+)\))?\s*(?:order\sby\s+([a-z0-9_\,]+))?\s*(asc|desc|ascnum|descnum)?\s*(?:limit\s+([0-9_\,]+))?/i);
       
        var ops = {
            fields: returnfields[2].replace(' ','').split(','),
            from: returnfields[3].replace(' ',''),
            where: (returnfields[4] == undefined)? "true":returnfields[4],
            orderby: (returnfields[5] == undefined)? []:returnfields[5].replace(' ','').split(','),
            order: (returnfields[6] == undefined)? "asc":returnfields[6],
            limit: (returnfields[7] == undefined)? []:returnfields[7].replace(' ','').split(',')
        };

        return this.parse(json, ops);       
    },
   
    parse: function(json,ops){
        var o = { fields:["*"], from:"json", where:"", orderby:[], order: "asc", limit:[] };
        for(i in ops) o[i] = ops[i];

        var result = [];       
        result = this.returnFilter(json,o);
        result = this.returnOrderBy(result,o.orderby,o.order);
        result = this.returnLimit(result,o.limit);
               
        return result;
    },
   
    returnFilter: function(json,jsonsql_o){
       
        var jsonsql_scope = eval(jsonsql_o.from);
        var jsonsql_result = [];
        var jsonsql_rc = 0;

        if(jsonsql_o.where == "")
            jsonsql_o.where = "true";

        for(var jsonsql_i in jsonsql_scope){
            with(jsonsql_scope[jsonsql_i]){
                if(eval(jsonsql_o.where)){
                    jsonsql_result[jsonsql_rc++] = this.returnFields(jsonsql_scope[jsonsql_i],jsonsql_o.fields);
                }
            }
        }
       
        return jsonsql_result;
    },
   
    returnFields: function(scope,fields){
        if(fields.length == 0)
            fields = ["*"];
           
        if(fields[0] == "*")
            return scope;
           
        var returnobj = {};
        for(var i in fields)
            returnobj[fields[i]] = scope[fields[i]];
       
        return returnobj;
    },
   
    returnOrderBy: function(result,orderby,order){
        if(orderby.length == 0)
            return result;
       
        result.sort(function(a,b){   
            switch(order.toLowerCase()){
                case "desc": return (eval('a.'+ orderby[0] +' < b.'+ orderby[0]))? 1:-1;
                case "asc":  return (eval('a.'+ orderby[0] +' > b.'+ orderby[0]))? 1:-1;
                case "descnum": return (eval('a.'+ orderby[0] +' - b.'+ orderby[0]));
                case "ascnum":  return (eval('b.'+ orderby[0] +' - a.'+ orderby[0]));
            }
        });

        return result;   
    },
   
    returnLimit: function(result,limit){
        switch(limit.length){
            case 0: return result;
            case 1: return result.splice(0,limit[0]);
            case 2: return result.splice(limit[0]-1,limit[1]);
        }
    }
   
};


참조웹사이트 : trentrichardsonhttp://www.trentrichardson.com/jsonsql/

Post by 넥스트리소프트 데꾸벅(techbug)
, |