블로그 이미지

카테고리

데꾸벅 (194)
Publisher (39)
Scripter (97)
Programmer (1)
Designer (30)
Integrator (18)
Pattern Searcher (4)
News (2)
강좌 및 번역 (3)

최근에 올라온 글

최근에 달린 댓글

'넥스트리 nextree 데꾸벅 techbug'에 해당되는 글 102건

  1. 2010.03.02 HTML5 10
  2. 2009.01.29 Apache expires 설정으로 브라우저 캐시
  3. 2009.01.21 extjs 2.2의 IE에서 iframe document load 버그패치
  4. 2009.01.20 홈페이지 보안 강화 도구(CASTLE) 보급 안내 1
  5. 2009.01.19 2009년 유행할 웹디자인 트렌드 13
  6. 2009.01.14 ext의 border-layout과 같은 jQuery UI.Layout Plugin
  7. 2009.01.06 Prototype.js Cross-Domain Ajax 플러그인 2
  8. 2008.12.13 Chap01. XForms 소개
  9. 2008.12.03 자바스크립트 가이드
  10. 2008.11.12 Extjs 3.0 Roadmap 10
  11. 2008.11.12 JsonML 활용하기
  12. 2008.11.08 HTTP Header에 대하여
  13. 2008.10.29 IIS 405 Error 처리방법 2
  14. 2008.10.26 CSS & JAVASCRIPT 최적화 도구
  15. 2008.09.24 AJAX에서 즐겨찾기와 뒤로가기를 다루는 방법
  16. 2008.09.08 safari 및 google Chrome에서의 Fieldset CSS버그 2
  17. 2008.09.03 구글크롬 테스트 및 브라우저버전체크 스크립트 6
  18. 2008.09.03 jQuery 링크에 걸린 파일 사이즈 자동으로 알아내기 1
  19. 2008.08.19 웹페이지 소스보기 금지
  20. 2008.08.19 자바스크립트 단축키 사용 [Key Binding]
  21. 2008.08.13 PNG(setPNG)를 이용시 이미지 토글 이벤트 먹는 경우 2
  22. 2008.08.07 Ext2.2 Release 11
  23. 2008.08.02 CSS Hack(핵) 정리 및 IE6,7,FF3 CSS맞추기
  24. 2008.07.30 IE,Opera,Safari에서도 Firebug를 쓰자 2
  25. 2008.07.30 자바스크립트 최적화(반복문)
  26. 2008.07.30 사용자에게 브라우저 업데이트 권장하기(Push up) 2
  27. 2008.07.23 웹폰트로 이쁜 웹페이지를 꾸며보자 4
  28. 2008.07.08 jQuery Loading바 구현하기 2
  29. 2008.07.02 자바스크립트 코딩가이드 #1 1
  30. 2008.06.27 MS office2007 Excel 파일 각각 따로 열기 8

HTML5

강좌 및 번역 / 2010. 3. 2. 14:26



 HTML5 강의자료입니다.




 
 
웹표준 관련 추천책 
 웹표준교과서

 CSS 마스터전략

 실용예제로 배우는 웹표준

 웹2.0을 이끄는 방탄웹

 웹표준 Ajax DOM 스크립팅



For Presentation Developer

For UI/UX

For Web Publisher

For Javascript & Ajax Integrator

For FLEXer

etc & Misc

'강좌 및 번역' 카테고리의 다른 글

프로젝트 관리자가 알아야할 97가지 사실  (1) 2009.12.08
AJAX & UI 강의자료  (8) 2009.03.22
Post by 넥스트리소프트 데꾸벅(techbug)
, |


Apache Module mod_expires 관련 글 : PHP스쿨에서 좋은 팁하나를 꼬불쳐 둔다.  
아래 내용은 여기저기서 관련글들을 모아모아서 정리하였다. 낭중에 서버관리할때 처리하면 편하겠네..  




apache에서는 mod_expires 모듈을 통해 Expires HTTP header 를 설정할 수 있다.
이를 통하여 클라이언트(웹페이지 방문자)에 캐싱되는 문서나 이미지들이 많아서 트래픽을
감소시킬 수 있다. 이미지 전용 서버나 이미지 디렉토리에 설정을 해두면 효과적이다.

이미지 서버에 지정한 다음 예를 보자.


<IfModule mod_expires.c>
        ExpiresActive On
        ExpiresDefault "access plus 1 month"

        # 제외할 디렉토리
        <Directory "/usr/local/apache/htdocs/temp">
        ExpiresActive Off
        </Directory>
</IfModule>

- ExpiresActive On 지시자로 Expires 설정을 enable 한다.
- ExpiresDefault "access plus 1 month" 지시자는 액세스한지 얼마나 지나서 expire할 것인지를 지정한다.
  즉, 지정한 기간만큼 클라이언트에 캐싱이 된다. 위에는 1달이다.

이외에 클라이언트에서 액세스한지 1달, 4주, 30일, 1년 등과 같은 expire 주기와
서버의 파일의 수정 시간으로 expire 주기를 설정할 수 있다.

ExpiresDefault "access plus 1 month"
ExpiresDefault "access plus 4 weeks"
ExpiresDefault "access plus 30 days"
ExpiresDefault "access plus 1 years"
ExpiresDefault "modification plus 30 days"



ExpiresDefault "<base> [plus] {<num> <type>}*"
ExpiresByType type/encoding "<base> [plus] {<num> <type>}*"

ExpiresByType image/bmp "access plus 1 month" 
ExpiresByType image/cgm "access plus 1 month" 
ExpiresByType image/gif "access plus 1 month" 
ExpiresByType image/jpeg "access plus 1 month" 
ExpiresByType image/png "access plus 1 month" 
ExpiresByType image/jpeg "access plus 1 month" 
ExpiresByType image/tiff "access plus 1 month" 
ExpiresByType image/png "access plus 1 month" 

ExpiresByType video/mpeg "access plus 1 month" 
ExpiresByType video/quicktime "access plus 1 month" 
ExpiresByType video/x-msvideo "access plus 1 month" 

ExpiresByType audio/basic "access plus 1 month" 
ExpiresByType audio/midi "access plus 1 month" 
ExpiresByType audio/mpeg "access plus 1 month" 
ExpiresByType audio/x-aiff "access plus 1 month" 
ExpiresByType audio/x-mpegurl "access plus 1 month" 
ExpiresByType audio/x-pn-realaudio "access plus 1 month" 
ExpiresByType audio/x-wav  "access plus 1 month" 

ExpiresByType application/x-shockwave-flash  "access plus 1 month"


- 설정 마지막부분에 Directory 지시자와 ExpiresActive Off 설정을 통해
  특정 디렉토리만 expire 설정에서 제외할 수 있다.
  반대로 특정 디렉토리만 On으로도 설정할 수 있다. (일반 웹서버에 /images 와 같이 디렉토리가 있는 경우)


ExpiresByType image/gif "acces plus 4 weeks"


- 위처럼 파일의 유형으로도 가능하다.



파일 다운로드 php 에는 

header('Pragma: cache'); // 아파치가 자동으로 no-cache 를 붙이기 때문에 넣어준다. 
header('Cache-Control: max-age=2592000'); 
header('Expires: '.substr(gmdate('r', strtotime('+1 MONTH')), 0, -5).'GMT'); 




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

얼마전 부터 방명록에 몇몇 분들이 iframe 안에서 grid panel이 동작하지 않는다고 하여 포럼글을 찾아보던중 다음과 같은 버그가 존재하였다.

FF3, Opera, IE6에서 document를  load시 load타임이 맞지 않아서 생기는 버그였다. 기존 2.1버전에서 2.2 버전으로 업그레이드 하면서 생긴 버그이다. 만일  ext의 프리미엄 멤버라면 svn을 통해서 해당 내용들을 모두 업데이트 받았겠지만 가난한 나같은 개발자들은 그러지 못한 관계로 포스팅한다. 

먼저 가장 최근의 ext-2.2 버전을 다운로드한다. ( 같은 버전이라도 버그패치되는 대로 패치하기 때문에 매일매일 다를수 있다. 다운로드 받거든 이미 받았던 버전과 용량체크를 해 보면 바로 알수 있다.. ㅡ"ㅡ; )

ext-all-debug.js 를 이용한다면 다음과 같이 3개 메쏘드를 바꿔준다.

fireDocReady(),  initDocReady(), onDocumentRead()

1580줄 fireDocReady를 다음과 같이 바꿔준다.

 var fireDocReady = function(){
        docReadyState = true;
        if(Ext.isGecko) {
             document.removeEventListener("DOMContentLoaded", fireDocReady, false);
        }

        if(docReadyProcId){
             clearInterval(docReadyProcId);
             docReadyProcId = null;
        }

        if(docReadyEvent && !Ext.isReady){
            Ext.isReady = true;
            docReadyEvent.fire();
            docReadyEvent.clearListeners();
        }
    };


1597줄의 initDocReady를 다음과 같이 바꿔준다.

    var initDocReady = function(){
        docReadyEvent = new Ext.util.Event();

        if(Ext.isReady){ return;}

        E.on(window, 'load', fireDocReady);

        if(Ext.isGecko) {
            document.addEventListener('DOMContentLoaded', fireDocReady, false);
        }
        else if(Ext.isIE){
                                 
            document.onreadystatechange = function(){
                if(document.readyState == 'complete'){
                     document.onreadystatechange = null;
                     fireDocReady();
                }
            };
                                
             if(window == top){   //Use the default readystatechange/onload as primary detection mechanism for frames 
                   var doScrollChk = function(){
                    try{
                       document.documentElement.doScroll('left');
                       Ext.isReady || fireDocReady();
                   }catch(e){
                       Ext.isReady || setTimeout(doScrollChk ,0);
                   }
                  };
                  doScrollChk();
               }
          
        } else if(Ext.isOpera){
              document.addEventListener( 'DOMContentLoaded', function () {
                    if (Ext.isReady) return;
                    for (var i = 0; i < document.styleSheets.length; i++)
                          if (document.styleSheets[i].disabled) {
                                  setTimeout( arguments.callee, 0 );
                                  return;
                          }
                           Ext.isReady || fireDocReady();
                           document.removeEventListener("DOMContentLoaded", arguments.callee, false);

                }, false);
        }
        else if(Ext.isSafari){
           var re = /complete|loaded/i;
            docReadyProcId = setInterval(function(){
                if(re.test(document.readyState) ) {
                    Ext.isReady || fireDocReady();
                 }
            }, 10);
        }
    };


1743줄의 onDocumentReady를 다음과 같이 바꿔준다.

     onDocumentReady : function(fn, scope, options){
            if(!docReadyEvent){
                initDocReady();
            }
            if(docReadyState || Ext.isReady){
                options || (options = {});
                fn.defer(options.delay||1, scope);    ----------> 0을 1로 바꿔주면 된다.  defer(1)과 같은 효과
            }else{
                docReadyEvent.addListener(fn, scope, options);
            }
        },




직접 ext-all-debug.js를 수정하였을 경우는 다음과 같이 하면 되고 각각의 컴포넌트들을 수정하려면 아래 eventManager관련 파일을 찾아 덮어쓴후 다시 빌드하여 ext-all.js로 만들어 쓰면 된다. 





사족 : 조만간 올초에 3.0 이 나올텐데 다시 업그레이드 되겠죠~ 이클립스용 ext designer와 standalone designer도 벌써 3.0 버전용이 나와 있더군요.. ㅡ.,ㅡ;











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

Examples Of ExtJS in Action  (2) 2009.03.31
extjs RowAction 붙이기  (1) 2009.03.31
Extjs 3.0 Roadmap  (10) 2008.11.12
Ext2.2 Release  (11) 2008.08.07
ExtJS 2.1 릴리즈  (4) 2008.04.22
Post by 넥스트리소프트 데꾸벅(techbug)
, |

금일(2009/01/20)  KISA(인터넷침해사고대응지원센터)에서 홈페이지관련 보안강화도구인 캐슬을 배포하였다. (진작에 이렇게 하지..) 
 웹관련 분야에 종사하다 보면 프로젝트 말기에 보안관련 패치와 보안관련 레포트에 스트레스를 받아오던 차에 범정부(?) 적으로 지원해 주니 감사할 따름이다. 



최근 공격자들이 국내 홈페이지를 해킹하여 악성코드 유포 및 개인정보 탈취하는 사례가 지속적으로 발생하고 있습니다.

이에, 한국정보보호진흥원에서는 홈페이지의 보안성을 강화하는 "홈페이지 보안 강화도구(CASTLE)"를 배포하고 있습니다.

사용을 희망하는 회사(기관)나 개인 사용자 분들은 아래의 프로그램과 설명서를 다운받아 사용하시기 바랍니다.

○ CASTLE 다운로드(ASP, PHP, JSP)  --------------------

○ CASTLE 사용자 설명서 다운로드------------------------

○ CASTLE 설치 가이드 다운로드 -------------------------
※ CASTLE를 홈페이지에 적용하면, 주요 취약점을 공격하는 침입시도 및 공격코드들을 차단할 수 있습니다. 또한 개발 중이거나, 운영 중인 홈페이지에 약간의 수정을 통해 쉽게 적용 가능하고, 적용 후 CASTLE의 관리 기능으로 손쉽게 관련 정책이나, 설정을 수정할 수 있습니다.




참고적으로 웹보안 4종가이드를 첨부하여 올린다. 

1. 홈페이지 개발 보안가이드
2. 웹애플리케이션 보안템플릿(PHP버전)
3. 웹서버 구축 점검가이드
4. 가이드 CD


















'Integrator > SECURITY' 카테고리의 다른 글

IIS 405 Error 처리방법  (2) 2008.10.29
Post by 넥스트리소프트 데꾸벅(techbug)
, |


들어가기에 앞서
얼마전 가트너에서 발표한 2009 웹 10대 전략을 아래와 같이 요약하였다.
1. 가상화(Virtualization)
2. 클라우드 컴퓨팅(Cloud Computing)
3. 서버(Servers)
4. 웹 기반 아키텍처(Web-Oriented Architectures)
5. 엔터프라이즈 매쉬업(EnterpriseMashups)
6. 특성화 시스템(Specialized Systems)
7. 소셜 소프트웨어와 소셜 네트워킹(Social Software and Social Networking)
8. 통합 커뮤니케이션즈(Unified Communications)
9. 비즈니스 인텔리전스(Business Intelligence)
10. 그린IT(Green IT)

대부분의 2009년 웹트렌드는 소셜네트웍, 모바일, Saas라 불리는 클라우딩 컴퓨팅에 초점을 맞추고 있다. 대부분이 2008년에 이미 이슈화 되었고 앞으로 기술전망에서 언급된 내용이였다. 다만 전망하지 못한 부분들이 있었는데 금융위기에 관련된 부분이 조금 추가되었을 뿐이다. 
그런데 그에 따른 디자이너들의 웹트렌드에 대책은 어느정도 만족할수 있을까라는 생각에 여러사이트들을 둘러보다가 좋은 정보가 있어 포스팅한다. 


디자이너들은 항상 새로운것을 요구하고 여러가지를 경험하는 것을 좋아합니다.
작업물에 사용자의 반응을 지켜보는것을 좋아하고 가능한한 주류보다는 남들과 차별화된 디자인적 접근을 좋아합니다. 결론적으로 남들과 다르게 접근하고 새로운 트렌드를 추구하는 디자이너를 위해 최근 몇개월간의 추세를 기준으로 2009년 웹디자인트렌드를 작성합니다..
 - 원본글 중에서


1. Letterpress

최근 몇개월간 이제껏 많이 사용하지 않았던 온라인 서비스를 하는 웹사이트에서 인쇄물에서의 글꼴과 같은 웹사이트들이 많이 출현하였습니다. 이미 국내의 네트웍 인프라 덕분에(?) 국내의 다수 웹사이트는 이미 이러한 대형 인쇄타이포를 이용한 웹사이트들이 많이 있습니다. 특히 웹에이젼시나 디자인 전문 포트폴리오 사이트의 경우에는 더더욱 그렇습니다.


[ http://365daysofastronomy.org/ ]


[ http://www.alexbuga.com/v8/ ]


[ http://brightkite.com/ ]


[ http://www.powerset.com/ ]


[ http://www.storenvy.com/ ]


[ http://unblab.com/login ]


[ http://www.leemunroe.com/ ]


[ http://2d2.es/ ]


[ http://www.respiromedia.com/ ]






2. Rich User Interfaces

기쁘게도 현대 웹사이트와 웹애플리케이션에서의 UI는 점점 더 뷰티플해지고 사용하기 좋아집니다. 그러나 최근 몇년 동안은 이러한 애플리케이션의 사용자경험이 환상적으로 향상되고 전통적인 데스크탑애플리케이션에 거의 가깝게 진화하고 있습니다.

특히 지난해에는 더 많은 사이트들에서 다양한 디자인 요소로써 사용되고 있고 사용성을 중시한 인터페이스들이 나타나기 시작하였습니다.  웹동향과 마찬가지로 RIA, Flex, Javascript UI Libraries의 영향으로 이러한 현상은 점점더 두드러 질것으로 예상됩니다.


[ http://www.quicksnapper.com/ ]


[ http://www.quicksnapper.com/ ]


[ http://dc2009.drupalcon.org/> ]

위의 두 예제는 웹애플리케이션 디자이너들에게 좀더 기능적으로 접근하고 표현하기 위해 그들의 경험을 향상시키고 있는 증거이다.


[ http://konigi.com/interface/mobileme-calendar-date-selector ]


[ http://www.newspond.com/science/ ]


[ http://www.howcast.com/categories ]


[ http://moodstream.gettyimages.com/ ]


[ http://www.gettyimages.com/ ]


[ http://listen.grooveshark.com/ ]


[ http://www.kontain.com/#home ]









3. PNG transparency

투명한 PNG 포맷은 불행히도 IE6에서는 지원하지 않지만(IE6에서도 편법적으로 지원합니다.) 좀더 사용자들에게 좋은 이미지를 제공하게 해둔다. 이전까지의 투명이미지는 PNG만큼의 쿨러티를 지원해주지 않았으나 PNG의 투명도를 이용한 디자인은 아래와 같이 근사한 사이트를 디자인 하게 해준다. 

IE6에서는 setPNG와 같이 자바스크립트 나 url(data: /base64)와 같은 CSS만으로도 가능하겠지만 디자인적인 측면에서 투명이미지 사용으로 인하여 얻는 효과는 무궁무진합니다. 


[ http://rustinjessen.com/ ]


[ http://dc2009.drupalcon.org/ ]


[ http://24ways.org/ ]


[ http://labs.paulicio.us/viewport/#2 ]


[ http://www.restroom.nl/ ]


[ http://www.wishingline.com/notebook/ ]


[ http://carrotcreative.com/ ]







4. HUGE Typography

사용자에게 좀더 어필하기 위하여 36픽셀이상의 폰트들이 많이 사용되고 있습니다. 특히 웹디자인 에이젼시나 포트폴리오 사이트, 제품사이트에서 많이들 사용됩니다. 국내의 웹사이트들은 이미 많이들 사용하고 있죠? 다만 깨끗한 한글폰트를 사용하는 사이트는 그리 많지 않고 대부분이 영어라는 점에서 아쉬운점은 있습니다.


[ http://www.francescomugnai.com ]


[ http://madebygiant.com/ ]


[ http://theautumnfilm.com/red-white-sale/us.html ]


[ http://www.signalapps.com/ ]


[ http://www.blackestate.co.nz/ ]


[ http://www.onefastbuffalo.com/ ]


[ http://www.shiftpx.com/ ]







5. Font Replacement

기존의 폰트에서 요즘은 다른 폰트들로 바껴가고 있습니다. 타이포그라피에 더 많은 주의를 기울이는 디자이너들 만큼 웹사이트의 본문에 더 세심한 주의를 기울입니다. 기존의 helvetica, arial, georgia,verdana체에서 다양한 폰트들로 웹사이트가 채워졌습니다. 재미있는것은 이러한 폰트들이 웹사이트의 디자인을 결정하기도하며, 사용자들에게 더 어필한다는 것입니다. 


[ http://blog.iso50.com/ ]


[ http://365daysofastronomy.org/ ]


[ http://www.chigarden.com/ ]


[ http://www.nonesuch.com/journal ]


[ http://daily.creattica.com/ ]









6. Modal Boxes (Lightboxes)

Modal boxes (dialog windows)는 차세대 팝업화면입니다. 이미 모든 브라우저에서 팝업차단기능때문에 div 태그와 자바스크립트를 이용한 팝업을 많이 겪어 보았을 것입니다. 이러한 팝업도 둥근 모서리의 애플리케이션 디자인처럼 진화하고 있습니다.


[ http://typedeskref.com/ ]


[ http://www.realmacsoftware.com/rapidweaver/overview/ ]


[ http://listen.grooveshark.com/ ]








7. Media Blocks

점점 더 빠른 네트웍인프라가 좋아지다 보니 이러한 미디어 블럭들이 많이 사용되고 있습니다. 사용자들에게 좀더 빠르고 사용하기 편하고 접근성이 좋은 디자인을 제공하기 위하여 자바스크립트와 플래쉬를 이용한 기술들이 주류를 이루고 있습니다.


[ http://www.getbackboard.com/ ]


[ http://www.goodbarry.com/ ]









8. The Magazine Look

대부분의 블로그, 기술 포트폴리오 사이트등등에서 게시물의 배치, 타이포그래피등 전통적인 인쇄방식의 그리드 기반의 디자인이 점점 인기를 끌고 있습니다. 현재 보시고 계신 티스토리 블로그 조차도 잡지와 같은 그리드 형식을 뛰고 있는것이 많으며 특히 뇌입어블로그의 스마트에디터의 경우느 이러한 그리드-레이아웃 템플릿 조차도 지원하고 있습니다.


[ http://www.alpha-multimedia.com/category/blog ]


[ http://www.objectifiedfilm.com/ ]


[ http://www.inspirationbit.com/sources-of-inspiration-to-the-rescue/ ]


[ http://www.good.is/ ]


[ http://cutandtaste.com/ ]


[ http://www.nonesuch.com/journal ]







9. Carousels (Slideshows)

Carousels은 자신이 원하는 페이지를 마우스 클릭이나 키보드의 화살표만으로 이동할수 잇는 슬라이드 네비게이션의 필수요소입니다. 이러한 슬라이드쇼는 사용자들로 하여금 더 쉽게 원하는 컨텐츠를 찾을수 있도록 배려해 줍니다.

전통적인 탑-레프트-컨텐츠 레이아웃에서 좀더 사용자들에게 쉽고 빠르게 정보를 전달하기 위해서 더 유용한 방식의 슬라이드 네비게이션이 강조되는 경향이 많습니다. 뇌입어의 웹캐스트도 같은 현상이라고 봐도 될런지... 


[ http://www.itv.com/ ]


[ http://money.cnn.com/ ]


[ http://music.yahoo.com/ ]


[ http://vickycristina-movie.com/ ]







10. Introduction Blocks

대부분의 웹사이트에서 상단-왼쪽영역은 가장 중요한 부분입니다. 이부분은 사용자에게 중요한 메세지나 권리들을 알려주고 가능한 빨리 메세지를 전달하는 역할을 합니다. 사실 많은 디자이너들이 웹애플리케이션이나 회사웹사이트디자인이든 온라인 서비스든 포트폴리오 사이트이든 상단-왼쪽 영역은 슬로건이나 간단한 소개를 넣는 것을 좋아합니다. 이곳에는 생생한 타이포그래피나 강력한 인상을 위하여 임팩트한 이미지들이 많이 사용됩니다. 보통 250~400픽셀의 높이로 사용됩니다. 디자인 요소 중 정보전달의 중요한  "강"-"약" 포인트에서 "강"에 해당되는 임팩트가 주로 들어가는 영역입니다. 


[ http://www.shannonmoeller.com/ ]


[ http://productplanner.com/ ]


[ http://www.45royale.com/ ]


[ http://revyver.com/ ]


[ http://creamscoop.com/ ]





더 많은 정보는 이곳에서 확인하세요! 






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

ExtJS의 border-layout 과 같은 효과를 내는 jQuery플러그인이 나와서 소개합니다.

UI.Layout 플러그인 제작자이며 초기프로젝트 제한자인 Kevin Dalman씨 또한 extJS border-layout을 보고 감명받아 jQuery Plug-in을 만들었다고 하며, 간단한 헤더레이아웃이나 사이드에서 부터 툴바, 메뉴, 헬프패널, status bars, sub-forms등을 가지고 있는 복잡한 애플리케이션까지 원하는 어떤 레이아웃도 만들수 있다고 하네요 ^^;
라이센스제한은 듀얼라이센스로  GPL과 MIT 라이센스를 따르고 있습니다. 아무렇게나 써도 된다는 것이네요 다만 제작자들이 원하는것은 사용해보고 괜찮으면 jQuery 플러그인사이트에서 "rate it" 투표나 해달라는거네요.. ㅡ"ㅡ;

jQuery stable version : 1.2.6
jQuery UI 1.5.2
UI.Layout Plugin 1.2.0

extjs의 기본 border-layout


솔직히 jQuery의 레이아웃매니저가 사용하기는 더 어렵게 느껴지는 이유는 무얼까요?




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

jQuery Grid Plugin : jqGrid  (16) 2009.04.06
jQuery pageSlide  (0) 2009.01.12
jQuery 링크에 걸린 파일 사이즈 자동으로 알아내기  (1) 2008.09.03
jQuery Loading바 구현하기  (2) 2008.07.08
Post by 넥스트리소프트 데꾸벅(techbug)
, |


예전 블로그에 포스팅한 글이 우연히 스쿨[PHPSchool]에서 보다가 발견했다.
그때에 2007년이였으니 Prototype 1.5.0 에서 적용되던 것이였는데...... 

extjs에서 크로스도메인 처리하던 localXHR.js와 같은 기능을 하는것이다.
localXHR에서 사용된 개념과 비슷하게 여기에서도 동적으로 <script>태그로 생성한다. 시간나실때 짬짬히 뜯어보시는것도... 괜찮을듯 하다.

    this.node = document.createElement('SCRIPT');
    this.node.type = 'text/javascript';
    this.node.src = arg.url;  <---- 

사용법은 간단한다. prototype.js 를 import한뒤 아래에 transport.js를 import해서 기존 Prototype.js의 Ajax.Request 클래스를 상속받아 쓰면 된다.

Prototype.js에서 사용할때와 같이

new Ajax.Request('myurl', {
    method: 'GET',
    crossSite: true,
    parameters: Form.serialize(obj),
    onLoading: function() {
        //things to do at the start
    },
    onSuccess: function(transport) {
        //things to do when everything goes well
    },
    onFailure: function(transport) {
        //things to do when we encounter a failure
    }
});

Prototype.js 1.6.0 버전에서 쓰려면 기존 transport.js 하단 상속부분을 다음과 같이 수정해 주면 된다.

[1.5.0 버전]
Ajax.Request.prototype = Object.extend(Ajax.Request.prototype,{
    initialize: function(url, options) {
        this.setOptions(options);
        this.transport = (!this.options.crossSite) ? Ajax.getTransport() : new scriptTransport;
        this.request(url);
        }   
});

[1.6.0 버전]
Ajax.Request.prototype = Object.extend(Ajax.Request.prototype, {
    initialize: function(url, options) {
        this.options = {
          method:       'post',
          asynchronous: true,
          contentType:  'application/x-www-form-urlencoded',
          encoding:     'UTF-8',
          parameters:   '',
          evalJSON:     true,
          evalJS:       true
        };
        Object.extend(this.options, options || { });

        this.options.method = this.options.method.toLowerCase();

        if (Object.isString(this.options.parameters))
          this.options.parameters = this.options.parameters.toQueryParams();
        else if (Object.isHash(this.options.parameters))
          this.options.parameters = this.options.parameters.toObject();
       
        this.transport = (!this.options.crossSite) ? Ajax.getTransport() : new scriptTransport;
        this.options.asynchronous = (!this.options.crossSite) ? this.options.asynchronous : false;
        //turns of the timed onLoad executer
        this.transport.respondToReadyState = this.respondToReadyState.bind(this);
        this.request(url);
        }
});





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

Chap01. XForms 소개

Publisher/XForms / 2008. 12. 13. 14:20

현재 프로젝트에서 사용하는 국내산 X-Internet (컴스퀘어 트러스트폼)이 XForms기반이라 하여 찾다가 내용을 정리해본다.  

트러스트폼은 개인적으로 내가 모르는 소스가 밑단에서 실행되는걸 싫어해서 별로 좋아하는 솔루션은 아님에도 간단한 그리드형식 페이지나 브라우저 컨트롤의 경우는 상당히 맘에 든다.. 개발퍼포먼스는 상당히 빠른 편이다.
그러나 다른 솔루션들도 마찬가지겠지만 개발자들에게 어느정도의 권한을 주는 기능들이 별로 없어서 개발할때는 상당히 까다롭다다. 또한 API나 샘플화면의 부재는 개발상 많은 아쉬움이  남긴다.

우선 잡설은 집어치우고 트러스트폼에서 사용된 XForms에 대해서 알아보기로 한다.
현재 포스팅 중인 이 글은 w3school 내용을 번역해서 올림을 미리 알린다.. ㅡ.ㅡ;


XForms 1.0 (Second Edition) [W3C Recommendation](같은 이름의 X Window System GUI 라이브러리와 혼동하지 말라.)은 XML 데이터 프로세싱용 웹 폼 스팩으로서, 다양한 미디어를 통해 광범위한 플랫폼에서 사용할 수 있다. XForms는 폼의 목적과 표현을 분리한다. 폼이 어떤 것을 수행해야 하는지에 대한 고려 사항과 폼이 어떻게 보여질 것인가를 분리한다. 이것은 XML 콘텐트를 조작하기 위해 폼 UI를 개발할 때 사용할 수 있는 XML 어휘이다. XForms는 XHTML의 일부로 시작되었지만, 이제는 독자적인 길을 가고 있다. 어떤 사람들은 이것이 필요 이상으로 복잡하다고 지적하지만, 웹 폼이라는 복잡한 세계에 질서를 가져다 주었다. 현재 XForms 1.1 [개발 중], 가용성 향상에 초점을 맞추고 있다.

XForms를 하기전에 갖춰야 할 기반 지식
  • HTML
  • HTML Forms
  • XHTML
  • XML

XForms란 도대체 무엇이며 좋은점은?
  • 웹에서 input form을 생성하기 위해 XML을 사용하는 차세대 HTML Forms이다.  
  • HTML Forms보다 더 유연하고 풍부한 기능을 자랑한다.
  • XHTML2.0의 form기준
  • XForms는 장치(device)와 독립적인 플랫폼이다.
  • 화면단으로 부터 로직과 데이타영역을 분리한다.
  • 폼데이타를 정의하기 위해 XML을 사용한다.
  • XML 문서에 데이타를 저장하고 전송한다.
  • 폼데이타를 XML로 정의한다.
  • 폼데이타의 정합성이나 계산과 같은 기능을 가지고 있다.
  • 스크립트할 필요를 없애거나 줄여준다. (이건 아닌것 같아요...)
  • W3C의 권고안이다... 


XForms는 HTML Forms의 후계자(Successors)이다.
오늘날 많은 웹애플리케이션의 중요한 부분이 Formdlek. HTML폼은 웹애플리케이션이 사용자로 부터 입력을 받을수 있도록 해준다. HTML 폼이 HTML표준의 한파트로서 사용된후 10년째인 현재, 웹사용자들은 표준 HTML폼의 한계를 띄어넘는 복잡한 트랜잭션을 사용하고 있다.
XForms는 좀더 풍부하고, 보안성이 뛰어나며 디바이스 독립적인 방법으로 웹입력을 제공한다. 조만간 XForms-enabled된 브라우저를 사용하기를 기대한다.
(데꾸벅 주: 그러나 현재 XForms를 지원하는 브라우저는 없다. 다만 국내에서는 ActiveX를 사용하고 있다.
Firefox에서는 플러그인을 사용하여 XForms를 테스트해볼수 있다.
)

XForms는 화면단으로 부터 로직과 데이타영역을 분리한다.
Xforms는 화면단으로 부터 로직과 데이타 영역을 분리하기 위해 XML을 사용하고 있다. 이 기능은 애플리케이션으로 사용자와 소통을 원할하게 할것이다.  (데꾸벅주 : 무간섭 스크립트와 같이 쓴다면 모르겠지만.. designer


데이타 저장 및 전송을 XML로 처리
XML 문서안에서 데이타를 저장하고 XML전문을 전송하며 화면에 출력한다.

XForms는 장치에 독립적이다.
모든 장치에서 사용할수 있는 DATA MODEL때문에 device 독립적이며  서로다른 UI (모바일폰, 이동장치,점자 판독기)에서 커스터마이징할수 있다. XML에 기반한 Xforms의 장치독립성 때문에 VoiceXML이랑, WML, SVG와 같은 XML애플리케이션안에서 직접적으로 XForms elements를 추가할수 있다.

XForms는 W3C권고안이다.
XForms1.0 은 2003년 10월에 W3C 표준권고안으로 채택되었다.  권고안보기


XHTML2.0 Spec중 하나이다. [XHTML2.0]
XHTML2.0은 아래와 같은 요소로 구성되어 있다 XForms도 그중에 하나로 버젓이 등록되어 있다.. XFrames와 같이..
  • RDFa (Resource Definition Framework)
  • XForms
  • Access
  • Role
  • XML Events (XForms에서도 사용된다.. ㅡ.,ㅡ;)

Specification FPWD LC CR PR Rec
XForms 1.1 Nov 2004 Feb 2007 Nov 2007 July 2008 Sep 2008
XForms 1.2 
Streamlined for Web Authors 
(Transitional)
June 2008 Dec 2008 Mar 2009 Oct 2009 Dec 2009
XForms 2.0 Nov 2008 Sep 2009 Dec 2009 Sep 2010 Nov 2010




'Publisher > XForms' 카테고리의 다른 글

Chap03. XForms Namespace  (0) 2008.12.14
Chap02. XForms Model  (0) 2008.12.14
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)
, |

Extjs 3.0 Roadmap

Scripter/EXTJS / 2008. 11. 12. 16:42

벌써 2.2가 Release되고 3.0이 Extjs Forum글에서 언급되고 있다.
Extjs Roadmap을 포스팅한지가 지난 4월이였는데 이번주 Ajaxian사이트에 올라온 Extjs Designer동영상을 보니 다시금 불끈~~!!


Ext JS 2.1 (Released April 21, 2008)

View the release notes for full details.

  • Full REST support
  • Remote component loading samples
  • First class support for non-Ajax form submits
  • Upgrade all adapter libraries to current versions
  • Additional support for AIR platform
  • Grid filtering sample
  • StatusBar
  • Slider
  • CheckBox/Radio group controls (deferred to 2.2)

Ext JS 2.2 (Released August 4, 2008)

View the release notes for full details.

  • Styled Checkbox and Radio button controls
  • CheckBox/Radio group controls
  • Browser history support
  • XML TreeLoader sample
  • FileUpload field sample
  • MultiSelect and ItemSelector sample
  • Firefox 3.0 support
  • Slider (already released in 2.1)
  • Ext.Ajax enhancements (deferred to 3.0)
  • Support for reset styles scoped to Ext components only (deferred to 3.0 to coincide with additional CSS refactoring to enable easier custom theming)

Ext JS 3.0 (Early 2009)

  • All new lightweight, high-speed core base library
  • Flash Charting API
  • Ext.Direct - Remoting and data streaming/comet support
  • Integrated client-server data binding/marshaling of updates
  • ListView component
  • Enhanced Button and Toolbar components
  • ARIA/Section 508 accessibility improvements
  • CSS updates for reset style scoping and easier custom theming
  • Update the Ext event registration model
  • Ext.Ajax enhancements
  • Browser history support (released in 2.2)


출처 : http://extjs.com/products/extjs/roadmap.php

아래 동영상은 3.0 Release시 같이 출시된 designer tool 이다... 흠.. 이거 쓰면 괜찮겠는데.. Trust Form Designer랑 비슷하다.. ㅡ.,ㅡ;







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

extjs RowAction 붙이기  (1) 2009.03.31
extjs 2.2의 IE에서 iframe document load 버그패치  (0) 2009.01.21
Ext2.2 Release  (11) 2008.08.07
ExtJS 2.1 릴리즈  (4) 2008.04.22
RESTFul 한 ExtJS  (0) 2008.04.16
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.p3pwriter.com/LRN_111.asp



HTTP Header
해당 웹페이지가 보내지기 전에 META Information을 포함하여  페이지에 대한 정보 및 브라우저에 전달하는 정보

HTTP/1.1 200 OK
Date: Wed, 11 Oct 2003 01:11:50 GMT
Server: Apache/1.2.0
Last-Modified: Fri, 01 Jun 2003 11:16:44 GMT
ETag: "31f9e-620-44ca89c1"
Content-Length: 3112
Accept-Ranges: bytes
Connection: close
Content-Type: text/html


META HTTP-EQIV
웹페이지 화면 상단에 위치한 META태그로 해당 페이지 전체에 적용된다.
아래와 같이 입력시

<META HTTP-EQUIV="Author" CONTENT="P3Pwriter">

브라우저에서는 다음과 같은 Header정보를 보여준다.

HTTP/1.1 200 OK
Date: Wed, 11 Oct 2003 01:11:50 GMT
Server: Apache/1.2.0
Last-Modified: Fri, 01 Jun 2003 11:16:44 GMT
ETag: "31f9e-620-44ca89c1"
Content-Length: 3112
Accept-Ranges: bytes
Author: P3Pwriter
Connection: close
Content-Type: text/html

브라우저가 웹페이지문서를 받기전에 해당페이지에 Header값이 전달된다.
HTML이 브라우저에 의해 decoded되기 될때 브라우저에 Header값이 전달된다는 얘기이다.

HTTP-EQUIV의 정의에서 보면 이것은 "응답 HEADER안의 특별한 문자로 된 정보"를 읽는다는 것이다. 진실은 대부분의 서버가 META tag를 이용하여 페이지에 Header값들을 추가한다는 것이다.  P3P의 경우는 compat policy가 반드시 응답Header에 의해 전달되는것은 별로 좋지 않다.

실제 P3P의 동작원리
P3P Header는 브라우저에 의해 compact policy를 전달되고, 응답Header 안에 포함된 cookie값에 의해 페이지에 전달된다. 전달된 Policy는 브라우저의 privacy 셋팅에 의해 결정지어진다.
HTTP Header는 두가지 다른 방법으로 페이지에 추가될수 있다. 첫번째는 선택된 페이지나 모든 페이지의 header정보를 전달하는 서버파일들을 수정하는 것이고,  두번째는 asp,php,perl,cold funsion과 같은 프로그램언어를 사용하는 방법이다. 

프로그램언어를 이용해서 P3P Header를 추가하기 위해서는 HTML을 렌더링하기 전에 작성해야 한다.

<?여기다가 공백없이 작성해 주세요 UTF-8일때 NOBOM으로도... ?>
<HTML>
<HEAD>
<TITLE>MyPage</TITLE>
</HEAD>
<BODY>
Information
</BODY>
</HTML>






 

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

Ajax Framework 분석  (0) 2009.05.04
CSSHttpRequest  (0) 2008.11.12
AJAX에서 즐겨찾기와 뒤로가기를 다루는 방법  (0) 2008.09.24
100라인 Ajax Wrapper  (0) 2008.04.19
어떤 AJAX Framework를 선택할 것인가.  (0) 2008.03.14
Post by 넥스트리소프트 데꾸벅(techbug)
, |
ajax POST로 호출시 같은 도메인의 다른 웹서버의 xml 을 호출하였을 경우 405에러가 발생하는 경우가 있다.  이럴때는 get방식으로 처리한다. ㅡ.,ㅡ;  무조건 ajax는 RESTful하게 작성하는게 좋겠다...

 
   $.ajax({
        type: "POST", url: "xml/liveScore.xml",   //--> GET바꿔주면 해결끝
        data: {}, async: true, cache: false, dataType: 'xml',  timeout: 5000, global: false,
        success:function(resultDataSet){
            if(resultDataSet !=undefined && resultDataSet !=null ){
                var howManyLivescoreList =$(resultDataSet).find('list').length;
                if(howManyLivescoreList > 0 ) {
                    changeMainTab("livescore");
                }
            }
        }
    });




아래 사이트 참조 :
http://www.somacon.com/p126.php


원인은 IIS script map settings 에 get방식으로 조회가능한 확장자로 되어있어서 맵핑을 시켜주지 않는데서 있다.  보안정책상 IIS6에서는 스크립트 실행을 되지 않게 해 놓은데서 발생하는 문제다.

해결책은 다음과 같이..

  1. Go to "Control Panel"-"Administrative Tools"-"Internet Information Services".
  2. Expand the tree to "COMPUTERNAME"-"Web Sites"-"Default Web Site".
  3. Right-click on "Default Web Site" and select "Properties". (Alternately, select "Default Web Site" and press Alt+Enter.)
  4. Select the "Home Directory" tab.
  5. Click the "Configuration" button.
  6. From the "Mappings" tab, select the "Add" button.
  7. Click the "Browse..." button, choose "Dynamic Link Libraries *.dll" from the "Files of Type" dropdown, and select c:\WINDOWS\System32\inetsrv\asp.dll.
  8. Type ".html" (without quotes) in the "Extension" box.
  9. Select the "Limit to:" radio button, and type in "GET, POST" (without quotes) in the box next to it.
  10. Click the "OK" button and close all the dialogs. (If the "OK" button is greyed out, then make sure all the entries are correct and try clicking in the file name box.)

이것보단 그냥 RESTful하게 조회는 GET으로 처리하는게...



'Integrator > SECURITY' 카테고리의 다른 글

홈페이지 보안 강화 도구(CASTLE) 보급 안내  (1) 2009.01.20
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)
, |

location.href =====> protocol :// hostname : port / pathname ? search # hash





히스토리기능으로 고민하던 어느분이 메일로 도움을 청해와서 찾아보던중
Ajax History기능구현이 가능하다는걸 알았다.
관련글을 찾아보던중 번역문서를 찾아 포스팅 한다.

원문 :  [ajax-history-libraries],
번역문 : [한빛미디어]
국내관련글 : juDe's blog(친절히도 설명해 놓았다.. ^^) [1],[2],[3],[4]

관련 파일 : dhtmlHistory.js



===========================================================
여기서는 AJAX 응용 프로그램에 즐겨찾기와 뒤로 이동을 지원하는 오픈 소스 자바스크립트 라이브러리를 소개할 것이다. 이 글을 마지막까지 보게된다면 구글맵스지메일과 같은 곳들조차 제대로 지원하지 못했던 웹 사이트에서의 즐겨찾기, 앞으로 이동, 뒤로 이동과 같은 AJAX의 문제들을 해결할 수 있게 될 것이다.

"AJAX: 즐겨찾기와 뒤로 이동을 다루는 방법"에서는 에 이잭스(AJAX) 응용 프로그램들이 현재 당면하고 있는 즐겨찾기, 뒤로 이동과 같은 중요한 문제들을 설명하고, 이 문제를 해결하기 위한 오픈 소스 프레임워크인 RSH(Really Simple History) 라이브러리를 소개하고, 실제 예제들을 몇 가지 소개할 것이다.

([1]역주: 영어사전에서 AJAX는 에이잭스로 소개되며, 그리스의 신화의 아이아스나 오딧세이의 아이아스를 의미한다. sys-con의 AJAX & Rich Internet Applications 프레젠테이션에서도 그 발음을 확인할 수 있다. 네덜란드 축구팀의 이름을 딴 아약스, 또는 아작스 등으로 불리기도 한다. 한편, 세제 제조회사인 Ajax Industries는 "에이잭스社"로 옮긴다.)

여 기서 소개할 프레임워크의 주요 부분은 두 개로 나뉘어진다. 첫째는 클라이언트의 정보를 갖고 있는 임시 세션 캐시를 사용하기 위해 숨겨진 HTML 폼을 사용한다. 이 캐시는 어떤 지점으로 이동하거나 페이지를 떠나는 경우에도 사용할 수 있다. 둘째는 A 태그와 숨겨진 iframe을 사용해서 브라우저 히스토리를 가로챈 다음 브라우저 히스토리 이벤트를 기록하고, 뒤로 이동과 앞으로 이동 버튼에 연결한다. 이 두 가지 기능은 모두 개발시에 쉽게 이용할 수 있도록 간단한 자바스크립트 라이브러리로 되어있다.

문제

즐 겨찾기와 뒤로 이동은 여러 페이지로 구성된 전형적인 웹 응용 프로그램에서 매우 유용하다. 사용자가 웹 사이트를 항해할 때, 브라우저의 주소 창은 새로운 URL로 업데이트되며, 나중에 이 주소를 다시 방문하기 위해 이메일에 붙여넣거나 즐겨찾기에 추가할 수 있다. 뒤로 이동, 앞으로 이동 버튼들도 올바르게 동작하며, 사용자는 방문했던 페이지들을 자유로이 이동할 수 있다.

그 러나, 에이잭스 응용 프로그램은 웹 페이지 하나에서 동작하는 복잡한 프로그램이기 때문에 예외적인 응용 프로그램이다. 브라우저는 이런 기능을 위해 만들어지지 않았다. 웹 응용 프로그램들이 마우스 클릭을 할 때마다 완전히 새로운 페이지를 가져올 수 있게 되었어도 브라우저는 과거에 사로잡혀 있다.

지메일과 같은 AJAX 소프트웨어에서 사용자가 기능을 선택하고, 응용 프로그램의 상태를 바꾸어도 브라우저의 주소창은 항상 같은 위치만 갖고 있기 때문에 응용 프로그램의 특정 화면에 대해 즐겨찾기를 축가하는 것은 불가능하다. 뿐만 아니라, 사용자가 이전 작업을 원상태로 되돌리기위해 뒤로 이동 버튼을 클릭하면 브라우저가 응용 프로그램의 웹 페이지를 떠나기 때문에 사용자들은 놀라게 된다.

해결책

오픈소스 RSH(Really Simple History) 프레임워크는 이러한 문제를 해결하고, 에이잭스 응용 프로그램에서 즐겨찾기, 뒤로 이동, 앞으로 이동을 제어할 수 있게 해준다. RSH는 현재 베타 버전이며, 파이어폭스 1.0, 넷스케이프 7 이상, 인터넷 익스플로러 6 이상의 버전에서 동작하며, 사파리는 현재 지원되지 않는다.(이에 대한 설명은 나의 웹 로그에서 Coding in Paradise: Safari: No DHTML History Possible를 참고하기 바란다.)

몇몇 에이잭스 프레임워크는 현재 즐겨찾기와 히스토리 문제를 해결하려 하고 있지만 이들 프레임워크는 구현 방식 때문에 몇가지 중요한 버그들을 해결하지 못하고 있다.(보다 자세한 사항은 "Coding in Paradise: AJAX History Libraries"를 참고한다) 게다가, 많은 에이잭스 [2]히스토리 프레임워크는 BackbaseDojo 같은 보다 큰 라이브러리안에 통합된 형태로 되어 있다. 이들 프레임워크는 AJAX 응용 프로그램에 대해서 완전히 다른 프로그래밍 모델을 제공하고 있으며, 개발자가 히스토리 기능을 사용하기 위해서는 완전히 새로운 접근방법을 사용할 것을 강요받게 된다.

([2]역주: 히스토리(History)는 "기록" 또는 "방문기록"으로 옮기지만 대부분이 히스토리에 익숙하기 때문에 번역하지 않았다)

반면에, RSH는 기존 AJAX 시스템에 포함시킬 수 있는 간단한 모듈로 되어 있다. 뿐만 아니라, RSH 라이브러리는 다른 히스토리 프레임워크들이 갖고 있는 버그들을 피하기 위한 기술들을 사용하고 있다.

RSH 히스토리 프레임워크는 자바스크립트 클래스 DhtmlHistory, HistoryStorage로 구성되어있다.

DhtmlHistory 클래스는 에이잭스 응용 프로그램을 위한 히스토리 추상화를 제공한다. 즉, 에이잭스 페이지는 브라우저에 새 위치와 그에 대한 히스토리 데이터를 지정한 히스토리 이벤트를 추가하는 add()를 호출한다. DhtmlHistory 클래스는 A 태그에 #new-location과 같은 해쉬를 사용해서 브라우저의 현재 URL을 업데이트하고, 히스토리 데이터와 새 URL을 연결한다. 에이잭스 응용 프로그램 자체를 히스토리 리스너(listener)로 등록하고, 사용자가 뒤로 이동, 앞으로 이동 버튼을 사용해서 이동할 때 마다 히스토리 이벤트는 add() 호출로 저장했던 히스토리 데이터와 브라우저의 위치를 제공한다.

개발자는 HistoryStorage 클래스를 사용해서 어떤 크기의 히스토리 데이터라도 저장할 수 있다. 일반 페이지에서 사용자가 새로운 웹 사이트로 이동할 때 브라우저는 이전 웹 페이지의 모든 응용 프로그램을 제거하고, 응용 프로그램과 자바스크립트의 상태를 정리한다. 따라서, 사용자가 뒤로 이동 버튼을 사용하여 이전 페이지로 돌아가면 모든 데이터가 사라진다. HistoryStorage 클래스는 put(), get(), hasKey()와 같은 간단한 해쉬 테이블 메서드를 제공하는 API를 통해서 이 문제를 해결한다. 사용자가 웹 페이지를 떠난 다음에도 개발자는 이들 메서드를 사용해서 데이터를 저장할 수 있다. 사용자가 뒤로 이동 버튼을 사용해서 돌아오면 HistoryStorage 클래스를 사용해서 데이터에 접근할 수 있다. 이 기능은 사용자가 웹 페이지를 떠난 후에도 브라우저가 폼 양식에 있는 값들을 자동으로 저장한다는 사실을 이용한 것으로, 숨겨진 폼 필드를 사용해서 구현됐다.

예제

이제 바로 간단한 예제로 살펴보자.

먼저, RSH 프레임워크를 사용할 페이지는 dhtmlHistory.js 스크립트를 반드시 인클루드해야 한다.

<!-- Load the Really Simple
       History framework -->
<script type="text/javascript"
            src="../../framework/dhtmlHistory.js">
</script>


DHTML 히스토리 응용 프로그램은 에이잭스 웹 페이지가 있는 디렉터리에 blank.html 파일을 포함시켜야 한다. 이 파일은 RSH 프레임워크에 함께 들어있으며, 인터넷 익스플로러에서 사용한다. 여담이지만, 인터넷 익스플로러는 히스토리 변경 사항을 추적하고 추가하기 위해 "숨겨진 iframe"을 사용한다. 히스토리 기능이 제대로 동작하기 위해서는 실제 위치를 가리키는 것이 필요한데, 이를 위해 비어있는 iframe을 사용한다. 그래서 이름도 blank.html이다.

RSH 프레임워크는 브라우저 히스토리를 조작하기 위한 진입점으로 dhtmlHistory라는 전역 객체를 생성한다. dhtmlHistory로 작업하는 첫번째 단계는 페이지 로딩이 끝난 후에 이 객체를 초기화하는 것이다.

window.onload = initialize;
     
function initialize() {
   // initialize the DHTML History
   // framework
   dhtmlHistory.initialize();

다음으로, 개발자는 히스토리 변경 이벤트를 [3]구 독하기 위해 dhtmlHistory.addListener()를 사용해야 한다. 이 메서드는 DHTML 히스토리가 변경될 때, 페이지의 새로운 위치, 히스토리 변경 이벤트와 관련된 히스토리 데이터를 인자로 받는 콜백 함수를 인자로 받는다.

([3]역주: 이벤트 구독보다는 이벤트 감시가 더 적절한 표현이지만 원문이 subscribe이므로 구독으로 옮김)

window.onload = initialize;
     
function initialize() {
// DHTML 히스토리 프레임워크를 초기화한다
   dhtmlHistory.initialize();
   
// HTML 히스토리 변경 이벤트를 구독한다
   dhtmlHistory.addListener(historyChange);

historyChange() 메서드는 사용자가 새 위치로 이동한 후의 newLocation과 히스토리 변경 이벤트와 관계된 historyData를 인자로 받는 함수로 이해하기 쉽다.

/** 히스토리 변경 이벤트를 받기 위한 콜백 */
function historyChange(newLocation,
                                  historyData) {
   debug("A history change has occurred: "
            + "newLocation="+newLocation
            + ", historyData="+historyData,
            true);
}


위에서 사용한 debug() 메서드는 예제 소스 파일에 정의된 유틸리티 함수로 전체 예제 안에 포함되어 있다. debug()는 웹 페이지안에 메시지를 출력한다. 두번째 인자는 불리언(boolean) 타입으로 위 인자에서는 true를 사용했다. true를 사용하면 앞의 메시지를 모두 정리한 다음에 새로운 디버그 메시지를 출력한다.

개 발자는 add() 메서드를 사용해서 히스토리 이벤트를 추가한다. 히스토리 이벤트를 추가하는 것은 edit:SomePage와 같이 히스토리 변경 이벤트와 함께 저장할 historyData 값을 제공하기 위한 새 위치를 지정하는 것이다.

window.onload = initialize;
     
function initialize() {
   // initialize the DHTML History
   // framework
   dhtmlHistory.initialize();
   
   // subscribe to DHTML history change
   // events
   dhtmlHistory.addListener(historyChange);
         
   // if this is the first time we have
   // loaded the page...
   if (dhtmlHistory.isFirstLoad()) {
      debug("Adding values to browser "
               + "history", false);
      // start adding history
      dhtmlHistory.add("helloworld",
                               "Hello World Data");
      dhtmlHistory.add("foobar", 33);
      dhtmlHistory.add("boobah", true);
         
      var complexObject = new Object();
      complexObject.value1 =
                           "This is the first value";
      complexObject.value2 =
                           "This is the second data";
      complexObject.value3 = new Array();
      complexObject.value3[0] = "array 1";
      complexObject.value3[1] = "array 2";
         
      dhtmlHistory.add("complexObject",
                               complexObject);

add() 를 호출하는 즉시 사용자 브라우저의 URL 툴바에 새로운 위치가 표시된다. 예를 들어, http://codinginparadise.org/my_ajax_app 주소의 에이잭스 웹 페이지에서 dhtmlHistory.add( "helloworld", "Hello World Data" )를 호출하면 사용자는 브라우저의 URL 툴바에서 다음 주소를 보게 된다.

http://codinginparadise.org/my_ajax_app#helloworld

사 용자는 이 페이지를 북마크할 수 있다. 사용자가 이 북마크를 이용하면 에이잭스 응용 프로그램은 #helloworld 값을 읽어서 웹 페이지를 초기화할 수 있다. 해시 # 다음의 위치 정보는 RSH 프레임워크에 의해 투명하게 인코딩과 디코딩이 수행된다.

historyData 는 URL을 사용하는 것 보다 쉽게 에이잭스 위치 변화에 따른 복잡한 상태들을 저장할 수 있게 해준다. historyData는 숫자, 문자열, 객체와 같은 자바스크립트 타입으로 사용할 수 있는 값이다. 이를 사용하는 예로는 사용자가 DHTML 텍스트 에디터에서 다른 페이지로 이동하는 경우에 에디터의 내용을 모두 저장하는 것이다. 사용자가 뒤로 이동 버튼을 클릭해서 다시 DHTML 페이지로 돌아오면 브라우저는 히스토리 변경 리스너에게 객체를 돌려주게 된다.

개발자는 중첩된 객체나 복잡한 상태를 표현하는 배열과 같은 자바스크립트 객체 전체를 historyData에 사용할 수 있다. 히스토리 데이터에는 간단한 데이터 타입이나 NULL 타입 뿐만 아니라 JSON(자바스크립트 객체 표기법)으 로 표현할 수 있는 무엇이든 될 수 있다. 그러나, DOM 객체에 대한 참조나 XMLHttpRequest와 같은 스크립트 가능한 브라우저 객체는 저장되지 않는다. historyData는 북마크와 함께 보존되는 데이터가 아니며, 브라우저를 종료하거나, 브라우저 캐시를 제거하거나, 사용자가 히스토리를 정리하면 사라지는 데이터이다.

dhtmlHistory를 사용하는 마지막 단계는 isFirstLoad() 메서드이다. 어떤 브라우저에서는 웹 페이지를 항해할 때 다른 페이지로 이동했다가 뒤로 이동 버튼을 눌러서 처음 사이트로 돌아오면 첫번째 페이지가 완전히 재로딩되고 onload 이벤트가 발생한다. 페이지를 반복적으로 재로딩하는 경우가 아니라 처음 로드될 때만 특별한 방법으로 초기화하길 원하는 코드를 망쳐버릴 수 있다. isFirstLoad() 메서드는 웹 페이지를 처음 로드한 경우와 사용자가 브라우저 히스토리에 저장된 웹 페이지에서 뒤로 이동한 경우를 구별해준다.

예제 코드에서는 페이지가 처음 로드되었을 때 히스토리 이벤트를 추가하길 원한다. 페이지가 로드된 다음에 사용자가 페이지로 돌아가기 위해 뒤로 이동 버튼을 누른 경우에는 히스토리 이벤트를 추가하지 않는다.

window.onload = initialize;
     
function initialize() {
   // initialize the DHTML History
   // framework
   dhtmlHistory.initialize();
   
   // subscribe to DHTML history change
   // events
   dhtmlHistory.addListener(historyChange);
         
   // if this is the first time we have
   // loaded the page...
   if (dhtmlHistory.isFirstLoad()) {
      debug("Adding values to browser "
               + "history", false);
      // start adding history
      dhtmlHistory.add("helloworld",
                               "Hello World Data");
      dhtmlHistory.add("foobar", 33);
      dhtmlHistory.add("boobah", true);
         
      var complexObject = new Object();
      complexObject.value1 =
                           "This is the first value";
      complexObject.value2 =
                           "This is the second data";
      complexObject.value3 = new Array();
      complexObject.value3[0] = "array 1";
      complexObject.value3[1] = "array 2";
         
      dhtmlHistory.add("complexObject",
                               complexObject);

이제 historyStorage 클래스를 살펴보자. dhtmlHistory, historyStorage와 마찬가지로 historyStorage라는 전역 객체 하나를 통해서 모든 기능을 제공한다. 이 객체는 해시 테이블을 시뮬레이션 하기 위해 put(keyName, keyValue0, get(keyName), hasKey(keyName)과 같은 메서드를 제공한다. 키 이름은 반드시 문자열이어야하며, 키 값은 XML로 된 문자열이나 자바스크립트 객체와 같이 복잡한 것도 사용할 수 있다. 예제에서는 페이지가 처음 로드될 때 historyStorage안에 간단한 XML을 저장하기 위해 put()을 사용하고 있다.

window.onload = initialize;
     
function initialize() {
   // initialize the DHTML History
   // framework
   dhtmlHistory.initialize();
   
   // subscribe to DHTML history change
   // events
   dhtmlHistory.addListener(historyChange);
         
   // if this is the first time we have
   // loaded the page...
   if (dhtmlHistory.isFirstLoad()) {
      debug("Adding values to browser "
               + "history", false);
      // start adding history
      dhtmlHistory.add("helloworld",
                               "Hello World Data");
      dhtmlHistory.add("foobar", 33);
      dhtmlHistory.add("boobah", true);
         
      var complexObject = new Object();
      complexObject.value1 =
                           "This is the first value";
      complexObject.value2 =
                           "This is the second data";
      complexObject.value3 = new Array();
      complexObject.value3[0] = "array 1";
      complexObject.value3[1] = "array 2";
         
      dhtmlHistory.add("complexObject",
                               complexObject);
                              
      // cache some values in the history
      // storage
      debug("Storing key 'fakeXML' into "
               + "history storage", false);
      var fakeXML =
         '<?xml version="1.0" '
         +         'encoding="ISO-8859-1"?>'
         +         '<foobar>'
         +             '<foo-entry/>'
         +         '</foobar>';
      historyStorage.put("fakeXML", fakeXML);
   }

다음으로, 사용자가 다른 페이지로 이동한 다음에 뒤로 이동 버튼을 통해 돌아온 경우에 get() 메서드를 사용해서 저장된 값을 가져올 수 있고, hasKey()를 사용해서 키가 있는지 확인할 수 있다.

window.onload = initialize;
     
function initialize() {
   // initialize the DHTML History
   // framework
   dhtmlHistory.initialize();
   
   // subscribe to DHTML history change
   // events
   dhtmlHistory.addListener(historyChange);
         
   // if this is the first time we have
   // loaded the page...
   if (dhtmlHistory.isFirstLoad()) {
      debug("Adding values to browser "
               + "history", false);
      // start adding history
      dhtmlHistory.add("helloworld",
                               "Hello World Data");
      dhtmlHistory.add("foobar", 33);
      dhtmlHistory.add("boobah", true);
         
      var complexObject = new Object();
      complexObject.value1 =
                           "This is the first value";
      complexObject.value2 =
                           "This is the second data";
      complexObject.value3 = new Array();
      complexObject.value3[0] = "array 1";
      complexObject.value3[1] = "array 2";
         
      dhtmlHistory.add("complexObject",
                               complexObject);
                              
      // cache some values in the history
      // storage
      debug("Storing key 'fakeXML' into "
               + "history storage", false);
      var fakeXML =
         '<?xml version="1.0" '
         +         'encoding="ISO-8859-1"?>'
         +         '<foobar>'
         +             '<foo-entry/>'
         +         '</foobar>';
      historyStorage.put("fakeXML", fakeXML);
   }
   
   // retrieve our values from the history
   // storage
   var savedXML =
                     historyStorage.get("fakeXML");
   savedXML = prettyPrintXml(savedXML);
   var hasKey =
                historyStorage.hasKey("fakeXML");
   var message =
      "historyStorage.hasKey('fakeXML')="
      + hasKey + "<br>"
      + "historyStorage.get('fakeXML')=<br>"
      + savedXML;
   debug(message, false);
}

preetyPrintXml()은 전체 예제에 포함된 유틸리티 메서드로 디버깅을 위해 웹 페이지에 XML을 출력한다.

데 이터는 오직 현재 페이지의 히스토리에서만 유지된다는 점에 주의해야 한다. 즉, 브라우저를 종료하거나 사용자가 새로운 창을 열고 에이잭스 응용프로그램의 주소를 다시 입력하는 경우에 히스토리 데이터는 이용할 수 없다. 히스토리 데이터는 오직 뒤로, 앞으로 이동 버튼에 한해서만 유지된다. 사용자가 브라우저를 종료하거나 캐시를 정리하면 사라진다. 실제로, 오랜시간 유지할 수 있는 방법을 원한다면 에이잭스 대용량 저장 시스템(AMAXX, Ajax Massive Storage System)을 보기 바란다.

예제는 이것으로 끝났으며, 데모를 체험해보거나 전체 소스 코드를 다운로드하기 바란다.

예제2: 오라일리 메일

두 번째 예제는 Gmail과 유사한 오라일리 메일이라는 가짜 AJAX 이메일 응용프로그램이다. 오라일리 메일을 통해 dhtmlHistory 클래스를 사용해서 브라우저 히스토리를 제어하는 방법, historyStorage 객체를 사용해서 히스토리 데이터를 캐시하는 방법에 대해 설명할 것이다.

오라일리 메일 사용자 인터페이스는 두 부분으로 구성되어 있다. 페이지의 왼쪽 사이즈는 받은 편지(Inbox), 임시 보관(Draft) 같은 다양한 이메일 폴더와 옵션으로 구성된 메뉴다. 사용자가 받은 편지 같은 메뉴를 선택하면 페이지의 오른쪽에 내용을 업데이트한다. 실제 응용프로그램에서는 선택된 메일박스의 내용을 가져와서 표시해야하지만 오라일리 메일에서는 선택한 옵션만 간단하게 보여준다.

오라일리 메일은 브라우저 히스토리에 메뉴 변경사항을 추가하고, 위치 바를 업데이트하는데 RSH 프레임워크를 사용하기 때문에 사용자가 응용프로그램을 북마크하고 브라우저의 뒤로, 앞으로 이동 버튼을 사용해서 메뉴 변경 이전으로 이동할 수 있다.

historyStorage 사용법을 설명하기 위해 Address Book(주소록)이라는 메뉴를 추가했다. 주소록은 이름과 이메일 주소를 자바스크립트 배열로 저장하고 있지만 실제 응용프로그램이라면 원격 서버에서 배열 내용을 가져와야 할 것이다. 그러나, 오라일리 메일에서는 배열을 직접 생성하고, 이름과 이메일 주소를 몇 개 추가한 다음에 historyStorage 객체에 저장한다. 사용자가 웹 페이지를 떠난후에 돌아오면 오라일리 메일 응용프로그램은 원격 서버에서 접속하는 대신 캐시에서 주소록을 가져온다.

주소록은 initialize() 메서드에서 저장하고 가져올 수 있다.

/** 페이지가 로딩을 끝낸 후에 초기화를 수행하는 함수 */
function initialize() {
    // DHTML 히스토리 프레임워크를 초기화한다
    dhtmlHistory.initialize();
   
    // DHTML 히스토리 리스너에 등록한다
    dhtmlHistory.addListener(handleHistoryChange);

    // 주소록을 가져올 수 없으면 직접 추가한 주소록을
    // 히스토리 저장소에서 캐싱한다.
   if (window.addressBook == undefined) {
         // 주소록을 전역 객체로 저장한다
       // 실제 응용프로그램에서는 백그라운드에서 서버로부터
       // 주소록을 가져와야한다
         window.addressBook =
             ["Brad Neuberg 'bkn3@columbia.edu'",
               "John Doe 'johndoe@example.com'",
               "Deanna Neuberg 'mom@mom.com'"];
               
         // 주소록이 있으면 이를 캐시에 보관한다
       // 사용자가 페이지를 떠난 후에 뒤로 이동으로 돌아온 경우에도 사용한다
       historyStorage.put("addressBook",
                                     addressBook);
    }
    else {
         // 히스토리 저장소에서 캐시된 주소록을 가져온다
         window.addressBook =
                      historyStorage.get("addressBook");
    }

히 스토리 변경을 다루는 코드는 이해하기 쉽다. 아래 코드에서처럼 사용자가 뒤로 또는 앞으로 이동 버튼을 클릭할 때 handleHistoryChange가 호출된다. 그러면 newLocation을 갖게 된다. 이를 이용해서 사용자 인터페이스를 올바른 상태로 업데이트할 수 있다.

/** 히스토리 변경 이벤트를 처리한다 */
function handleHistoryChange(newLocation,
                                           historyData) {
    // 위치가 없으면 수신함의 기본 위치를 보여준다
    if (newLocation == "") {
         newLocation = "section:inbox";
    }
   
    // 위치 변화가 있으면 표시할 섹션을 추출한다.
    // newLocation은 "section:"으로 시작한다
    newLocation =
             newLocation.replace(/section\:/, "");
   
    // DHTML 히스토리 변경에 따라 브라우저를 업데이트한다
    displayLocation(newLocation, historyData);
}

/** 오른쪽 컨텐트 영역에 주어진 위치를 표시한다*/
function displayLocation(newLocation,
                                     sectionData) {
    // 선택한 메뉴 항목을 가져온다
    var selectedElement =
                  document.getElementById(newLocation);
                 
    // 이전에 선택된 메뉴 항목을 제거한다
    var menu = document.getElementById("menu");
    for (var i = 0; i < menu.childNodes.length;
                                                               i++) {
         var currentElement = menu.childNodes[i];
         // DOM 요소 노드인지 확인한다
         if (currentElement.nodeType == 1) {
             //모든 클래스 이름을 제거한다
             currentElement.className = "";
         }                                                         
    }
   
    // UI에서 다르게 나타나는 새로 선택된 메뉴 항목
    selectedElement.className = "selected";
   
    // 화면 오른쪽에 새로운 섹션을 표시한다.
    // sectionData에 따라 섹션을 결정한다

    // 앞서 캐시된 로컬 주소 데이터를 사용해서 주소록을 보여준다
    if (newLocation == "addressbook") {
         // 주소록을 보여준다
         sectionData = "<p>Your addressbook:</p>";
         sectionData += "<ul>";
         
         // 주소록이 아직 없다면 캐시에서 주소록을 가져온다
         if (window.addressBook == undefined) {
             window.addressBook =
                      historyStorage.get("addressBook");
         }
         
         // 주소록을 표시한다
         for (var i = 0;
                      i < window.addressBook.length;
                               i++) {
             sectionData += "<li>"
                                    + window.addressBook[i]
                                    + "</li>";                          
         }
         
         sectionData += "</ul>";
    }
   
    // sectionData가 없다면 원격으로 가져온다. 이 예제에서는 주소록을 제외한
    // 모든 데이터는 가짜를 이용하고 있다
    if (sectionData == null) {
         // 실제 응용프로그램에서는 섹션의 내용을 원격으로 가져와야한다
         sectionData = "<p>This is section: "
             + selectedElement.innerHTML + "</p>";  
    }
   
    // 제목과 내용을 업데이트한다
    var contentTitle =
             document.getElementById("content-title");
    var contentValue =
             document.getElementById("content-value");
    contentTitle.innerHTML =
                                    selectedElement.innerHTML;
    contentValue.innerHTML = sectionData;
}


오라일리 메일 데모를 체험하거나 소스 코드를 다운로드할 수 있다.

결론

RSH(Really Simple History) API를 사용해서 에이잭스 응용프로그램에서 즐겨찾기와 뒤로, 앞으로 이동 버튼을 사용하기 위한 방법을 보았으며 직접 에이잭스 응용프로그램을 작성하는데 발판이 될 수 있는 예제 코드들을 살펴보았다. 나는 즐겨찾기와 히스토리를 완전히 지원하는 여러분의 에이잭스 발명품들을 볼 수 있기를 기대한다.

감사의 글

이 글을 검토해준 모든 사람과 RSH 프레임워크를 제작한 모두에게 감사드린다: Michael Eakes, Jeremy Sevareid, David Barrett, Brendon Wilson, Dylan Parker, Erik Arvidsson, Alex Russell, Adam Fisk, Alex Lynch, Joseph Hoang Do, Richard MacManus, Garret Wilson, Ray Baxter, Chris Messina, and David Weekly.

참고자료
  • 이 기사의 모든 소스코드 다운로드
  • RSH 프레임워크 다운로드
  • 오라일리 메일 데모와 오라일리 메일 소스 코드 다운로드. 전체 예제 다운로드에는 시험할 수 있는 보다 많은 예제들이 있다
  • Coding in Paradise(코딩천국): AJAX, DHTML, 자바 기술, 위키위키와 같은 협업 기술 등을 다루는 저자의 웹로그
  • "Coding in Paradise: AJAX: Bookmarks and Back Buttons, Advanced Example"
  • "Coding in Paradise: Safari: No DHTML History Possible"
  • "Coding in Paradise: AJAX Tutorial: Saving Session Across Page Loads Without Cookies, On The Client Side"
  • "Coding in Paradise: AJAX History Libraries"
Bard Neuberg는 모질라, JXTA, 자카르타 피드 파서 등에 코드를 공헌하고 있으며, 오픈소스 커뮤니티에서 폭넓은 공헌을 하고 있다.


출처 :
http://network.hanbitbook.co.kr/



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

Ajax Framework 분석  (0) 2009.05.04
CSSHttpRequest  (0) 2008.11.12
HTTP Header에 대하여  (0) 2008.11.08
100라인 Ajax Wrapper  (0) 2008.04.19
어떤 AJAX Framework를 선택할 것인가.  (0) 2008.03.14
Post by 넥스트리소프트 데꾸벅(techbug)
, |

요즘 구글크롬으로 이제껏 작업했던 사이트의 버그 잡는 쏠쏠한(ㅠ.,ㅠ)재미에 푹 빠졌다.
google chrome의 경우 webkit엔진을 사용하므로 safari 와 비슷하게 작동해서 불행히도 css버그도 같이 공유하고 잇따.

Safari , google chrome, FF2 의 경우 Fieldset 버그가 존재한다.
이럴경우에는 다음과 같이 처리하면 된다.

fieldset:after {content: “.”; display: block; height: 0; clear: both; } 

위의 내용중 :after는 CSS2 Spec에 나온것이므로 기술하지 않은 곳에서는 다음과 같이 작업한다.
fieldset {display: block; height: 0; clear: both; }


<=== height:0, clear:both 가 중요하다.. ㅡ.,ㅡ;


사족을 붙이자면 실제 작업을 하다가 보면 DTD버전이 4.01 이냐 xhtml1.0 이냐에 따라 이놈의 fieldset은 유난히 많이 틀리다는것을 알수 있다.

html4.01일 경우에는 <fieldset>밑에  첫번째 자식노드로 <legend>가 반드시 필요하다
html4.01에서 "반드시" 라는 것이 존재하는것이 이놈 뿐이다... 대부분 W3C 권고안이기 때문에 생략이 가능하나 이놈만은 생략하면 validtion부분에서 빨간색으로 표현된다... ㅡ.,ㅡ;

그러나 xhtml1.0에서는 생략이 가능하다....


Post by 넥스트리소프트 데꾸벅(techbug)
, |
브라우저 춘추전국시대 다시 시작하나....

오늘 구글크롬이 다운로드 서비스를 시작했다.
설치후 구글 크롬 이놈은 다른 브라우저의 종합판인듯하다.

Opera,Firefox, Safari 모두다 섞어 놓은것 같은데.. ㅡ.,ㅡ;  상상력이... 쿨럭!!.



각 브라우저의 값들을 비교해보고자
alert(navigator.userAgent+"\n=>"+parseFloat(navigator.appVersion));로 찍어봤다.
구글크롬 0.2
Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/525.13 (KHTML, like Gecko) Chrome/0.2.149.27 Safari/525.13:
=>Netscape

사파리  3.1.2
Mozilla/5.0 (Windows; U; Windows NT 6.0; ko-KR) AppleWebKit/525.19 (KHTML, like Gecko) Version/3.1.2 Safari/525.21:
=>Netscape

Firefox 3
Mozilla/5.0 (Windows; U; Windows NT 6.0; ko; rv:1.9.0.1) Gecko/2008070208 Firefox/3.0.1:
=>5

IE7
Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1) ; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; .NET CLR 3.0.04506):
=>4

Opera 9.52
Opera/9.52 (Windows NT 6.0; U; ko):
=>Opera
헉.. 이놈 대단한 놈이다.. safari의 AppleWebkit으로도 유효성검증을 하기가.. ㅠ.,ㅠ;
결국은 다음과 같이 버전체크 부분을 몽땅 바꿔버렸다.

/**
 * @fileoverview 브라우저비교 및 JS상속, 클래스 생성관련 스크립트 모음
 * @author 데꾸벅
 * @version 0.1
 * @since 2003.05.08, 2008.08.27 IE6 판별 버그 수정, 2008.09.03 Google Chrome 판별 추가
 */


 var sUserAgent = navigator.userAgent;
var fAppVersion = parseFloat(navigator.appVersion);

/**
 * 브라우저 버전 비교
 */
function compareVersions(sVersion1, sVersion2) {
    var aVersion1 = sVersion1.split(".");
    var aVersion2 = sVersion2.split(".");

    if (aVersion1.length > aVersion2.length) {
        for (var i=0; i < aVersion1.length - aVersion2.length; i++) {
            aVersion2.push("0");
        }
    } else if (aVersion1.length < aVersion2.length) {
        for (var i=0; i < aVersion2.length - aVersion1.length; i++) {
            aVersion1.push("0");
        }
    }
    for (var i=0; i < aVersion1.length; i++) {
        if (aVersion1[i] < aVersion2[i]) {
            return -1;
        } else if (aVersion1[i] > aVersion2[i]) {
            return 1;
        }
    }
    return 0;
}



//Opera
var isOpera = sUserAgent.indexOf("Opera") > -1;
var isOpera7 = isOpera8 = isOpera9 =isOpera10 = false;
if (isOpera) {
    if (/Opera[\/\s](\d+\.\d+)/.test(navigator.userAgent)){
     var oprversion=new Number(RegExp.$1);
     if (oprversion>=10) isOpera10 = true;
     else if (oprversion>=9) isOpera9 = true;
     else if (oprversion>=8) isOpera8 = true;
     else if (oprversion>=7) isOpera7 = true;
    }
}




//KHTML, Konqueror
var isKHTML = sUserAgent.indexOf("KHTML") > -1 || sUserAgent.indexOf("Konqueror") > -1  || sUserAgent.indexOf("AppleWebKit") > -1;

var isSafari1 = isSafari1_2 = false;
var isKonq2_2 = isKonq3 = isKonq3_1 = isKonq3_2 = false;
var isSafari = false;
if (isKHTML) {
    isSafari = sUserAgent.indexOf("AppleWebKit") > -1;
    isKonq = sUserAgent.indexOf("Konqueror") > -1;

    if (isSafari) {
        var reAppleWebKit = new RegExp("AppleWebKit\\/(\\d+(?:\\.\\d*)?)");
        reAppleWebKit.test(sUserAgent);
        var fAppleWebKitVersion = parseFloat(RegExp["$1"]);
        isSafari1 = fAppleWebKitVersion >= 85;
        isSafari1_2 = fAppleWebKitVersion >= 124;
    } else if (isKonq) {
        var reKonq = new RegExp("Konqueror\\/(\\d+(?:\\.\\d+(?:\\.\\d)?)?)");
        reKonq.test(sUserAgent);
        isKonq2_2 = compareVersions(RegExp["$1"], "2.2") >= 0;
        isKonq3 = compareVersions(RegExp["$1"], "3.0") >= 0;
        isKonq3_1 = compareVersions(RegExp["$1"], "3.1") >= 0;
        isKonq3_2 = compareVersions(RegExp["$1"], "3.2") >= 0;
    }
}


// Internet Explorer
var isIE = sUserAgent.indexOf("compatible") > -1 && sUserAgent.indexOf("MSIE") > -1 && !isOpera;
var isIE4 = isIE5 = isIE5_5 = isIE6 = isIE7 = isIE8 = false;
if (isIE) {
    var reIE = new RegExp("MSIE (\\d+\\.\\d+);");
    reIE.test(sUserAgent);
    var fIEVersion = parseFloat(RegExp["$1"]);
    isIE4 = fIEVersion >= 4  && fIEVersion < 5;
    isIE5 = fIEVersion >= 5  && fIEVersion < 5.5;
    isIE5_5 = fIEVersion >= 5.5  && fIEVersion < 6.0;
    isIE6 = fIEVersion >= 6.0 && fIEVersion < 7.0;
    isIE7 = fIEVersion >= 7.0 && fIEVersion < 8.0;
    isIE8 = fIEVersion >= 8.0 ;
}


// Mozilla 여부
var isMoz = sUserAgent.indexOf("Gecko") > -1 && !isKHTML;
var isMoz1 = sMoz1_4 = isMoz1_5 = false;

if (isMoz) {
    var reMoz = new RegExp("rv:(\\d+\\.\\d+(?:\\.\\d+)?)");
    reMoz.test(sUserAgent);
    isMoz1 = compareVersions(RegExp["$1"], "1.0") >= 0;
    isMoz1_4 = compareVersions(RegExp["$1"], "1.4") >= 0;
    isMoz1_5 = compareVersions(RegExp["$1"], "1.5") >= 0;
}

var isNS4 = !isIE && !isOpera && !isMoz && !isKHTML && (sUserAgent.indexOf("Mozilla") == 0) && (navigator.appName == "Netscape") && (fAppVersion >= 4.0 && fAppVersion < 5.0);
var isNS4 = isNS4_5 = isNS4_7 = isNS4_8 = false;

if (isNS4) {
    isNS4 = true;
    isNS4_5 = fAppVersion >= 4.5;
    isNS4_7 = fAppVersion >= 4.7;
    isNS4_8 = fAppVersion >= 4.8;
}


var isFF = !isIE && !isOpera && isMoz && !isKHTML && (sUserAgent.indexOf("Mozilla") == 0) && (navigator.appName == "Netscape");
var isFF1 = isFF2 = isFF3 = false;
if(isFF){
    if (/Firefox[\/\s](\d+\.\d+)/.test(navigator.userAgent)){
     var ffversion=new Number(RegExp.$1);
     if (ffversion>=3)
          isFF3 = true;
     else if (ffversion>=2)
         isFF2 = true;
     else if (ffversion>=1)
          isFF1 = true;
    }
}


//구글 크롬 버전체크 추가 2008.09.03
var isChrome = !isIE && !isFF && !isOpera && !isMoz && !isKonq && isSafari && isKHTML && (sUserAgent.indexOf("Mozilla") == 0) && (sUserAgent.indexOf("Chrome") != -1) && (navigator.appName == "Netscape");
var isChrome02 = false;

if(isChrome){
    if (/Chrome[\/\s](\d+\.\d+)/.test(navigator.userAgent)){
        var ffversion=new Number(RegExp.$1);
        if(parseFloat(ffversion) >= parseFloat('0.2'))
            isChrome02 = true;
    }
}


/**
 * XP인지 아닌지 판별함수
 * @return {boolean} true/false
 */
function isXP(){
    var agent = window.navigator.userAgent;
    if(agent.indexOf("MSIE")!= -1 && agent.indexOf("5.1") !=-1)
        return true;     //SP1
    else
        return false;
}

/**
 * XP의 ServicePack2인지 처리함수
 * @return {boolean} true/false
 */
function isXPSP2(){
    var tmp_MSIE = window.navigator.userAgent.indexOf("MSIE");
    if(tmp_MSIE && window.navigator.userAgent.indexOf("SV1") > tmp_MSIE){
        return true;     //SP2
    }else{
        return false;
    }
}

사용자 삽입 이미지


구글크롬에서는 태터툴즈의 웹에디팅기능이 되지 않아 지금 포스팅은 FF3에서 작성하고 있다. ㅡ.,ㅡa


Acid3 Test 결과화면 : 테스트사이트 (http://acid3.acidtests.org/)
사용자 삽입 이미지
Opera9, Firefox3, IE7,
Safari, google Chrome, IE8
순서로 테스트 (Safari는 네트웍때문에 연결되지 않았으며, google Chrome의 경우 78/100 이 나왔습니다. 사파리하고 비슷한 수준이네요~~



근데... 이건 뭥미???
사용자 삽입 이미지



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

오늘자 ajaxian에 올라온 포스트 중에 jQuery Tip으로 링크에 걸린 파일사이즈를 자동으로 알아낸뒤 링크뒤에 출력해주는 포스팅을 번역해서 올려본다.
이미 올려져 있는 소스의 파일사이즈를 알아내 오는것으로 파일업로드시 파일사이즈 체크는 달리 해야 한다.


jQuery(function($){
        $('a[href$=".pdf"], a[href$=".doc"], a[href$=".mp3"], a[href$=".m4u"]').each(function(){
                // looking at the href of the link, if it contains .pdf or .doc or .mp3
                var link = $(this);
                var bits = this.href.split('.');
                var type = bits[bits.length -1];
               
               
                var url= "http://json-head.appspot.com/?url="+encodeURI($(this).attr('href'))+"&callback=?";
       
                // then call the json thing and insert the size back into the link text
                 $.getJSON(url, function(json){
                        if(json.ok && json.headers['Content-Length']) {
                                var length = parseInt(json.headers['Content-Length'], 10);
                               
                                // divide the length into its largest unit
                                var units = [
                                        [1024 * 1024 * 1024, 'GB'],
                                        [1024 * 1024, 'MB'],
                                        [1024, 'KB'],
                                        [1, 'bytes']
                                ];
                               
                                for(var i = 0; i <units.length; i++){
                                       
                                        var unitSize = units[i][0];
                                        var unitText = units[i][1];
                                       
                                        if (length>= unitSize) {
                                                length = length / unitSize;
                                                // 1 decimal place
                                                length = Math.ceil(length * 10) / 10;
                                                var lengthUnits = unitText;
                                                break;
                                        }
                                }
                               
                                // insert the text directly after the link and add a class to the link
                                link.after(' (' + type + ' ' + length + ' ' + lengthUnits + ')');
                                link.addClass(type);
                        }
                });
        });
});
 


소스에서 굵게 표시된 json.headers 를 이용해서 컨텐츠의 사이즈를 알아온뒤 link.after메쏘드로 화면에 출력해 주었다...
너무도 간단하게.. ㅡ.,ㅡ; 



샘플사이트 : http://natbat.net/code/clientside/js/addSizes/
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
   "http://www.w3.org/TR/html4/strict.dtd">

<html lang="en">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>addSizes</title>
    <!-- Date: 2008-07-29 -->
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js" type="text/javascript"></script>
    <script src="addSizes.js" type="text/javascript"></script>
</head>
<body>
    <h1>addSizes</h1>
    <p>This is a link to a remote <a href="http://clearleft.com/worksheet/client-worksheet.doc">doc</a> file.</p>
    <p>This is a link to a remote <a href="http://www.onyx.com/pdf/CustomerMgmtBrochure.pdf">pdf</a> file.</p>
    <p>This is a link to a remote <a href="http://media.giantbomb.com/podcast/giantbombcast-071708.mp3">mp3</a> file.</p>
   
    <p>This is a link to a local <a href="media/test.doc">doc</a> file.</p>
    <p>This is a link to a remote <a href="media/test.pdf">pdf</a> file.</p>
    <p>This is a link to a remote <a href="media/test.mp3">mp3</a> file.</p>
</body>
</html>


[ 다른 방법 : jQuery와 같이 3-party library를 사용하지 않고 단순 xhr을 이용한 방법 ]
function filesize (url) {
    var req = window.ActiveXObject ? new ActiveXObject("Microsoft.XMLHTTP") : new XMLHttpRequest();
    if (!req) throw new Error('XMLHttpRequest not supported');
    
    req.open ('HEAD', url, false);
    req.send (null);
    
    if (!req.getResponseHeader) {
        try {
            throw new Error('No getResponseHeader!');
        } catch(e){
            return false;
        }
    } else if (!req.getResponseHeader('Content-Length')) {
        try {
            throw new Error('No Content-Length!');
        } catch(e){
            return false;
        }
    } else {
        return req.getResponseHeader('Content-Length'); 
    }
}


사용법 : filesize('파일주소');

테스트샘플
<html>
<head><title>테스트</title></head>
<body>
<script type="text/javascript">
function filesize (url) {
    var req = window.ActiveXObject ? new ActiveXObject("Microsoft.XMLHTTP") : new XMLHttpRequest();
    if (!req) throw new Error('XMLHttpRequest not supported');

    req.open ('HEAD', url, false);
    req.send (null);

alert("전체 헤더======================\n\n"+req.getAllResponseHeaders());

try{
if(!req.getResponseHeader('Content-Length')) alert(req.getResponseHeader('Content-Length') + 'bytes');
}catch(e){
alert("에러");
}
}


</script>
<button onclick="filesize('https://t1.daumcdn.net/cfile/tistory/190E4E1249F6B2D7E2');" >이미지 파일사이즈</button><br />
<button onclick="filesize('http://techbug.tistory.com/122');" >웹페이지 파일사이즈(Entity header가 없는경우)</button><br />
<button onclick="filesize('http://www.webmasterworld.com/forum91/1920.htm');" >웹페이지 파일사이즈(Entity header가 있는경우)</button><br />
</body>
</html>

이경우 맨위의 버튼은 이미지 파일사이즈를 가져오는 것이라 content-Length가 표시되지만 아래의 경우 text/html의 content-length가 되지 않아 사이즈를 정할수 없다.
보통 HTTP header의 경우 (특히 Entity-Header)의 경우는 request를 보내는 브라우저의 종류에 따라 보내주는 정보가 틀려서 content-length를 구하는 방법이 어렵다.
위에서 보는 바와 같이 똑같이 웹페이지 파일사이즈를 정하는데 text/html일 경우 Fiddler나 다른 HTTP Header정보를 볼수 있는 프로그램으로 보면 서로 달리 나오는것을 확인할수 있다.




파일업로드시 용량을 체크하려면 File System Object 를 사용해야 한다. 
스크립트 보안 메세지가 뜨는 단점이 있다.
<html>
<head>
<script language="JavaScript">
function A(){
    var oas = new ActiveXObject("Scripting.FileSystemObject");
    var d = document.a.b.value;
    var e = oas.getFile(d);
    var f = e.size;
    alert(f + " bytes");
}
</script>
</head>
<body>
<form name="a">
<input type="file" name="b">
<input type="button" name="c" value="SIZE" onClick="A();">
</form>
</body>
</html>










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

jQuery Grid Plugin : jqGrid  (16) 2009.04.06
ext의 border-layout과 같은 jQuery UI.Layout Plugin  (0) 2009.01.14
jQuery pageSlide  (0) 2009.01.12
jQuery Loading바 구현하기  (2) 2008.07.08
Post by 넥스트리소프트 데꾸벅(techbug)
, |








소스보기를 막는 코드는 여러가지가 있습니다.

하지만 소스보기를 막는 코드가 있다고 하더라도 조금만 관심을 가지면 소스는 100%볼 수가 있습니다. 그 어떤 HTML이던 소스보기는 100%차단할 수 없으며(100% 볼수 있음) 소스보기를 번거럽게 할 뿐(소스보기를 까다롭게)입니다.

인터넷의 특성상 소스는 100%오픈되어 있습니다.

네이버카페 역시 모든 소스를 볼수가 있습니다.

아래문서는 소스보기를 막는 코드들로써 어느정도 소스보기를 번거럽게 할 수 있지만 100%차단을 할 수 는 없습니다.

 

 

1. 마우스 오른쪽메뉴, 드래그, 선택복사 금지하기

<body oncontextmenu='return false' ondragstart='return false' onselectstart='return false'>

oncontextmenu='return false' : 마우스 오른쪽 메뉴 금지
ondragstart=return false : 드래그 금지
onselectstart='return false' : 선택복사 금지

참고 onkeydown="return false" 키보드 완전 금지


 

2. 마우스 오른쪽 버튼 클릭시 경고 메세지
<script language=JavaScript>function click() {if ((event.button==2) || (event.button==2)) {alert('죄송합니다. 오른쪽 마우스 금지입니다. - 태그인넷 ');}}document.onmousedown=click// --></script>

 

 

3. 프레임 소스보기 막기

<script language="JavaScript">
if(parent.frames.length <= 0) { top.location.href="http://tagin.net"; }
</script>

프레임을 쓰는 홈페이지에서 프레임 페이지가 아닌 하위 프레임으로 직접 들어갔을 때 http://tagin.net으로 이동하는 예제입니다
head에 넣어주세요

 

4. 새로고침(F5), 전체창(F11) 막기

<SCRIPT LANGUAGE="JavaScript">
<!-- www.tagin.net
function processKey()
{
        if( (event.ctrlKey == true && (event.keyCode == 78 || event.keyCode == 82)) ||
        (event.keyCode >= 112 && event.keyCode <= 123) || event.keyCode == 8)
            {
        event.keyCode = 0;
        event.cancelBubble = true;
        event.returnValue = false;
            }
}
document.onkeydown = processKey;
-->
</script>

 

 

5. shift, ctrl (쉬프트, 컨트롤)키 클릭하면 경고메세지 띄우기

<script language="JavaScript">
<!-- www.tagin.net
function click() {
     if((event.ctrlKey) || (event.shiftKey)) {
       alert('키를 사용할 수 없습니다.');
     }
   }
document.onmousedown=click;
document.onkeydown=click;
-->
</script>

 
6. 동영상 마우스 오른쪽 버튼 막기

<embed src="http://tagin.net/js/1.wmv" EnableContextMenu="false" >

<object classid='clsid:22D6F312-B0F6-11D0-94AB-0080C74C7E95' id='MediaPlayer1' width="580" height="387">
  <param name='AudioStream' value='-1'>
  <param name='AutoSize' value='false'>
  <param name='AutoStart' value='true'>
  <param name='AnimationAtStart' value='true'>
  <param name='AllowChangeDisplaySize' value='true'>
  <param name='BufferingTime' value='5'>
  <param name='DisplayBackColor' value='0'>
  <param name='DisplayForeColor' value='16777215'>
  <param name='Enabled' value='true'>
 
 <param name='EnableContextMenu' value='false'>
  <param name='EnableTracker' value='true'>
  <param name='Mute' value='false'>
  <param name='PlayCount' value='1'>
  <param name='Rate' value='1'>
  <param name='ShowCaptioning' value='1'>
  <param name='ShowControls' value='true'>
  <param name='ShowAudioControls' value='true'>
  <param name='ShowDisplay' value='false'>
  <param name='ShowGotoBar' value='false'>
  <param name='ShowPositionControls' value='true'>
  <param name='ShowStatusBar' value='false'>
  <param name='ShowTracker' value='true'>
  <param name='TransparentAtStart' value='false'>
  <param name='Volume' value='-110'>
  <param name="FileName" value="http://tagin.net/js/1.wmv">
  <param NAME="SAMIFileName" VALUE="자막주소">
</object>

동영상 태그(embed, object) 자세히 보기
 
7. 상태바의 링크 주소 감추기

<script language=JavaScript>
setInterval("x()",1);
function x(){window.status="태그인넷"}
</script>
 <A href="http://tagin.net">태그인넷</a>

다른 소스

<a href="http://tagin.net" onmouseover="self.status='태그인넷';return true" onmouseout="self.status=' 태그인넷';return true">링크 </a>

<head>
<script language="JavaScript">
<!--

function hidestatus()
{
window.status='태그인넷'
return true
}
if (document.layers)
document.captureEvents(Event.mouseover | Event.mouseout)
document.onmouseover=hidestatus
document.onmouseout=hidestatus

// -->
</script>
</head>

 
8. 익스플로러 6의 이미지 도구모음(저장버튼 등) 뜨는 것 막기.
<HEAD><META http-equiv="imagetoolbar" content="no"></HEAD>
 
9. 무단링크 금지 스크립트
<script language='JavaScript'>
//link1 과 link2 지정해 넣은 홈을 통해서 들어오지 않으면 무단링크 취급 기본홈페이지로 열리는 소스
var home_url="http://www.tagin.net";   // 기본 홈페이지
var link1="http://tagin.net/";
var link2="http://www.naver.com/";
if (document.referrer.indexOf(home_url)==-1 && document.referrer.indexOf(link1)==-1 && document.referrer.indexOf(link2)==-1) {
        if (document.referrer) {
           alert("무단링크 하셨습니다.!");  // 무단링크시 에러 메세지
                window.location=home_url;  // 기본 홈으로 이동
        } else {
           alert("무단링크 하셨습니다. ");  // 무단링크시 에러 메세지
        window.location=home_url;  // 기본 홈으로 이동
        }
}
</script>

 출처 : 태그인넷










'Publisher > HTML/HTML5' 카테고리의 다른 글

[HTML5] Progress Bar CSS입히기  (2) 2013.03.04
SVG와 CANVAS사이의 선택  (16) 2010.03.09
HTML5 Gallery  (4) 2009.04.10
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)
, |

보통 IE5,5와 IE6에서의 투명 PNG이미지 처리시 CSS와 스크립트로 다음과 같이 처리하는데
.png24 {
    tmp:expression(setPNG24(this));
}


/* png24 이미지 파일을 웹에서 투명하게 변경하는 스크립트 */
function setPNG24(obj) {
    obj.width=obj.height=1;
    obj.className=obj.className.replace(/\bPNG24\b/i,'');
    obj.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+ obj.src +"',sizingMethod='image');"
    obj.src='';
    return '';
}

보통 위와 같이 처리하면 onmouseover='this.src=this.src.replace(".gif","_over.gif")'와 같이 처리하는데..

이미지 토글처리를 하다가 setPNG로 filter:progid:DXImageTransform 필터가 적용되면 mouseover 이벤트로 이미지 변경이 되지 않았다.
IE7, IE6에서 필터가 적용되면  onclick, onmouseover이던지 이벤트는 모두 먹어버리고 심지어 <a>태그도 먹질 않는다. 다른 브라우저에서는 아예 filter 속성이 먹질 않아서 정상적으로 작동한다.

실제 이미지의 소스를 filter속에서 정의하기 때문에 그렇다.

이럴경우 다음과 같이 처리한다. [레퍼런스 : http://homepage.ntlworld.com/bobosola/png_mouseover.htm]
<!--[if lt IE 7]>
<script type="text/javascript">
var arVersion = navigator.appVersion.split("MSIE")
var version = parseFloat(arVersion[1])
function correctPNG() // correctly handle PNG transparency in Win IE 5.5 and 6.
{
   if ((version >= 5.5) && (document.body.filters))
   {
       for(var i=0; i<document.images.length; i++)
       {
          var img = document.images[i]
          var imgName = img.src.toUpperCase()
          if (imgName.substring(imgName.length-3, imgName.length) == "PNG")
          {
             var imgID = (img.id) ? "id='" + img.id + "' " : ""
             var imgClass = (img.className) ? "class='" + img.className + "' " : ""
             var imgTitle = (img.title) ? "title='" + img.title + "' " : "title='" + img.alt + "' "
             var imgStyle = "display:inline-block;" + img.style.cssText
             var imgAttribs = img.attributes;
             for (var j=0; j<imgAttribs.length; j++)
             {
                var imgAttrib = imgAttribs[j];
                if (imgAttrib.nodeName == "align")
                {
                   if (imgAttrib.nodeValue == "left") imgStyle = "float:left;" + imgStyle
                   if (imgAttrib.nodeValue == "right") imgStyle = "float:right;" + imgStyle
                   break
                }
             }
             var strNewHTML = "<span " + imgID + imgClass + imgTitle
             strNewHTML += " style=\"" + "width:" + img.width + "px; height:" + img.height + "px;" + imgStyle + ";"
             strNewHTML += "filter:progid:DXImageTransform.Microsoft.AlphaImageLoader"
             strNewHTML += "(src='" + img.src + "', sizingMethod='scale');\""
             strNewHTML += " onmouseover=\"PNGswap('" + img.id + "');\" onmouseout=\"PNGswap('" + img.id +"');\""
             strNewHTML += "></span>"
             img.outerHTML = strNewHTML
             i = i-1
          }
       }
   }
}
window.attachEvent("onload", correctPNG);
function PNGswap(myID)
{
   var strOver  = "_on"
   var strOff = "_off"
   var oSpan = document.getElementById(myID)
   var currentAlphaImg = oSpan.filters(0).src
   if (currentAlphaImg.indexOf(strOver) != -1)
      oSpan.filters(0).src = currentAlphaImg.replace(strOver,strOff)
   else
      oSpan.filters(0).src = currentAlphaImg.replace(strOff,strOver)
}

</script>
<![endif]-->

<script language="JavaScript" type="text/javascript">
<!--
function imgSwap(oImg)
{
   var strOver  = "_on"    // image to be used with mouse over
   var strOff = "_off"     // normal image
   var strImg = oImg.src
   if (strImg.indexOf(strOver) != -1)
      oImg.src = strImg.replace(strOver,strOff)
   else
      oImg.src = strImg.replace(strOff,strOver)
}
//-->
</script>

</head>
<body>

<div class="plainbackground">
<img id="img100" src="logo_off.png" width="100" height="100" alt="a PNG logo"
onmouseover="imgSwap(this)" onmouseout="imgSwap(this)"/>
</div>

<div class="plainbackground">
<img id="img200" src="logo2_off.png" width="100" height="100" alt="another PNG logo"
onmouseover="imgSwap(this)" onmouseout="imgSwap(this)"/>

</div>


결국 필터의 src 소스를 변경시켜야 하다는 얘기닷.. ㅡ.,ㅡ;
다들 건승하길... 저 같으면 그냥 gif 깨끗하게 쓰겠어요.. ㅠ.,ㅠ;



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

Ext2.2 Release

Scripter/EXTJS / 2008. 8. 7. 10:30

일전에 포스팅한 extjs 로드맵에서 언급했듯이 extjs 2.2 가 릴리즈 됐다.

그리고 데꾸벅의 한글화 부분(ext-2.2/build/locale/ext-lang-ko.js)도 추가적으로 패키징되어 들어가 있다. 캬햐햐
/**
 * Korean Translations By nicetip
 * 05 September 2007
 * Modify by techbug / 25 February 2008
 */
트리로더 확장과 불여우2에서 스크롤문제(overflow)와 IE6 버그(relative)일때 스크롤문제부분(스쿨학우여러분 땡큐 많이 참조했어요.. ^^)도 부분적으로 채택이 됐네요.. 크크..
FF3 Beta1에서 에러나던 버튼위치부분은... 쿨럭.. ㅡ.,ㅡ;

2.2 (2008 여름) : 릴리즈노트

  • Ext.Ajax 기능향상
  • Ext컴포넌트만의 초점을 맞춘(scoped) REST style지원
  • XML을 포함한 추가적인 TreeLoader 데이타로딩
  • 슬라이더 컴포넌트
  • 파일업로드 필드

릴리즈노트에 나타난 새롭게 추가된 기능들은 다음과 같다.

[ CheckboxGroup / RadioGroup ]

... },{
    xtype: 'checkboxgroup',
    fieldLabel: 'Multi-Column (horizontal)',
    columns: 3,
    items: [
        {boxLabel: 'Item 1', name: 'cb-horiz-1'},
        {boxLabel: 'Item 2', name: 'cb-horiz-2', checked: true},
        {boxLabel: 'Item 3', name: 'cb-horiz-3'},
        {boxLabel: 'Item 4', name: 'cb-horiz-4'},
        {boxLabel: 'Item 5', name: 'cb-horiz-5'}
    ]
},{ ...

각 개별적인 item으로만 적용했던 라디어버튼과 체크박스를 그룹핑하여 만든 컴포넌트가 추가되었다. [샘플보기]
사용자 삽입 이미지



[히스토리컴포넌트 추가] [샘플보기]
listeners: {
    'tabchange': function(tabPanel, tab){
        // Ignore tab1 since it is a separate tab panel and we're managing history for it also.
        // We'll use its handler instead in that case so we don't get duplicate nav events for sub tabs.
        if(tab.id != 'tab1'){
            Ext.History.add(tabPanel.id + tokenDelimiter + tab.id);
        }
    }
}

사용자 삽입 이미지

위의 탭기능중 sub-tab3 를 선택한위 상단 탭을 클릭햇을 경우 다시 돌아왔을때 sub-tab3이 선택되어 있게 만들어준다. 이전 버전에서는 별도의 글로벌변수로 선언해준뒤 사용했었는데 이번 릴리즈에는 포함되어 나와서 상당히 편할듯하다..
히스토리 컴포넌트 사용시에는 URL 핸들링이 하는지 URL자체가 변하는 효과를 볼수 있다.
사용자 삽입 이미지


[MultiSelect / ItemSelector] [데모보기]
이 기능은 사용자 확장기능에 올라왔던 기능인데 이번 릴리즈에 포함되었있다.
전통적인 방식의 <select multiple> 기능을 extjs로 구현한 것이다.
사용자 삽입 이미지


[FileUploadField][데모보기]
사용자 확장기능에서 가장 많이 찾던 swfFileUpload에서 차용한듯한 소스가 이번 릴리즈에 포함되어 있다. ajax fileupload를 찾는 국내 사용자에게는 상당히 유용한 컴포넌트가 될듯하다. Form 컴포넌트에 포함되어 있다.
var fibasic = new Ext.form.FileUploadField({
    renderTo: 'fi-basic',
    width: 400
});


[XmlTreeLoader] [데모보기]
사용자 확장기능이다. 이전 treeLoader와 사용법은 비슷하다.


[GMapPanel][데모보기]
사용자 삽입 이미지
구글맵을 보여줄수 있는 panel이 추가되었다.
이것또한 사용자 확장기능이였으나 이번 릴리즈에 포함되었다.








사실 새롭게 추가된 기능들만 보자면 로드맵에 나왔던 내용들은 거의 없다.
향상된 기능들이라면 Firefox3 및 IE8 버전을 지원하다는 내용과 드래그앤드랍 기능(특정DnD영역그리드패널 Row의 드래그엔 드랍, 폼내널에서의 드래그엔드랍), 그리도 속도 향상, status기능등이 많이 향상되었다.

또한 축약어 들이 많이 등장했는데 Ext.MessageBox()를 msg()와 같이 표현한다던가, 브라우저 버전에 대한 글로벌 변수 Ext.isGecko2, Ext.isGecko3 등이 더 추가되었다.

그외 아래 링크로 확인하시기 바랍니다.






오픈소스 라이센스에 대한 이해~!! 는 다음 파일을 참조하세요








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

extjs 2.2의 IE에서 iframe document load 버그패치  (0) 2009.01.21
Extjs 3.0 Roadmap  (10) 2008.11.12
ExtJS 2.1 릴리즈  (4) 2008.04.22
RESTFul 한 ExtJS  (0) 2008.04.16
Extjs Qtips 사용하기  (2) 2008.04.16
Post by 넥스트리소프트 데꾸벅(techbug)
, |

IE7 의 렌더링 방식이 IE6과 다르다.
CSS testing of Selector and Pseudo selectors 를 보면 IE7 은 FF 에 더 가까와 지고 있다.
그래서 바야흐로 브라우저 3개를 켜고 코딩을 해야하는 시대가 온 것이다.

이를 해결하기 위한 방법 중 하나는 Selector Hack 을 이용하는 것이다.
.context_bar_form_field
{
height: 15px; // 모든 브라우저
#height: 15px; // IE 전용
_height: 21px; // IE6.0 과 이전버젼용
}
우선 파폭에 맞추어 개발을 한 후 E7 에서 점검한다. 수정할 부분이 있다면 # 접두어를 붙여 수정해 준다. #이 붙은 것은 FF 에서 무시한다. 하지만 IE 는 재설정 해준다.
다음에 IE6 을 열고 수정하면서 _ 를 접두어로 붙여 새로 재설정 한다. IE7 은 '-' 가 붙은 것을 무시한다.
 
또 다른 방법은,
.title h3 {height: 21px; }
.title > h3 {height: auto; min-height: 21px; }

이렇게 하는 방법도있다. 맨 아래줄은 파이어폭스와 IE7만 적용된다.

한가지 주의할 점은

body
{
text-align:-moz-center; /*FF*/
#text-align:center; /*IE */
}
속성 키워드 자체가 다른 것이 많다. 주의 할 것!
위에서 처럼 속성값 자체가 다른 경우가 있다. 그러니 안된다고 hack 만 쳐다보고 있으면 밤세야 한다.

내가 보기에 가장 좋은 방법은 Conditional Comments 를 사용하는 것이다.
복잡하게 한 파일에 구질구질 작성하지 말고 파일을 분리해 버리는 것이다.

참고 :http://webborg.blogspot.com/2007/01/css-compatibility-ie6-ie7-firefox-and.html

<head>
<title>my css hacked page</title>
<link rel="stylesheet" type="text/css" href="styles.css" />
<!--[if lt IE 7]>
<link rel="stylesheet" type="text/css" href="iehacks.css">
<![endif]-->
<body>
  <div class="watermark">....</div>...


이렇게 분리해서 각개격파하는 것이 좋을 듯 싶다.






IE 용인 Expression을 사용하여 본다면

a { expression(어쩌구 문법) }

이렇게 해서 a 태그 즉, 링크에 걸린 항목에 대하여 Expression은 적용 시킬 수 있을것입니다.

그럼 예로.. 링크주소중에 pdf 라은 확장자가 있다면 링크 앞에 자동으로 PDF 아이콘을 띄워봅시다.


a {
   padding-left: expression(this.href.indexOf('.pdf') > 0 ? '20px' : '');
   background: expression(this.href.indexOf('.pdf')>0 ? 'transparent url(pdf.gif) no-repeat center left' : '');
}

이건 IE 용입니다. Firefox에선 이렇게 하시면 됩니다.


a[href $='.pdf']{
   padding-left: 20px;
   background: transparent url(pdf.gif) no-repeat center left;
}

음... 불여시에서 사용하는게 훨씬 간편하네요 @@;;

[href $='.pdf'] 이 구문에서 $는 .pdf로 끝나는 것을 의미합니다.

.pdf로 시작하는 것을 찾으려면 $대신에 ^을 사용하시면 됩니다.

[href ^='.pdf']가 되겠죠. 그냥 포함 되어 있는지를 찾는 거라면 *을 사용하시면 됩니다.


<style>
a[href $='.pdf']{
   padding-left: 20px;
   background: transparent url(pdf.gif) no-repeat center left;
}

a {
   padding-left: expression(this.href.indexOf('.pdf') > 0 ? '20px' : '');
   background: expression(this.href.indexOf('.pdf')>0 ? 'transparent url(pdf.gif) no-repeat center left' : '');
}
</style>

<a href="test.pdf">test1</a><br/>
<a href="test.gif">test2</a>










Netscape 4 제외시키기

Netscape 4은 media속성값에 "screen"이외의 값이 올 경우 읽어 들이지 못하는 것을 이용한 방법이다.

<link rel="stylesheet" type="text/css" href="/css/style.css" media="all" /> 이나
<link rel="stylesheet" type="text/css" href="/css/style.css" media="screen, tv" /> 

라고 지정할 경우 Netscape 4은 읽어 들이지 못한다.

부분적으로 읽어들이지 못하게 하는 경우에는 Caio's hack인 /*/*/를 이용한다. 보통 코멘트는 */으로 닫지만 /*/으로 닫게 되면 Netscape 4에서는 인식되지 않는다. 그 뒤에 평상시의 코멘트 /* */를 적어두면 그 뒤의 스타일은 Netscape 4에서도 문제없이 적용된다.

p { /*/*/ color:white; /* */ } 

Mac IE 4.5, Netscape 4 제외시키기

@import룰로 url()함수를 이용하여 외부 스타일시트를 이중인용부호로 지정한다.
Mac IE 4.5는 @import에 url()함수를 이용하는 경우, 단일 인용부호와 인용부호가 없는 것이 아니면 읽어 들이지 못한다. Netscape 4은 @import를 지원하지 않는다.

@import url("/css/style.css")

Mac IE 5 제외시키기

CSS소스 안의 코멘트 서식을 /* \*/ 이라는 방식으로 기술한다. holly hack이라고 하며 그 뒤에 평상시의 코멘트 /* */를 적어두면 그 뒤의 스타일은 Mac IE 5에서도 문제없이 적용된다.

p { /* \*/ color:white; /* */ }

Win IE 4~5 제외시키기

셀렉터 바로 뒤에 /**/라고 적는다.

p/**/ { color:white;}

Win IE 4~5, Mac IE 4.5~5 제외시키기

프로퍼티와 값을 구분하는 콜론(;) 앞에 코멘트에 스페이스를 포함하여 /* */라고 적는다.

p { color/* */:white;}

Win IE 4~6, Mac IE 4, Netscape 4 제외시키기

셀렉터 앞에 html>body를 붙인다.

html>body p { color:white;}

Win IE 6 제외시키기

프로퍼티와 값을 구분하는 콜론(;)의 앞에, 스페이스와 코멘트를 /**/라고 적는다.

p { color /**/:white;}

star hack

셀렉트 앞에 *html를 붙이면, Win IE 4~6, Mac IE 4~5 등에는 스타일이 적용되고, 그 외의 브라우저에서는 적용되지 않는다.

*html p { color:white; }

underscore hack

프로퍼티의 가장 앞부분에 언더스코어(_)를 붙이면, Win IE 4~6에서 스타일이 적용되고, 다른 브라우저에서는 적용되지 않는다.

p { _color:white; }

hash hack

프로퍼티의 앞에 샾(#)을 붙이면, Win IE 4~6, Mac IE 5, Opera 7, Mozilla, Firefox에서는 스타일이 적용되고, 다른 브라우저에는 적용되지 않는다.

p { #color:white; }

star 7 hack

셀렉트의 앞에 html*을 붙이면, Win IE 5.5~6, Mac IE 5, Safari 등에서 스타일이 적용되고, 다른 브라우저에서는 적용되지 않는다. html*과 셀렉터사이에 스페이스를 넣지 않는다.

html*p { color:white; }

xmlns hack

속성셀렉터를 이용하여, html요소에 붙이는 xmlns속성을 스타일적용을 위하여 사용하는 방법.
Mozilla, Fire-fox, Opera 7/8, Safari 등 속성셀렉터를 서포트하는 브라우저에서는 스타일이 적용되고, 다른 브라우저에서는 적용되지 않는다.

html[xmlns] h1 { color:red; }

:root hack

셀렉터의 앞에 :root를 붙이면, Mozilla, Firefox, Mac IE 5, Safari 등 :root유사클래스를 지원하는 브라우저에만 스타일이 적용되고, 다른 브라우저에서는 적용되지 않는다.

:root h1 { color:red; }

Tantek box model hack

voice-family프로퍼티를 이용한 가장 유명한 박스모델핵.

div#content { width:500px; voice-family: ""}""; voice-family:inherit; width:400px; }

Win IE 5용 패스필터

@media tty { i{content:"";/*" "*/}}; @import '/css/style.css'; {;}/*";} }/* */

Win IE 5.5용 패스필터

@media tty { i{content:"";/*" "*/}}@m; @import '/css/style.css';/*";} }/* */

Win IE 5-5.5용 패스필터

@media tty { i{content:"";/*" "*/}}@import '/css/style.css';/*";} }/* */

모던브라우저용 패스필터

@import "null?"{"; @import "/css/style.css"; @import "null?"}";

이 이외에도 많은 핵(hack)이 존재한다. CSS Filters (dithered.com)에 다양한 CSS hack이 잘 정리되어 있으므로 참고하시길…


IE7에만 적용

IE7를 포함한 모든 IE에만 적용하는 방법은

IE7을 포함한 모던브라우저에 적용(IE6이하를 제외)

IE7을 제외한 모던브라우저에만 적용


위의 내용은 썬샤인님의 블로그에서 꿈쳐온 것입니다..

나이가 먹다보니 가끔 치매끼가 있어서.. 잊어버릴것 같아 살포시... ^^


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

데꾸벅이 FF를 사용하는 이유 중 하나가 Firebug를 사용할수 있다는 것이다.(너무 과장했나?)
그런데 IE, Opera, Safari에서도 Firebug를 사용할수 있다.

참조사이트 : http://getfirebug.com/lite.html

1. 설치
<script type='text/javascript' src='http://getfirebug.com/releases/lite/1.2/firebug-lite-compressed.js'></script>

2. 북마크하기
javascript:var firebug=document.createElement('script');firebug.setAttribute('src','http://getfirebug.com/releases/lite/1.2/firebug-lite-compressed.js');document.body.appendChild(firebug);(function(){if(window.pi&&window.firebug){firebug.init();}else{setTimeout(arguments.callee);}})();void(firebug);


3. 오프라인에서 사용하기 (소스다운로드)

<script language="javascript" type="text/javascript" src="/path/to/firebug/pi.js"></script>
<script language="javascript" type="text/javascript" src="/path/to/firebug/firebug-lite.js"></script>


4.console.log() 에서 에러가 발생한다면 아래 파일을 다운로드 받은후 다음과 같이 작성한다.

 <script language="javascript" type="text/javascript"  src="/path/to/firebug/firebugx.js"></script>

 
5. Firebug Lite를 사용하려면 마크업에 다음과 같이 표시한다.
<html debug="true">




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)
, |


Ajax 사이트를 개발하다보면 브라우저 버전에 따른 별도의 작업을 해줘야 하는 경우가 발생한다.
실제 현재 투입되어 개발중인 사이트의 경우에도 IE6,IE7에 최적화되게 개발하기로 했지만 실제로 테스트해본결과 Opera9, FF2~3, IE7, IE8Beta 버전에서 더 잘 돌아갔다..
문제는 IE6인데 IE6에서도 Windows 2000 SP1~3, Windows XP SP1,SP2에서는 무리없이 잘 작동되던 스크립트인데 유독 Windows XP SP3 버전의 IE6에서만 오작동하는 경우가 발생했다.
IE6 버전 (WindowsXP SP3)
6.0.2900.5512 xpsp.080413-2111
Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)


이놈 하나 때문에 패키징을 다시 해야 되는 경우가 발생되었고 모든 작업을 브라우저버젼별로 분리하여 작업하기란 워낙 까다로운게 아닐수 없다.
그냥 사용자의 브라우저를 IE7로 업그레이드를 시킬수만 있다면 좋을텐데 라는 생각을 많이 하곤 한다.

그러다 찾아 본 사이트가 이곳 푸쉬업(Push up:Pushing up the web) 이다.
자바스크립트와 CSS로 업데이트 날짜가 지난 사용자의 브라우저를 업데이트하라는 경고메세지를 보낼수 있다.


현재지원되는 브라우저 버전
  • Internet Explorer 7+
  • Firefox 2+
  • Safari 3+
  • Opera 9.25+
사용자 삽입 이미지




설치방법은 간단하다
아래 파일을 다운로드 받은후 원하는 페이지소스에다 아래와 같이 입력하면 된다.
(July 27 2008)


<link rel='stylesheet' type='text/css' href='css/pushup.css' />
<script type='text/javascript' src='js/pushup.js'></script>






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

웹표준코딩에 익숙한 사용자라면 csszengarden 사이트를 잘 알것이다.
csszengarden 사이트를 보면 동일한 마크업(HTML)에 CSS만으로 페이지 자체가 완전히 틀린 분위기를 연출하게 만들며 환상적인 폰트사용을 볼수 있다.

@font-face에 대해서 말해보려 한다.
아래 이미지는 강의자료로 사용했던 내용이다.
사용자 삽입 이미지

웹폰트 제공사이트 : http://www.fontembedding.com/fonts-and-the-law/

오늘 Ajaxian에 올라온 포스트중에 재미있는 글이 있어 링크를 따라 가다 보니 다음과 같은 글이 있어 포스팅해 본다.
원문 : http://www.alistapart.com/articles/cssatten


웹폰트 사용할시
@font-face { font-family: "Kimberley"; src: url(http://www.princexml.com/fonts/larabie/ » kimberle.ttf) format("truetype"); }
h1 { font-family: "Kimberley", sans-serif }

@font-face와 같이 길게 쓰지 않고 간략한 표현
@import url(http://www.princexml.com/fonts/ » larabie/index.css) all;
h1 { font-family: Goodfish, serif }

W3에서 권장하는 방법
h1 { font-family: "Trebuchet MS", sans-serif; letter-spacing: 0.1em; }
@media all and (web-fonts: "truetype") {
   h1 { font-family: "Primer Apples", sans-serif; letter-spacing: 0.2em; }
}

사용자 삽입 이미지

Screenshot of web page using real TrueType fonts. PDF (via Prince). HTML (via your browser).


사용자 삽입 이미지

Screenshot of web page using real TrueType fonts. PDF (via Prince). HTML (via your browser).


사용자 삽입 이미지

Screenshot of web page using real TrueType fonts. PDF (via Prince). HTML (via your browser).


사용자 삽입 이미지

Screenshot of web page using real TrueType fonts. PDF (via Prince). HTML (via your browser).


사용자 삽입 이미지

Screenshot of web page using real TrueType fonts. PDF (via Prince). HTML (via your browser).


사용자 삽입 이미지

Screenshot of web page using real TrueType fonts. PDF (via Prince). HTML (via your browser).

사용자 삽입 이미지

Screenshot of web page using real TrueType fonts. PDF (via Prince). HTML (via your browser).






데꾸벅폰트 다운로드






HTML5에서 Canvas 관련 요약정리 CheatSheet










Post by 넥스트리소프트 데꾸벅(techbug)
, |
이미 아는 사람들은 다아는 로딩바 원하는 형태로 만들기 사이트(http://www.ajaxload.info/)에서 좋은 Loading Indicator(Spinner)를 구한 다음에 아래와 같이 간단히 구현할 수 있다.

jQuery(function($){
        // Create img dom element and insert it into our document
        var loading = $('<img alt="loading" src="/images/loading.gif" />')
        .appendTo(document.body).hide();
        // Make the image appear during ajax calls
        $(window).ajaxStart(loading.show);
        $(window).ajaxStop(loading.hide);
});



참고적으로 요기도 보아두면 좋아요~~
jQuery를 모르는 분들은 여기서 부터 시작하세요



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)
, |

Excel 새창에서 열기
엑셀시트를 이용해서 작업을 하다가 보면 기본적으로 항상 같은 창에 cascade하게 열린다.
파일을 각각 따로 열고 싶을때가 있다.

뇌입어 지식인에 물어보면 xp에서는 있는 메뉴가 vista에는 없는 경우가 있어
직접 excel 파일의 환경설정을 찾아봐야 하나 2007 메뉴가 기존의 as-is와 틀려서
한참을 고생하다 찾은 팁을 올린다.

먼저 이곳(http://support.microsoft.com/kb/2551928/ko#B-1)을 참조하는게 더 빠를듯..




1.  오른쪽 하단의 "Excel 옵션" 클릭



2. 고급 > 일반 > DDE 체크


3. 끝 ㅡ.,ㅡ;




PowerPoint 2007 따로열기


1. 첨부된 파일을 다운받은후 압축을 해제한다.


2. PPCORE.DLL 이라는 파일을 확인한다.

3. 열려있는 모든 PowerPoint를 종료한다.

4. C:\Program Files\Microsoft Office\Office12\PPCORE.DLL 을 백업한다.[선택]

5. C:\Program Files\Microsoft Office\Office12에 압축을 해제한 PPCORE.DLL을 복사한다.

6. Microsoft Office 2007 PowerPoint를 실행하면 이제 각각의 창으로 오픈된다.


'Integrator > Windows' 카테고리의 다른 글

GET Method 길이 제한 (최대 URL 길이 )  (3) 2008.11.20
데꾸벅체 다운로드  (0) 2008.07.09
윈도우 서비스 등록하기  (1) 2008.02.21
Post by 넥스트리소프트 데꾸벅(techbug)
, |