CSSHttpRequest
Scripter/AJAX / 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);
}
};
})();
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를 살펴보면http://www.nb.io/hacks/csshttprequest/hello-world/helloworld.css,
function(response) { alert(response); }
);
@import url(about:chr:Hello%20World!);
와 같이 CSS의 about: 을 이용한다.CHR은 XHR이나 JSONP와 같은 sampe-origin policy (같은 도메인에서 동작)과 다른 범주에 속한다. (흠..번역이..쩝..) JSONP와 같이 CHR도 GET Reqeust밖에 사용하지 못한다.
샘플 :
참조 사이트 :
http://nb.io/hacks/csshttprequest/
'Scripter > AJAX' 카테고리의 다른 글
Ajax Framework 분석 (0) | 2009.05.04 |
---|---|
HTTP Header에 대하여 (0) | 2008.11.08 |
AJAX에서 즐겨찾기와 뒤로가기를 다루는 방법 (0) | 2008.09.24 |
100라인 Ajax Wrapper (0) | 2008.04.19 |
어떤 AJAX Framework를 선택할 것인가. (0) | 2008.03.14 |