Scripter/AJAX

CSSHttpRequest

데꾸벅 2008. 11. 12. 15:11

XML과 XMLHttpRequest(XHR)의 시대는 물건너 갔는가?
JSON(JSONML)과 CSS만으로 통신을 하다 못해 이제는 CSSHttpRequest까지 나왔다.

CSS의 Hack을 이용한 것으로 cross-domain이 가능하다.
CSSHttpRequest(CHR)은 CSS 통신을 위한 크로스도메인 AJAX 메쏘드이다.

CSSHttpRequest.js
(function(){
    var chr = window.CSSHttpRequest = {};
   
    chr.ID = "__csshttprequest__";
    chr.DELAY = "50";
    chr.counter = 0;
    chr.requests = {};
    chr.timeout = null;
    chr.styleSheet = null;
    chr.styleElement = null;
   
   
    chr.get = function(url, callback) {
        var id = (++chr.counter);
        var s = chr.getStyleSheet();
        var item, index;
       
        // IE
        if(s.addImport) {
            index = s.addImport(url);
            item = s.imports(index);
        }
       
        // W3C
        else if(s.insertRule) {
            index = s.insertRule("@import url(" + url + ");", 0);
            item = s.cssRules[index];
        }
       
        chr.startPoll();
        return chr.requests[id] = {
            id: id,
            index: index,
            item: item,
            styleSheet: item.styleSheet || item,
            callback: callback
        };
    };
       
   
    chr.getStyleSheet = function() {
        if(chr.styleSheet)
            return chr.styleSheet;
       
        var s, e;
        if(document.createStyleSheet) {
            s = document.createStyleSheet();
            e = s.owningElement || s.ownerNode;
        } else {
            e = document.createElement("style");
            s = e.sheet;
        }
       
        e.setAttribute("type", "text/css");
        e.setAttribute("media", "print, csshttprequest");
        e.setAttribute("title", chr.ID);
        e.setAttribute("id", chr.ID);
       
        if(!e.parentNode)
            document.getElementsByTagName("head")[0].appendChild(e);
        if(!s)
            s = e.sheet;
       
        chr.styleSheet = s;
        chr.styleElement = e;
       
        return s;
    };
   
   
    chr.reset = function() {
        var s = chr.getStyleSheet();
        if(s.imports)
            while(s.imports.length)
                s.removeImport(0);
        else if(s.cssRules)
            while(s.cssRules.length)
                s.deleteRule(0);
        chr.requests = {};
    };
   
   
    chr.startPoll = function() {
        if(chr.timeout)
            return;
        chr.timeout = window.setTimeout(chr.poll, chr.DELAY);
    };
   
   
    chr.poll = function() {
        chr.timeout = null;
        var retry = false;
       
        for(var id in chr.requests) {
            var request = chr.requests[id];
            if(id != request.id)
                continue;
            var response = chr.parse(request.item.styleSheet || request.item);
            if(response === undefined)
                retry = true;
            else {
                delete chr.requests[id];
                request.callback(response, request);
            }
        }
       
        if(retry)
            chr.startPoll();
        else
            chr.reset();
    };
   
   
    chr.parse = function(s) {
        if(!s)
            return;
       
        var res = "";
        var d = decodeURIComponent;
       
        // IE
        if(s.imports && s.imports.length) {
            for(var i = 0; i < s.imports.length; i++) {
                var m = s.imports(i).href.match(/about\:chr\:(.+)/);
                if(m && m[1])
                    res += m[1];
            }
            return d(res);
        }
       
        // W3C
        else if(s.cssRules && s.cssRules.length) {           
            var rs = s.cssRules;
            for(var i = 0; i < rs.length; i++) {
                var r = rs[i];
                if(r.type != CSSRule.IMPORT_RULE)
                    continue;
                var m = r.cssText.match(/@import\s+url\("?about\:chr\:([^")]+)"?\)/);
                if(m && m[1])
                    res += m[1];
            }
            return d(res);
        }
    };
})();



XHR이 XML이나 JSON을 타겟으로 삼는다면 CHR은 CSS파일의 @import url()을 이용한다.
CSSJSON 이나 CSSML을 이용한것이 사실 XML/XSLT를 이용한것 보다 화면레더링하기는 사실 더 편하고 관리하기도 쉽다. CSS,JSON을 이용한다면 XML Node찾는것 보다 더 쉽지 않을까?


CHR을 이용하려면 AJAX Wrapper인 CSSHttpRequest.js 을 받아서 아래와 같이 입력한다.
    CSSHttpRequest.get(
        http://www.nb.io/hacks/csshttprequest/hello-world/helloworld.css,
        function(response) { alert(response); }
    );
보는바와 같이 css를 호출한다. 해당 css를 살펴보면
 @import url(about:chr:Hello%20World!);
와 같이 CSS의 about: 을 이용한다.

CHR은 XHR이나 JSONP와 같은 sampe-origin policy (같은 도메인에서 동작)과 다른 범주에 속한다. (흠..번역이..쩝..) JSONP와 같이 CHR도 GET Reqeust밖에 사용하지 못한다.


샘플 :


참조 사이트 :
http://nb.io/hacks/csshttprequest/