[bootstrap] 폼 만들기

http://twitter.github.com/bootstrap/base-css.html#forms

bootstrap의 CSS만 사용해서, 다음과 같이 깔끔한 폼을 쉽게 만들 수 있습니다.

마침 봄싹 홈페이지를 개편하려던 중에 Bootstrap을 보게됐고, 유려하고 일관성있는 디자인, 다양한 UI 제공, 깔끔하고 얇게(?) 정리된 문서와 가벼워 보이는 구성 때문에  바로 도입했습니다.

처음엔 네비게이션 바를 만드는 것부터 했었는데, 오늘은 폼 만드는걸 했고, 다음엔 탭 뷰를 다루게 되지 않을까 싶네요. 폼은 CSS만 class만 잘 사용하면 되는데… 구성은 다음과 같습니다.

여기서 로그인 폼 코드는 다음과 같습니다.

  • form 태그에는 form-horizontal 클래스를 붙인다.
  • form 구성 요소는 div 태그를 사용하고 control-group 클래스를 붙인다.
  • form 구성 요소의 제목은 label 태그를 사용하고 control-label 클래스를 붙인다.
  • form 구성 요소의 본문을 둘러싸는 div 태그를 사용하고 controls 클래스를 붙인다.
  • form 구성 요소는 div.controls 안에 둔다.
  • input type=”text” 요소에는 input-xlarge 클래스를 사용한다.
  • form 버튼을 둘러싸는 div 태그를 만들고 form-actions 클래스를 붙인다.
  • form 버튼은 div.form-actions 안에 두고, button 태그를 사용하고 btn 클래스를 붙인다.

[자바스크립트] 모듈

http://blog.davidpadbury.com/2011/08/21/javascript-modules/

자바스크립트에는 자바의 import나 C#의 using이라는 개념이 없다. 그래서 자바스크립트를 사용하는 개발자가 직접 그런 개념을 구현하고자 노력 중이다.

모듈 패턴

http://www.adequatelygood.com/2010/3/JavaScript-Module-Pattern-In-Depth 이 글에 있는 최종적인 소스 코드가 다음과 비슷하다.

이 코드에는 다음과 같은 개념이 녹아있다.

Isolation

자바스크립트의 함수 스코프를 이용해서 글로벌 스코프 변수를 사용해서 발생할 수 있는 난감한 상황을 피할 수 있다. 함수 내부에 있는 모든것은 시스템의 영향을 받지 않는다.

namespacing

위 코드의 마지막 줄처럼 이미 window에 lab49라는 네임스페이스가 있는지 없는지 여부에 따라서 이미 있다면 기존의 것을 사용하고 없다면 비어있는 객체 리터널을 넣어서 새로 만들도록 할 수 있다. 위와 같은 함수 랩퍼를 여러 자바스크립트 파일이 사용한다고 가정했을 때 유용한 방법이다.

Private State

함수 안에 있는 모든건 외부에서 접근할 수 없기 때문에 코드를 격리시키기 좋긴하지만, 함수 밖에서 그 안에 있는 걸 아무것도 접근할 수 없다면, 별 쓸모없는 함수가 되고 만다. 그래서 lab49처럼 window 객체에 네임스페이스 역할을 할 객체를 붙이고, 거기에 외부로 공개할 것을 붙이는 형태로 코딩할 수 있다. 마치 add 함수처럼. 저렇게 코딩해두면 밖에서는 lab49.add(2, 2)처럼 호출할 수 있다.

CommonJS 모듈

CommonJS는 주로 서버 사이드 자바스크립트 런타임을 만든 사람들로 구성된 그룹으로 모듈 공개와 접근에 대한 표준화를 시도했다.

CommonJS 모듈 스팩

exports에 공개할 모듈을 추가하고, 모듈을 사용하는 쪽에서는 require를 사용해서 필요한 모듈을 가져다 사용한다.

CommonJS는 서버 사이드 자바스크립트 런타임을 주요 타겟으로 설계되었기 때문에 다음과 같은 이유로 클라이언트 사이드에 적용하기는 어려움이 있다.

  • requrie는 반드시 즉시 리턴해야 한다: 스크립트를 비동기적으로 다운로드하는 스크립트 로더를 사용하기 어렵게 한다.
  • 파일당 모듈: CommonJS 모듈을 만들려면 함수 하나로 감싸야하며 특정한 방법으로 구성해야 하는데, 그러려면 StitchBrowseify같은 노드 모듈을 사용해서 여러 모듈 자바스크립 파일을 하나의 자바스크립 파일로 묶어주는 컴포넌트를 사용하지 않고는 힘들어진다.

AMD(Asynchronous Module Definition)

AMD는 브라우저용 모듈 포맷으로 설계됐다. CommonJS 그룹에서 먼저 제안했지만, Github으로 자리를 옮기고 나서 테스트 스위트로 관리되고 있다.

AMD의 핵심 함수는 define 함수다. 이 함수를 세 개의 매개변수를 가지고 호출하는 코드가 가장 자주 사용하는 방법인데, 첫번째 매개변수로 모듈 이름을 넘기고, 두번째는 이 모듈이 의존하고 있는 모듈 식별자 배열을 넘기고, 마지막으로 모듈 정의를 반환할 팩토리 함수를 넘긴다.

모듈 정의가 define으로 감싸지기 떄문에 얼마든지 한 파일 안에 여러 모듈을 정의할 수 있다. 그리고 모듈 로더가 define 모듈 팩토리 함수를 호출할 때 그 의존성을 파악하여 필요로 하는 모듈을 먼저 비동기적으로 다운로드 할 수 있게 해준다.

자바스크립트가 구리다는 말이냐?

이런 개념 부재가 다른 언어를 사용해온 개발자에게 불편을 주긴하지만, 이런 개념 부재로 인해 자바스크립트 개발자 스스로가 원하는 패턴으로 모듈 구조를 만들어가고 있다.

10년 전에 이런 종류의 기능이 만들어졌다면 어땟을지 상상해보라. 지금처럼 서버 사이드에서 동작하는 자바스크립트 애플리케이션이나, 브라우저에서 비동기적으로 리소스를 로딩하는 기술도 없고 RequireJS 같은 로더처럼 텍스트 템플릿으로 리소스를 추가하는 것과 어울리는 기술은 아니었을 것이다.

 

[제이쿼리] 매개변수가 있는 function을 HTML 엘리먼트에서 분리하기

매개변수가 없는 함수는 HTML에서 분리가 쉽습니다.

$(document).ready( function(){

    $(“#comment_add”).click(function() {
        $(“form”).submit();
    });

}

이런식으로 제이쿼리를 이용해서 click 이벤트가 발생했을 때 특정 폼을 서브밋하라고 이벤트를 등록할 수 있죠. 그러나;; 매개변수가 들어간 녀석들은 어떻게 할지 좀 난감합니다.

<img id=”btn_list” class=”action” src=”<c:url value=”/images/study/back.png”/>” onclick=”javascript:fn_click_study(${meeting.study.id});”/>

예를 들어 위와 같이 특정 함수에 어떤 변수 하나를 넘겨줘야하는데, 그 값이 매번 달라지고, 목록 속에 들어있는 모든 요소들에 대한 것이라.. 페이지 로딩시에 위와 같이 등록하기가 좀…

그래서 같이 스터디 하는 형 중에 제이쿼리를 유리갤라만큼 하시는 분이 계셔서 물어봤더니 다음과 같이 해결해 두셨더군요.

<img id=”btn_edit” class=”action” src=”<c:url value=”/images/study/edit.png”/>” member=”${meeting.study.id}” meeting=”${meeting.id})” />

이렇게 엘리먼트에 임의이 속성을 추가합니다. 이제 페이지 로딩시에 등록할 수 있습니다.

$(document).ready( function(){

    $(“#btn_edit”).click(function(){
        var self = $(this);
        var url = ‘<c:url value=”/study/”/>’ + self.attr(“study”) + “/meeting/update/” + self.attr(“meeting”) + “.do”;
        $(document).attr(“location”, url);

    });

}

아.. 그나저나 c:url 정말 악몽 같네요. 저거 없으면 context path가 루트여야만 제대로 동작하고.. @_@
아휴 귀차나.. ㅠ.ㅠ

[jQuery] 날짜 선택하기

jQuery UI 위젯이 제공하는 기본 달력은 다음과 같습니다.


흠.. 이것까진 간단했습니다. 이 것을 이용한 태그 파일 두개를 만들었습니다. 하나는 검색 필드용 하나는 폼 필드용. 검색 필드는 get 방식으로 url뒤에 줄줄이 붙여서 가져올 것이고 폼 필드는 post 방식에서 사용하여 model의 특정 속성에 바로 바인딩 할 겁니다. 둘 다.. 자바스크립트 코드 부분은 다음과 같습니다.

    $(function() {
        $(“#${id}”).datepicker({
            dateFormat: ‘yy/mm/dd’,
            changeMonth: true,
            changeYear: true,
            yearRange: ‘${fromNS}:${toNS}’
         });
    });

적당한 포맷을 설정하고, 연도와 달을 좀 더 변경하기 쉽게 드랍다운으로 설정했고, 연도 범위를 설정했는데, 이 값은 태그에 전달해준 값을 쓰기로 했습니다. 값을 전달해 주지 않으면 기본값을 쓰도록 했지요.

복잡한건, 날짜 범위를 선택하는 것인데, 이건 Ajaxian에서 10가지 date picker중 하나로 선정된 filament group의 daterangepricker를 이용했습니다.


    $(function() {
        $(“#${id}”).daterangepicker({
            dateFormat: ‘yy/mm/dd’,
            datepickerOptions: {
                changeMonth: true,
                changeYear: true,
                yearRange: ‘${fromNS}:${toNS}’
            }
        });
    });

대충 이렇게 보여집니다. 옵션이 다양해서 이 녀석을 써봤습니다. 문제는 하나의 필드에 두 개 날짜 값을 넣어주고 있어서 DateRange라는 클래스를 만들고, DateRangePropertyEditor도 만들어줬습니다. DateRange 클래스는 테스트를 통해서 문자열 값을 생성자에 넣어줬을 때 제대로 동작하는지 확인을 해보았고, DRPE를 등록해서 돌아가는지 웹에서 확인도 해봤습니다.

이 녀석은 검색용 태그파일만 만들었는데.. 만들고 보니 날짜를 한 개만 받는 녀석이랑 용도가 겹치더군요. Today랑 Specific Date는 메뉴에서 빼고 싶어서 옵션들을 살펴봤는데 영~~ 시원찮네요. 흠.. 뺄 수 있을텐데 말이죠.

[JQuery] J쿼리 이용해서 속성 값 변경하기, 엘리먼트 셀렉션, 이벤트 추가하기

attr을 사용하면 됩니다. 이전에 작성한 탭 만들기 글에서 a 엘리먼트의 onclick 속성을 사용하여, 자바스크립트 함수를 호출했었는데, J쿼리를 이용해서 그런 부분을 완전히 자바스크립트 쪽으로 떼어 낼 수 있게 되었습니다.

            $(document).ready(function() {
                $(“#topnav a”).bind(“click”, function () {
                    var id = $(this).parents(“li”).attr(“id”);
                    $(“body”).attr(“class”, id);
                });
            });

이 간단한 코드에 위 제목에서 언급한 모든 것들이 들어있습니다. 먼저, 이벤트 등록을 html에서 완전히 분리할 수 있게 도와주는 코드는 바로..

$(document).ready(function() {

});

이 녀석입니다. 이 안에서 이벤트 등록 작업을 해주면,

<a href=”#” onclick=”changeMenu(‘report’);”>

HTML에서 이런 코드를 작성하지 않아도 됩니다.

다음은 이벤트를 등록하는 코드입니다.

$(“#topnav a”).bind(“click”, function () {

});

그 전에 셀렉션을 보겠는데, #topnav a 이 부분은 topnav id를 가진 엘리먼트 하위의 a 엘리먼트를 모두 선택하라는 것입니다. API를 보면 더 다양한 방법들이 예제와 함께 잘 나와있습니다.

다시 이벤트 코드로 돌아가서 bind는 특정 이벤트에 어떠한 함수를 호출하도록 등록하는 함수인데, 이것을 특정 이벤트에 맞게 줄여서 다음과 같이 쓸 수도 있습니다.

$(“#topnav a”).click(function () {

});

간단하죠. click은 클릭하라는게 아니라 click 이벤트 핸들러를 등록하는 겁니다.

var id = $(this).parents(“li”).attr(“id”);

이 코드에서는 parents를 사용해서 자신을 감싸고 있는(여기서 자신은 사용자가 클릭한 a 엘리먼트겠죠.) 엘리머먼트 중에 li를 선택하고, 그 엘리먼트의 id 속성 값을 가져옵니다.

attr(속성이름)은 보시다시피 속성의 값을 가져오는 게터와 비슷합니다.

이와 반대로 세터 역할을 하는 함수도 역시 attr인데 사용법이 조금 다릅니다. 이번에는 인자를 하나 더 줍니다.

$(“body”).attr(“class”, id);

이렇게, attr(속성이름, 값) 형태로 사용하면 세터같이 동작합니다. 참~~ 편리하군요.

ps: 원래는 body의 class가 아니라 id를 변경하도록 코드를 작성했었는데, 잘 되지 않아서 class를 이용해봤는데 잘 동작하네요. 왜 그런지는 모르겠습니다. $(document).ready(function(){}); 이 것을 사용하지 않으면 id 변경도 잘 되는데 말이죠.. 저것과 관련이 있어 보입니다.