Clean Code that Works.

사내 멘토링 진행하면서 했던것 정리 용 'ㅁ'

원본은 http://codesign.verse.jp/jquery/2009/09/stringball.html
위 사이트에서 확인 하실 수 있습니다.
http://codesign.verse.jp/jquery/ 여기를 방문하면 다양한 jQuery 플러그인을 볼 수 있습니다.
 
저기서 제공하는 플러그인은 단순히 태그 클라우드 구성만 해주기 때문에,
이 플러그인에다가 두 가지 기능을 추가했습니다.
  1. 태그에 마우스를 올릴 경우 회전 중지
  2. 태그를 클릭할 경우 태그명을 가지고 액션을 수행할 수 있도록 함
간단하게 플러그인에 대한 설명을 하면
(사이트의 설명을 펌질 했습니다.)

・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() - 태그들의 위치를 설정
그리고 마우스가 태그 클라우드에 hover 했을때 동작하도록 하는 이벤트가 있습니다.
 
여기까지가 기본적인 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라는 함수가 지정 됩니다.

 

여기까지 해서 간단하게 태그클라우드 플러그인을 사용하고 확장 하는 방법을 알아봤습니다.

예제소스를 첨부하오니 확인하시기 바랍니다. ^^


참고 할 것.
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" });

결과를 json으로 받아서 js로 html작성 하여 이벤트를 붙일 경우..

일반적으로 생각하면
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를 검색 하여, 효과를 주자.

http://codesign.verse.jp/jquery/

일본인 개발자의 jQuery플러그인.
오우. 깔끔하고 좋네!!!!!

멋지다!!

굿굿굿.!

It's awesome!!


jQuery를 이용한 링크가 죽었는 살았는지 체크하는 라이브러리입니다.
원본 주소 : http://plugins.jquery.com/project/linkchecker

원본은 예제가 php기준으로 되어 있어서 jsp로 바꾸었습니다.
이걸 쓰실려면 사이트에 맞게 바꿔 주어야 합니다.
한시간동안 날림으로 만든거라서..-,.-;;

그냥 jsp로 요청을 날려서 사이트가 살아 있으면 200, 죽으면 404를 가지고 있는 html을 리턴 합니다.
이걸 가지고 찾아서 링크의 css클래스를 변경하는 방법입니다.

이걸 쓸려면 아마 서버단에서 처리하고 json 형태로 결과를 리턴 받아서 이걸 가지고 처리하는게 더 좋겠죠 'ㅁ'
==============
조금 수정해서 json으로 값 리턴하게 변경.
function checkLinks(urls, settings, jLinks) {
  $.getJSON(settings.checkScript, {'links':urls, 'timeout':settings.timeout}, function(data)
  {
  for ( var i = 0; i < data.length; i++)
   {
    jLinks.filter('[href^='+ data[i].url + ']').addClass(data[i].code == 200 ? settings.activeClass : settings.inactiveClass);
   }  });
 }




주말에 해야할 포스팅.

ExtJs에 JSON 형태의 값을 리턴하기 위하여
SpringMVC에서 어떻게 값을 만들어서 리턴 해야 하는지.

필요 lib :
  • json-lib-2.2.3-jdk15.jar
  • commons-lang
  • commons-collections
  • commons-beanutils
환경
  • eclipse 3.4
  • spring 2.5
  • IE 7

컥.. 0,.0
주말에 머했지!
그냥 슝 지나갔네.. ㅠ_ㅠ

내일 점심 때 포스팅 합시다.



http://docs.jquery.com/Tutorials:Using_Ext_With_jQuery

구글 그룹에 답변 : 바로 가기

a) jquery.js
b) dimensions-plugin
c) other possible jquery-plugins you might want to use
d) the Ext jQuery Adapter script. This is in your ext-directory which you
just uncompressed earlier, at ext-1.0\adapter\jquery\ext-jquery-adapter.js
e) Include the main Ext javascript-file, ext-1.0\ext-all.js

6) Include the necessary css-eye-candy
Please note that the Ext css-files reference images inside the ext-folder,
so I wouldn't carelessly move them around.
a) The ext base css from: ext-1.0/resources/css/ext-all.css
b) Pick a theme, for Dark Vista: ext-1.0\resources\css\ytheme-vista.css
(there is also ytheme-aero.css and ytheme-gray.css, didn't try em out yet).

7) Like all l33ts just skip the tutorials and jump right into mixing jQuery
with Ext:

내일 회사 가면 해보자.

오.. 신기해.. =ㅁ=

Jquery 공부한지도 얼마 안됬는데 .... OTL.

extjs 도 번역서좀 굽신.

구글에 jquery dialog button focus 이렇게 검색 하였더니.
아래와 같은 결과가..

 Why is the dialog Close icon focused when opening the dialog?
I would like to have it not focused when the dialog opens.
Is there a way to make that happen?
Thanks,

 이렇게 질문한 사람이 있었다.
이것에 대한 답변으로


In rc5 and previous releases the logic was:
find the first tabbable element in the dialog and give it focus on
open.

In current SVN the logic is:
find the first tabbable element in the following order:
- content area
- button pane
- title bar
and give it focus on open.

This is done for accessibility to ensure that the dialog has focus
when opened.  We may change the logic after doing some testing to
focus the actual dialog div if the close button is what would receive
focus.

뭐 맨 윗줄 보면 처음 탭 이동이 가능한 엘리먼트를 다이얼 로그를 열때
포커스를 얻는다고 되어 있다.

이를 해결하기 위해 다이얼로그를 열때 포커스를 직접 지정해 주어야 한다.

You can try this:
$("#dialog").dialog({
    open: function() {
        $(this).parents('.ui-dialog').attr('tabindex', -1)[0].focus();
    }
});

이렇게.


위의 방식대로 하게 되면 버튼 자체에 포커스가 사라져 버린다.
ui.dialog.css 파일을 보면 text-align: 이 left로 되어있다. 이걸 center로 변경 하고
.ui-dialog .ui-dialog-buttonpane { text-align: center; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; }
그 밑에 라인을 보면 float: right로 되어있다. 이게 버튼 창을 오른쪽으로 밀게 되어있다.
.ui-dialog .ui-dialog-buttonpane button { float: none; margin: .5em .4em .5em 0; cursor: pointer; padding: .2em .6em .3em .6em; line-height: 1.4em; width:auto; overflow:visible; }

이렇게 하면 가운데 정렬에 (확인), (취소) 버튼 순서대로 나오고 (확인) 버튼에 포커스가 있는것을 확인 할 수 있다.


스트럿츠2 액션 요청을 전부다 ajax로 처리 하기 위하여 jquery를 도입했다.
파일 업로드 같은 경우는 스트럿츠2에 인터셉터로 통해 파일 업로드를 지원하는데.
멀티 파일 업로드는 ajax로 폼을 전송하였을 때는 값이 넘어 가지 않아서 처리하기가 곤란하다.

이전에는 프로토타입을 도입하여 ajax요청을 처리 하였는데.
멀티파일 업로드를 ajax로 처리하기 위하여 프로토타입을 걷어 내고 jquery로 ajax요청을 처리 하였다.

필요한 라이브러리
jquery.js : jquery core 라이브러리
jquery.form.js : form 을 ajax로 submit 하기 위한 라이브러리 
jquery.MultiFile.js : 멀티파일 업로드 구현을 위한 라이브러리

간단한 구현 시나리오를 살펴보면
멀티파일 업로드 뷰를 구현하고(html)
이를 전송하기 위한 폼 전송 메서드를 구현하고(javascript)
전송한걸 처리하는 actionclass를 구현하면 된다.

그럼 html 부분 부터 살펴보자.

<s:form action="fileUpload" id="fileUpload" method="post" enctype="multipart/form-data">
    <s:file name="file" label="File" id="file" cssClass="multi"/>
    <s:submit/>
</s:form>

아주 간단하다.
그냥 type="file" 인 태그에 class를 multi로 지정해 주면 된다.
일반 html 태그는 <input type="file" name="file" id="file" class="multi">로 지정해 주면 된다.

옵션으로는 class에 지정해 주거나, 속성으로 지정 가능하다.
class="multi max-4 accept-jpg|gif" => 업로드 4개로 제한, jpg, gif 제한
속성으로 지정 하는 방법은 위의 다운로드 사이트를 참고 하길 바란다.
다양한 예제가 준비 되어 있다.

여기까지는 단순히 뷰만 구현되어 있고.
이를 처리 하기 위한 ajax와 액션 클래스를 구성해야 한다.

그럼 ajax 부분 부터 살펴보자.

$(document).ready( function() {
 var options = {
         target:        '#output2',   // target element(s) to be updated with server response
         beforeSubmit:  showRequest,  // pre-submit callback
         success:       showResponse,  // post-submit callback
 
         // other available options:
         url:       'fileUpload.action'         // override for form's 'action' attribute
         type:      'post'        // 'get' or 'post', override for form's 'method' attribute
         //dataType:  null        // 'xml', 'script', or 'json' (expected server response type)
         //clearForm: true        // clear all form fields after successful submit
         //resetForm: true        // reset the form after successful submit
 
         // $.ajax options can be used here too, for example:
         //timeout:   3000
     };
 
     // bind to the form's submit event
     $('#fileUpload').submit(function() {
         // inside event callbacks 'this' is the DOM element so we first
         // wrap it in a jQuery object and then invoke ajaxSubmit
         $(this).ajaxSubmit(options);
 
         // !!! Important !!!
         // always return false to prevent standard browser submit and page navigation
         return false;
     });
});

 
// pre-submit callback
function showRequest(formData, jqForm, options) {
    // formData is an array; here we use $.param to convert it to a string to display it
    // but the form plugin does this for you automatically when it submits the data
    var queryString = $.param(formData);
 
    // jqForm is a jQuery object encapsulating the form element.  To access the
    // DOM element for the form do this:
    // var formElement = jqForm[0];
 
    alert('About to submit: \n\n' + queryString);
 
    // here we could return false to prevent the form from being submitted;
    // returning anything other than false will allow the form submit to continue
    return true;
}
 
// post-submit callback
function showResponse(responseText, statusText)  {
    // for normal html responses, the first argument to the success callback
    // is the XMLHttpRequest object's responseText property
 
    // if the ajaxSubmit method was passed an Options Object with the dataType
    // property set to 'xml' then the first argument to the success callback
    // is the XMLHttpRequest object's responseXML property
 
    // if the ajaxSubmit method was passed an Options Object with the dataType
    // property set to 'json' then the first argument to the success callback
    // is the json data object returned by the server
 
    alert('status: ' + statusText + '\n\nresponseText: \n' + responseText +
        '\n\nThe output div should have already been updated with the responseText.');
}

컥 길다.. -_-..showRequest, showResponse는 각각 콜백 함수임으로 별다른 설명은 하지 않겠다.
동작 원리를 살펴보면 폼의 submit을 새로운 함수로 바인딩해서
submit이 jQuery.form 에서 제공하는 ajaxSubmit()으로 실행 되도록 하는것이다.
jQuery.form 역시 해당 다운로드 사이트에 보면 완벽한 예제를 제공 하고 있다.

$(this).ajaxSubmit(options);
를 통해 ajax를 요청한다.

이제 파일 업로드를 구현 해야 한다.
fileUpload.action으로 액션을 요청 하는데.
스트럿츠2에서는 파일 업로드를 위한 인터셉터(fileUpload)를 제공한다.

스트럿츠 설정 파일인 strut.xml에 다음과 같이 액션매핑을 설정한다.

<action name="fileUpload" class="tutorial.FileUpload">
         <interceptor-ref name="fileUpload"/>
         <interceptor-ref name="basicStack"/>
         <result>index.jsp</result>
</action>

그 다음에 실제 파일을 업로드할 FileUpload클래스를 작성해주면 된다.

private File[] upload;
private String[] uploadContentType;
private String[] uploadFileName;
// 각 필드 get/setter 필요    
public String execute() throws Exception
{
       // 톰캣의 임시 폴더에 올라가 있는 파일을 서버에 저장하기 위한 로직이 필요.
       return SUCCESS;
}


위와 같이 액션 클래스를 작성해주고 디버깅을 실행해 주면 upload 변수에 임시서버에 올라간 파일명을 확인 할 수 있다. 이를 가지고 실제 서버에 파일을 쓰는 로직을 작성해 주면된다.

위와 같이 작성해 주면 ajax를 통해 파일 업로드를 수행 할 수 있다.
이것을 사용한 이유는 액션을 수행하고 나서(파일 업로드 후 디비에 파일 관련 정보 저장)
새로고침을 했을 경우 액션 url이 남아 있어서 해당 액션이 다시 수행되는 경우가 발생하였기 때문에
브라우저 url을 변경하지 않고 액션을 수행하기 위하여 이를 작성하였다.

물론 내 레벨이 낮기 때문에
이 포스트 수준역시 낮은 편이며.
아마도 액션을 다시 수행하는것을 막는 방법이 struts2에 존재할 것 같다.

jquery를 사용하여 RIA 애플리케이션 개발자에게 도움이 되었으면 좋겠다.
ps. 파일 쓰는 로직 및 파일들을 다시 작성하여 war 형태로 첨부 할 예정.

파일 트리 데모

캬.. 이거 멋진데..

그런데 이걸 가져다 쓰면 한글 폴더는 열리지 않는데...

이게 왜냐 하면.. JQuery는 파라미터를 전송할 때
encodeURIComponent 로 인코딩해서 utf-8로 전송한다.

그럼 서버 측에서
받아서 쓰면 되는데...

파일 트리를 쓰기 위해선 jqueryFileTree.js 파일을 수정해야 한다.
왜냐!!!
저 파일에서는 encodeURIComponent인코딩이 아니라 escape()로  인코딩을 하기 때문에..
escape()와 encodeURIComponent()의 차이점은..
escape는 조금만 변화하고 encodeURIComponent는 많이 -ㅅ-...

여튼 jqueryFileTree.js 파일을 열어 보면 escape를 두번 쓰고 있을 것이다.
이걸 encodeURIComponent로 바꿔주면.. 무리없이 트리메뉴를 쓸 수 있다.

오...신기해 -ㅅ-...