Rev. 2.73

avgrund.png

Avgrund는 Dmitri Voronianski씨가 작성한 모달 박스를 출력하는 jQuery용 플러그인입니다. 모달 박스가 출연할 때 원래 페이지와의 깊이를 표현하는 흥미로운 개념을 도입했습니다. 이는 CSS에서 transition 그리고 transform 속성을 이용해서 구현한 것이에요. 사용방법은 다음과 같습니다:

$('element').avgrund();

// or with several options for customize

$('element').avgrund({			
	width: 380, // max is 640px
	height: 280, // max is 350px
	showClose: false, // switch to 'true' for enabling close button 
	showCloseText: '', // type your text for close button
	closeByEscape: true, // enables closing popup by 'Esc'..
	closeByDocument: true, // ..and by clicking document itself
	holderClass: '', // lets you name custom class for popin holder..
	overlayClass: '', // ..and overlay block
	enableStackAnimation: false, // another animation type
	onBlurContainer: '', // enables blur filter for specified block 
	template: 'Your content goes here..'
});

Comments

HTML5의 History/State API를 이용하여 브라우저의 히스토리를 조작하는 방법에 대해 알아보겠습니다. 그동안 location.hash로 꾸리 하게 밖에 구현할 수 없었던 브라우저 히스토리를 대체할 수 있는 명세로서, Ajax로 호출한 컨텐츠가 드로잉 된 페이지를 조회한 후 브라우저에서 "뒤로 가기" 버튼을 눌러 다시금 이전 위치로 이동하고 해당 컨텐트를 조회할 수 있게 하는 목적으로 사용할 수 있습니다. 알다시피, 이와 같은 뒤치다꺼리를 하지 않으면 방문객은 우리의 웹사이트를 무심결에 떠나 버리는 불상사가 발생할 수 있지요. 얼마 전에 소개한 Customized JS Bin에 이 명세를 적극적(대부분의 요청에 사용)으로 반영하면서 알아낸 몇 가지 사실들에 대하여 정리해보겠습니다.

비동기(동적으)로 컨텐츠를 갱신할 때 매번 마음 한구석에 남는 응어리는 바로 시멘틱 웹입니다. Ajax로 불러들여 진 컨텐츠가 정적이어(검색되어)야 할 필요성 가장 먼저 판단해야 합니다. 왜냐하면, 이에 따른 추가작업이 필요하거나 구조가 달라지기 때문이죠. 만약 시멘티컬한 환경을 고려한다면 서버-사이드에서 하나의 URL을 각기다른 형식의 데이터로 응답할 필요가 있습니다. 비동기 요청에는 레이아웃을 제외한 갱신영역이나 내용만을 담은 작은 HTML 조각 혹은 JSON과 같은 응답형태를 가지고, 일반적인 요청에는 레이아웃을 포함한 완벽하게 파싱된 정적인 HTML 컨텐트를 응답하는 두 가지를 모두 준비하는 것이 좋습니다.

A 요소에 href 속성에는 페이지가 갱신될 주소를 반드시 기입해서 웹 크롤러들이 컨텐츠를 샅샅이 긁어갈 수 있게 하고 클릭을 자바스크립트로 제어하여 Ajax로 요청 및 갱신하는 것이 일반적인 패턴입니다. 하나의 주소에서 응답형태가 다른 컨텐트를 제공하는 것이 마음에 안들지도 모릅니다. 물론 개별적으로 응답형태에 따른 주소를 제공하거나 파라미터를 이용할 수도 있겠지만, 개인적으로 선호하지 않는 방법이기 때문에 개별 주소를 사용하는 방법에 대해서는 생략하겠습니다. 대부분의 서버-사이드 언어는 Ajax 요청인지를 구분할 수 있으며, PHP는 다음과 같은 방법으로 알아냅니다.

<?php
  $ajax = isset($_SERVER['HTTP_X_REQUESTED_WITH'])
      || (isset($_SERVER['HTTP_ORIGIN']) && $_SERVER['REQUEST_METHOD'] == 'GET');

  if ($ajax) {
    header("Content-Type: application/json; charset=utf-8");
?>
{
  "title": "Fire JS Bin",
  "url": "http://jsbin.firejune.com",
  "text": "Collaborative playground for web developers."
}
<?php
  } else {
    header('Content-type: text/html; charset=utf-8');
?>
<html>
  <head>
    <title>Fire JS Bin</title>
  </head>
  <body>
    <div id="content">Collaborative playground for web developers.</div>
  </body>
</html>
<?php
}
?>

JS Bin의 컨텐츠는 코드이기 때문에 검색으로 접근될 확률이 낮습니다만, 기본 설계가 정적인 컨텐츠를 제공하는 형태로 만들어져 있기 때문에 시멘틱한 모습으로 방향을 잡았습니다. History API를 지원하는 브라우저에서는 동일한 주소에서 JSON형식의 데이터만 수신하고 그렇지 않으면 주소창의 주소가 변경되면서 이동합니다. 이제 브라우저 히스토리를 조작해 봅시다.

  function drawHTML(data, state) {
    if (state) history.pushState(data, data.title, data.url);
    $('#content').html(data.text);
  }

  function requestError(req, state) {
    alert('WTF? ' + state);
    //location.href = this.url;
  }

  $('a').click(function() {
    if (history.pushState) {
      $.getJSON(this.href).success(drawHTML).error(requestError);
      return false;
    }
    return true;
  });

범국민 라이브러리인 jQuery를 이용한 간단한 예입니다. A 요소의 클릭을 감시하는 함수는 지원 여부를 구분하여 href에 명시된 주소로 JSON 요청을 날린후 이벤트 진행을 중단하며 그렇지 않은 경우 A 요소가 정상적으로 클릭 되어 일반적인 주소 이동이 발생하도록 내버려 둡니다. drawHTML 함수에는 패이지가 갱신될 코드와 history.pushState 메서드를 호출하는 코드로 구성되어 있습니다. 이 메서드는 3개의 인자를 받는데, 해당 페이지의 상태를 보존하기 위한 데이터와 문서 제목 그리고 해당 페이지의 URL입니다. drawHTML 함수의 두 번째 state 인자가 유효한 때에만 실행되며 호출되는 즉시 브라우저의 주소창이 바뀌고 히스토리 스택이 쌓입니다. 여기까지는 쌓기만 한 것입니다. 이제 히스토리가 변경되면 발생하는 이벤트인 window.onpopstate를 작성해 봅시다.

  $(window).bind("popstate", function(event) {
    var data = event.originalEvent.state;
    if (data) drawHTML(data, false);
  });

이때 보존해 두었던 데이터를 그대로 캐시처럼 활용함으로써 두 번 다시 서버를 힘들게 하지 않아도 되는 장점이 있습니다. 그리고 drawHTML의 두번째 인자를 false로 넘겨 주는 것은 히스토리를 더이상 쌓지 않게 하기 위함입니다. 이미 쌓여있는 녀석을 또 쌓을 필요는 없으니까요. 이외에도 history.replaceState라는 메서드가 있는데, 해당 주소의 컨텐트가 갱신된 경우에 사용하는 것입니다. 이게 전부에요. 간단하죠? 해시가 아닌 URL이 변경되는 레알 히스토리이면서 Ajax로 신규 컨텐트만 갱신하고 캐시효과도 누릴수 있기 때문에 매우 빠릅니다. 우리가 잘 알고있는 GitHub에서도 슬라이드 효과를 동반한 소스코드 살펴보기 그리고 개시물을 조회하는 곳곳에 이 API를 사용하고 있습니다.

음... History/State API를 지원하지 않는 브라우저에서는 종전과 같이 location.hash트릭으로 비스무리한 기능을 부가적으로 제공할 수 있습니다. HTML5 History/State API를 모든 브라우저에서 사용 가능하게 하는 History.js도 좋은 대안이 될 수 있을 것아서 적용했다가, JS Bin은 이미 이 해시를 이용하여 에디터의 뷰 활성 상태를 관리하기 때문에 충돌이 발생했고 또한 다소 무거운 느낌이 들어서 바로 제거했습니다. jsbin.firejune.com으로 이동해서 컨텐츠와 주소창이 변경되는 모습을 직접 확인해보세요. 참 그리고 커스터마이즈한 JS Bin도 많이 진척되었습니다. 관심 있으신 분들은 릴리즈 노트도 함께 봐주세요. 소개글 이후 자세한 변동내역이 모두 기록되어 있습니다.

Comments

jsbin.png

그동한 소스분석 용도로 잘 사용해 오던 JSBin을 새로운 버전으로 업데이트 하려다가 커스토마이즈 하는 기쁨에 쉼취해 회사일도 마다하고 최근 3주간 불꽃 코딩을 작렬했습니다. 애용중인 맥용 소스코드 편집기인 Panic사의 코다에 영감을 얻어 웹기반으로 연출하려고 소스를 재작성한 것입니다. 이제 얼추 모습을 갖추어 그동안의 커스토마이즈 내역을 기록하고자 합니다. 기존 JSBin에 새로운 피쳐들을 여럿 추가했습니다. 레이아웃 리프레시, 편집, 보기, 저장소 도구를 상호작용 컨텍스트 메뉴로 리그룹, 저장소 이름 설정, 트위터 인증을 통한 저장소 관리 및 협업, 히스토리를 지원하는 Ajax 데이터 CRUD, CSS 편집 지원, 편집기(CodeMirror2) 환경 설정 및 테마 설정, 단축키 지원 확대, CSS3 기반(애니메이션, 웹폰트 아이콘 사용 노 이미지), 상태바, 문자열 찾기 및 찾아 바꾸기, MinifierBeautifier‎ 내장 및 북마크릿 생성 도구, Closure Compiler 도구 제공, 매치 하이라이터, 커서위치 표시기, 씬 스크롤러, 패널별 단축 메뉴, 저장소 문자열 검색 및 패널 보임/숨김, 모든 상황을 로컬 스토리지에 보존 등이 주요한 내용입니다. WebKit 계열 브라우저를 중심으로 작업했기 때문에 타 브라우저에서는 오작동이 발생할 수 있으며, 일부 기능(다이얼로그(Apprise), 서체 크기 조정, 코드 폴딩, 자동 완성, 코드 힌트, SNS 공유, 커밋 및 포크 추적, Diff 도구 등)은 아직 미구현 상태입니다. jsbin.firejune.com에서 직접 경험해 보세요.

Comments