Rev. 2.73

Ajax의 활동여부를 알리기 위한 알림이(Indicator)를 표시하기 위해 똑같은 반복 작업을 한적이 있다. 모든 Ajax요청의 onLoading, onComplete 콜백에 알림이를 보이고 숨기는 코드를 삽입하는 것이다. 목적이 서로다른 Ajax요청이 수십가지에 달한다면 매우 비효율적인 작업이 아닐 수 없다. 그러나 Prototype의 코어를 조금만 손대면 매우쉽게 전역 Ajax알림이를 구현할 수 있는 꼼수가 있다. 아래와 같은 Indicator라는 함수가 있다고 가정하자.

// Global Ajax Indicator
var Indicator = Class.create({
  initialize: function() {
    this.element = document.createElement('div');
    this.element.style.display = 'none';
    this.element.className = 'indicator';
    document.body.appendChild(this.element);
  },
  show: function() {
    this.element.show();
  },
  hide: function() {
    this.element.hide();
  }
});
Indicator = new Indicator();

보통은 아래와 비슷한 형식으로 Ajax 작동상태를 표시한다.

new Ajax.Request('/ajaxUrl', {
  onLoading: function() {
    Indicator.show();
  },
  onComplete: function() {
    Indicator.hide();
  },
  onSuccess: function(req) {
    // some actions
  }
});

Ajax객체를 생성 할 때 마다 위와 같은 작업을 일일이 해야하는 것이다. 그리고 때로는 onComplete 콜백을 놓치는 경우도 있어 알림이가 영영 사라지지 않는 현상도 발생한다. prototype.js의 Ajax.Responders.register 메서드를 아래와 같이 오버라이드하면 이 문제를 일거에 해결 할 수 있다.

// show/hide indicator on all Ajax callbacks
Ajax.Responders.register({
  onCreate: function() {
    Indicator.show();
    Ajax.activeRequestCount++;
  }, onComplete: function() {
    Indicator.hide();
    Ajax.activeRequestCount--;
  }
});

하지만, Ajax요청마다 알림이의 모양과 위치가 다르다면 '즐'이다.

Comments

prototypeonieerror.gif

어느 때 부터인지 IE에서 특정한 페이지를 로드하면 원인을 알수 없는 오류가 지속적으로 나타나는 증상을 보여서 디버깅에 들어갔다. Prototype 1.6.0 release candidate로 업데이트한 후 위 화면과 같은 문법오류 메시지가 나타나는 요상한 증상을 서로 다른 프로젝트에서 경험했다. 처음 접했을 때에는 인코딩에서 발생한 문제로 판단하고 별별 삽질을 강행하다가 울며 겨자먹기로 버전다운 할 수 밖에 없었다. 결국에는 수천 라인을 비교추적하는 작업 끝에 버그발생의 원인을 알아내고 말았다. 이 허무맹랑한 현상은 Dean Edwards씨에 의해 새롭게 생겨난 'contentloaded' 이벤트 때문에 발생한다.

prototype.js의 4013라인에 아래와 같은 문장이 있다.

4013      document.write("<script id=__onDOMContentLoaded defer " +
4014            "src='://javascript:void(0)'><\/script>");

위 문장을 다음과 같이 수정하면 오류가 사라진다.

4013      document.write("<script id=__onDOMContentLoaded defer " +
4014           "src='http://javascript:void(0)'><\/script>");

그러나, 오류만 사라지고 'contentloaded' 이벤트가 발동하지는 않았다. 이 이벤트는 DOM의 드로잉이 완료되는 시점에 발동하는 이벤트이다. 모든 컨텐츠의 로딩이 완료되는 시점에 발사되는 onload와는 차별되는 이벤트다. 이와 같은 문제로 골머리를 앓고 있는 개발자가 여럿 있다는 사실을 구글링을 통해 알 수 있었고 아래와 같은 해결방안을 찾을 수 있었다.

4013      document.write("<script id=__onDOMContentLoaded defer src=//:><\/script>"); // fix syntax error

아..... 요 벌거지 때문에 이틀 밤잠을 설레발쳤다.... 이제 자야지...

Comments

heatmap.jpg

ClickHeat은 HTML 문서영역에서 발생하는 모든 클릭을 감시하여 비주얼라이즈(visualize)하는 색다른 분석도구(analytics)이다. 클릭 이벤트를 자바스크립트로 감시하고 좌표와 문서크기 브라우저의 종류 등이 담긴 정보를 Ajax로 서버에 전송하여 그룹, 사이트, 브라우저, 버튼 그리고 기간 단위로 히트맵 PNG 이미지를 실시간 생성 및 출력한다. 별도의 로그인을 통해 히트맵을 조회 할 수 있으며, 웹사이트에 중첩하여 표시하는 화면과 관리화면 등이 준비되어있다.

ClickHeat은 PHP와 GD2(PNG 지원 필요) 라이브러리가 돌아가는 서버환경을 요구하며 브라우저 클라이언트는 파이어폭스2, IE 6, 5 그리고 Konqueror 등 거의 모든 브라우저에서 작동한다. 데이터베이스(SQL)를 사용하지 않는 구조여서 업로드만으로 돌아가기 때문에 설치가 매우 간편하다. 다음 릴리즈에는 데이터베이스 구조 지원 및 랜더링 속도 향상 그리고 정확도를 높일 예정이라고 한다. 아쉬운 점이라면, 링크별 비주얼라이제이션(visualization)이 번거롭다. 페이지마다 개별적으로 그룹화하지 않으면 히트맵의 정보와 사이트에 중첩된 화면이 언매칭(unmatching) 되는 경우가 잦다. 그리고 Ajax를 통한 전송 방법으로는 아웃링크(A태그)를 클릭했을 때 정보가 서버로 전달되지 않는 현상이 발생한다. 상황에 따라 달랐지만 대부분의 이벤트를 놓치는 것으로 나타났다. 아마도 XMLHTTPRequest 객체를 호출하는데에는 적잖은 브라우저 코스트(cost)가 발생하기 때문인 것으로 생각된다. IP별 또는 리퍼러별 히트맵이 추가되는 것도 재미있겠다는 생각이 든다.

그래서 뜯어 고쳤다. clickheat.js를 토대로 Prototype에 어울리는 환경으로 개조를 시도했다. 개조에는 크게 세가지 목적이 있는데, 자동으로 링크별 저장/출력 하는 것, 관리화면으로 진입하지 않고 히트맵을 비주얼라이즈하는 것(서버사이드 수정 필요), 그리고 아웃링크의 클릭도 정확하게 전송되도록 하는 것 등이다. 약 반나잘을 투자해서 heatmap.js를 구축하고 아래와 같이 사용하할 수 있는 클래스를 만들었다. 이곳을 클릭하고 잠시 기다려 보자. 이 포스트에 대한 히트맵만이 출력되는 것을 확인할 수 있다.

HeatMap = new HeatMap('/clickheat/', { group: 'index', site: 'firejune.com', time: 0.5 }); // initialize
HeatMap.show({group: 'index', range:'d', browser: 'all', heatmap: '1' }); // call heatmap images 

Comments