jQuery AOP Plug-in.
아하하핫. 공부 합시다.
내용을 살펴 보기 전에 관점지향 프로그래밍(Aspect Oriented Programming, 이하 AOP)이란
무엇인가에 대하여 간단히 알아 보도록 하겠습니다..
(AOP의 핵심, 횡단 관심사를 코드에서 분리)
AOP의 필요성을 이해하는 가장 기초가 되는 개념은‘관심의 분리(Separation of Concerns)’이다. 관심의 분리는 컴퓨터 프로그래밍의 가장 기초가 되는 원리 중 하나이다. 거의 모든 프로그래밍 패러다임은 바로 이 관심의 분리 과정을 통해 문제 영역(problem domain)을 독립적인 모듈로 분해한다. 절차적 프로그래밍에서는 분리된 관심을 프로시저로 구성하고 OOP에서는 이를 클래스로 작성한다. 여기서 AOP는 OOP를 적용한다고 할지라도 충분히 분리해 낼 수 없는 부분이 있다는 문제 제기에서 출발한다.
AOP에서 주목하고 있는 부분은 OOP와 같은 모듈화가 뛰어난 방법을 사용하더라도 결코 쉽게 분리된 모듈로 작성하기 힘든 요구사항이 실제 애플리케이션 설계와 개발에서 자주 발견된다는 점이다. AOP에서는 이를 횡단 관심(crosscutting concerns)이라고 한다. 이에 대비해서 해당 시스템의 핵심 가치와 목적이 그대로 드러난 관심 영역을 핵심 관심(core concerns)이라고 부른다. 이 핵심 관심은 기존의 객체지향 분석/설계(OOAD)를 통해 쉽게 모듈화와 추상화가 가능하다. 하지만 횡단 관심은 객체지향의 기본 원칙을 지키면서 이를 분리해서 모듈화하는 것이 매우 어렵다.
- http://www.zdnet.co.kr/ArticleView.asp?artice_id=00000039147106 기사 발췌-
자세한 내용은 위 기사를 확인 해 보시면 AOP가 무엇인지에 대하여 감을 잡으실 수 있습니다.
저도 감만 잡았지 확실하게 이해 하지는 못했습니다. -,.-
하지만 관심사의 분리가 가장 중요한 개념이라는 생각만 가지고 계시면 될 것 같습니다. ㅎㅎ;;;
그럼 AOP에 대해선 이정도만 알아 보고,
jQuery AOP에 대하여 알아보도록 하겠습니다.
사이트 : http://code.google.com/p/jquery-aop/
레퍼런스 : http://code.google.com/p/jquery-aop/wiki/Reference
레퍼런스를 확인해 보시면 알겠지만, 사용법이 대단히 간단 합니다.
before, after, around등을 지원 합니다.
그럼 샘플 코드를 살펴 보면서 AOP를 어떻게 적용 했는지 보도록 하겠습니다.
As-Is Script
$( '.moveFirst').click( function(){
if ( isClickAble( this))
return;
$( '#FavoriteList').children().remove();
getFavorite( publicUserType, 0);
});
$( '.moveLast').click( function(){
if ( isClickAble( this))
return;
$( '#FavoriteList').children().remove();
var page = ($( this).parent().find( '#currenPage').val() + 1) * $( this).parent().find( '#limit').val();
getFavorite( publicUserType, page);
});
$( '.movePrev').click( function(){
if ( isClickAble( this))
return;
$( '#FavoriteList').children().remove();
var page = ($( this).parent().find( '#currenPage').val() - 1) * $( this).parent().find( '#limit').val(); getFavorite( publicUserType, page);
});
$( '.moveNext').click( function(){
if ( isClickAble( this))
return;
$( '#FavoriteList').children().remove();
var page = ($( this).parent().find( '#currenPage').val() + 1) * $( this).parent().find( '#limit').val();
getFavorite( publicUserType, page);
});
음.. 이 Script를 보시면.. 뭔가 마틴 파울러란 사람이 말했던 bad smells in codes(http://en.wikipedia.org/wiki/Code_smell)...인가 그게 생각나지 않습니까?
-,.-;; 저도 생각나다 말았습니다. ㅋ_ㅋ
리팩토링 관점으로 본다면야, 아래 코드가 중복되어 있기 때문에 메서드로 추출해서 쓰면 되겠다.. 싶으실 껍니다. 하지만 이번엔 AOP적인 마인드로 생각을 해 보면.
아래의 코드는 비즈니스 로직과 관련이 없는 횡단관심사항인것으로 판단 할 수 있습니다.
그러니까 이 코드가 바로 AOP를 적용할 조인포인트(joinpoint)로 생각할 수 있습니다.
if ( isClickAble( this))
return;
// 페이징시 이전 페이징된 리스트들을 삭제.
$( '#FavoriteList').children().remove();
그럼 AOP를 적용하여 보도록 하겠습니다.
To-Be Script
$( '.moveFirst').click( function(){
movePageFirstHandler( this);
});
$( '.moveLast').click( function(){
movePageLastHandler( this);
});
$( '.movePrev').click( function(){
movePagePrevHandler( this);
});
$( '.moveNext').click( function(){
movePageNextHandler( this);
});
jQuery.aop.around({ target: window, method: /movePage*/},
function( invocation){
if ( isClickAble( invocation.arguments)) {
return null;
} else {
$( '#FavoriteList').children().remove();
invocation.proceed();
}
}
);
이렇게 바뀌게 됩니다!!
이 AOP 플러그인은 특정 메서드를 지정하거나, 정규 표현식을 사용해서 AOP를 걸 수 있습니다.
위 코드에서는 /movePage*/를 사용(정규식)해서 movePage로 시작하는 메서드들에 해당
around aop를 위빙(weaving)하고 있습니다.(정규식 테스트 사이트)
오우 사용 방법이 생각보다 어렵진 않습니다. AspectJ 나 SpringAOP에 비하면.. 쉬운것 같습니다.
Plus.
AOP를 적용하지 않았을 경우 발생할 수 있는 문제점.
AOP의 구성 요소
- AOP에는 새로운 용어가 많이 등장한다. 이 중에서 특히 AOP를 이용해서 개발하는데 필요한 중요한 구성요소들에 대한 정의를 정확히 이해해야 한다.
jquery jsonp에서 beforeSend
$.ajax({
이 경우 beforeSend는 동작 하지 않는다.
왜 그럴까?
If serviceUrl is on a different domain then your jsonp request will
not use ajax, and so beforeSend will not be called. x-domain jsonp
requests inject script tags into the document head.
하하하하하!!
다른 도메인으로 jsonp요청할땐 ajax가 아니라서
header에서 request정보가 없단다.
그래서 beforeSend를 사용할 수 없다.
ㅋㅋ
complete는 잘 동작함.
자바스크립트 AOP in Jquery.
jQuery로 구현된 자바스크립트 AOP.
이거 구현에 관해서는 조금 더 살펴봐야겠다.
어떻게 구현했는지..
다른 일반 JS AOP들을 보니깐 프로토타입 확장해서 어쩌구 하던데..
이거 관련해서는 자바스크립트 완벽 가이드 책 볼 것!!
AOP 관련해서, ajax 관련 메서드들을 실행할 때
ajax 옵션에 async: false 로 줘서 비동기를 동기 실행으로 바꿔서 실행 할 수 있도록 한다.
헙~~~이러면 ajax 의미와 일치하지 않네.. ㅋ
요청시간이 긴 것에는 사용하지 않도록 하자.
jQuery - Stringball TagCloud
위 사이트에서 확인 하실 수 있습니다.
http://codesign.verse.jp/jquery/ 여기를 방문하면 다양한 jQuery 플러그인을 볼 수 있습니다.
저기서 제공하는 플러그인은 단순히 태그 클라우드 구성만 해주기 때문에,
이 플러그인에다가 두 가지 기능을 추가했습니다.
- 태그에 마우스를 올릴 경우 회전 중지
- 태그를 클릭할 경우 태그명을 가지고 액션을 수행할 수 있도록 함
(사이트의 설명을 펌질 했습니다.)
・headへの記述
<script type="text/javascript" src="jquery-1.3.2.min.jsへのパス"></script> <script type="text/javascript" src="jquery.stringball.jsへのパス"></script> <script type="text/javascript"> $(function(){ $("ul#stringball").stringball({ camd:800, //ボールまでの距離です。 radi:250, //ボールの半径です。 speed:20 //回転スピードです。 }); }); </script>
・bodyへの記述
<ul id="stringball"> <li><a href="#">text1</a></li> <li><a href="#">text2</a></li> <li><a href="#">text4</a></li> <!--必要分liタグを繰り返し--> </ul>
ul로 구성된 html에다가 js에서 $("ul#stringball").stringball()을 지정해 주기만 하면 태그 클라우드가 구성 됩니다. 만약 태그를 동적으로 구성하고 싶다면 ul에다가 li를 동적으로 append 해줘야 겠죠.
ex :)
$.ajax({
url : 'someUrl',
type: 'post',
dataType : 'json',
success : function( data) {
$.each( data, function( val) {
$( '#stringball').append('<li><a href="#">val<a/></li>');
}
}
});
이렇게 태그 클라우드는 간단하게 구성 할 수 있습니다.
참 쉽죠잉~ 태그 플러그인 소스를 살펴 보아도...
사실 별다른 내용은 없고, 위치를 계산 하기 위한 소스가 대부분 입니다.
게다가 주석은 모두 일본어!!! 쿠왁!!
히라가나면 어찌 좀 보겠지만 한문은 무리.. ;
플러그인 안에는 두개의 함수가 있습니다.
- setini() - 초기 태그의 위치 값 들을 설정
- setpos() - 태그들의 위치를 설정
여기까지가 기본적인 StringBall에 대한 설명이고
추가로 들어간 기능에 대해서 알아 보도록 하겠습니다.
1. 태그에 마우스 올라간 경우 회전 중지
이 경우는 setini()에서 각 태그들의 위치를 설정 할 때,
해당 태그에 mouseover 했을 경우 태그의 스피드를 0으로 설정 하면 됩니다.
ex :)
//태그 위에 마우스 올라왔을때 회전 중지
$( elem[i]).mouseover(
function() {
speed = 0;
}).mouseout(
function() {
speed = realSpeed;
});
mouseout 했을 때는 이전 스피드로 복구하는걸 잊으시면 안되구요
2. 태그를 클릭할 경우 태그명을 가지고 액션을 수행할 수 있도록 함
이것도 setini()에서 태그를 클릭 할 때 수행말 함수를 지정해 주면
됩니다.
ex :)
//태그 클릭했을 때
$( elem[i]).click(
function() {
clickFunction( $( this).text());
});
태그를 클릭 했을 때 clickFunction 을 수행하도록 되어 있는데
clickFunction에 동작할 function을 지정해 주기
위해서는
ex :)
var target=$(this),
elem=$("li"
,target),
scrz=500,
radi=options.radi,
camd=options.camd,
speed=options.speed,
realSpeed=options.speed, clickFunction =
options.clickFunction;
이렇게 StringBall 소스를 수정 해야 합니다.
이렇게 수정 한 후, StringBall을 생성 할 때 사용할 함수를 지정해
주면 됩니다.
ex:)
// Tag cloud 생성
$(
target).stringball({
camd: 850,
radi: 100,
speed: 10,
clickFunction: getTagInfo
});
이렇게 하면 clickFunction에 getTagInfo라는 함수가 지정
됩니다.
여기까지 해서 간단하게 태그클라우드 플러그인을 사용하고 확장 하는 방법을
알아봤습니다.
예제소스를 첨부하오니 확인하시기 바랍니다. ^^
jQuery 플러그인 개발 방법.
http://docs.jquery.com/Tutorials:Getting_Started_with_jQuery
Plug me: Writing your own plugins
Writing your own plugins for jQuery is quite easy. If you stick to the following rules, it is easy for others to integrate your plugin, too.
Plugin Naming
Find a name for your plugin, lets call our example "foobar". Create a file named jquery.[yourpluginname].js, eg. jquery.foobar.js
Adding a Custom Method
Create one or more plugin methods by extending the jQuery object, eg.:
jQuery.fn.foobar = function() {
// do something
};
Which will then be accessible by performing:
$(...).foobar();
Default Settings:
Create default settings that can be changed by the user, eg.:
jQuery.fn.foobar = function(options) {
var settings = jQuery.extend({
value: 5, name: "pete", bar: 655
}, options);
};
You can then call the plugin without options, using the defaults:
$("...").foobar();
Or with some options:
$("...").foobar({ value: 123, bar: 9 });
Documentation
If you release your plugin, you should provide some examples and documentation, too. There are lots of plugins available as a great reference.
Now you should have the basic idea of plugin writing. Lets use this knowledge and write one of our own.
Checkbox Plugin
Something lots of people, trying to manipulate forms with jQuery, ask for, is checking and unchecking of radio buttons or checkboxes. They end up with code like this:
$(":checkbox").each(function() {
this.checked = true;
this.checked = false; // or, to uncheck
this.checked = !this.checked; // or, to toggle
});
Whenever you have an each in your code, you might want to rewrite that as a plugin, pretty straightforward:
jQuery.fn.check = function() {
return this.each(function() {
this.checked = true;
});
};
This plugin can now be used:
$(":checkbox").check();
Now you could write plugins for both uncheck() and toggleCheck(), too. But instead we extend our plugin to accept some options.
jQuery.fn.check = function(mode) {
// if mode is undefined, use 'on' as default
var mode = mode || 'on';
return this.each(function() {
switch(mode) {
case 'on':
this.checked = true;
break;
case 'off':
this.checked = false;
break;
case 'toggle':
this.checked = !this.checked;
break;
}
});
};
By providing a default for the option, the user can omit the option or pass one of "on", "off", and "toggle", eg.:
$(":checkbox").check();
$(":checkbox").check('on');
$(":checkbox").check('off');
$(":checkbox").check('toggle');
Optional Settings
With more than one optional setting, this approach gets complicated, because the user must pass null values if he wants to omit the first parameter and only use the second.
The use of the tablesorter in the last chapter demonstrates the use of an object literal to solve this problem. The user can omit all parameters or pass an object with a key/value pair for every setting he wants to override.
For an exercise, you could try to rewrite the Voting code from the fourth section as a plugin. The plugin skeleton should look like this:
jQuery.fn.rateMe = function(options) {
// instead of selecting a static container with
// $("#rating"), we now use the jQuery context
var container = this;
var settings = jQuery.extend({
url: "rate.php"
// put more defaults here
}, options);
// ... rest of the code ...
// if possible, return "this" to not break the chain
return this;
});
And allowing you to run the plugin like so:
$(...).rateMe({ url: "test.php" });
이번주에 해야 할 일.
jQuery 플러그인 개발에 대한 내용 정리 및
Fliker 플러그인 내용 역시 정리 할 것.
최소한 jQuery 플러그인 개발에 대해선 정리.
봄. 살짝 춥지만 아름다운.
혜윤아 미안~
얼마전에 읽은 웹 폼 디자인과 관련하야..
알티베이스 홈페이지를 방문했다.
음..
다운로드 할려면 회원 가입을 해야 한다.
왜 회원 가입이 필요하지??
문득 웹 폼 디자인 책이 생각났다..
웹 사이트에서 폼은 필수 지만 되도록 폼을 줄여야 한다.
다운로드하는데 솔직히 회원 정보는 필요가 없다.
회원 가입으로 넘어갔다.
음.
생년월일 및 자기 소개는 왜 필요하지?
이게 무슨 소셜 사이트인가..
회원 가입을 유도 할때 고객인지, 개발자인지 이런 양식에 따른 폼 양식을 나누어야 한다고 생각한다.
회원가입하고 다운로드받기가 귀찮아서 다른 링크를 찾아보는 사람도 있을 것이라 생각한다.
기분좋게 검색해서 다운로드를 클릭하면 다운로드 될꺼라 생각하는 잠재 고객들은
회원 가입하라는 폼 화면에 굉장히 불쾌감을 느낄 수도있다.
일이 지루하다.
프로젝트가 SM 성 성격이 강하다.
기존 C/S 환경을 마이플랫폼을 이용한 웹으로 바꾸는데...
우리쪽 제품은 이미 웹으로 되어있어서 기존 As-Is 테이블들을 To-Be테이블과 잘 동작하게 쿼리를 수정하는 작업이다.
뭐 내년에는 추가 개발이 있을 수도 있겠지만 ..
하암.. 뭐 여튼 너무 지루하다.
이건 뭐 스프링이랑 딴거 공부해도 써먹을 방법도 없고 -_-..
플렉스도 공부했던거 다 까먹을까봐. 요즘은 다시 책 보는 중.
비쥬얼 플렉스 UX 디자인.. 열이아빠 님이 번역하셨다고 하더라.
이거 보고.. 플렉스 에어 매쉬업 프로그램 책 보고
스프링 osgi & spring DM 보면 올해는 다 갈 듯.
내년에는 올해 공부한 플렉스 바탕으로 해서.
지금 제장 중인(멘토링에서 제작중인)사이트(스프링 2.5, jQuery, iBatis)에다가..
view를 지금 springMVC로 되어 있는데 이를 다 걷어 내고
플렉스로 덮어 씌워봐야겠다.
한 내년 3월 정도면 될것 같기도 하고...
이제 프로젝트가 5월 말 까지지...
봐서 스프링이나 플렉스 하는 쪽으로 이직을 고려해야겠다.
UX쪽으로 가면 좋으련만..ㅋㅋ
나름 재미 있는 사용자 경험 :)
jquery에 동적으로 이벤트 붙일 경우..
일반적으로 생각하면
for ( var i = 0; i < data.length; i++)
로 결과만큼 돌면서
$( '#element'+i).live( 'click', function() {
여기에 $( '#target'+i).hide()
이렇게 적용하면 될것 같지만 안된다..
});
맨 마지막꺼나 맨 처음것에만 적용이 되는데..
이런때는
$( '#target'+i).hide()이렇게 하지 말고
$( this).parent().parent().parent().parent().find( '#target').hide()
로 selector를 사용해서 타겟을 찾아낸 다음에 적용할 수 있도록 하자.
어우~~ css레이아웃은 머리 아파 ~_~
추가로.. ID는 고유한 것이기 때문에 반복문에서 target element를 생성하고 $( '#target').hide()이렇게 효과를 주지 말고 css class를 지정해서 selector로 css class를 검색 하여, 효과를 주자.