http://newism.com.au/blog/post/58/bigtarget-js-increasing-the-size-of-clickable-targets/

Say goodbye to boring ‘Read More…’ links by turning your entire content block into a clickable target!

With all the positive focus on grid based web design these days, I started to identify a couple of standard design elements. The main pattern used in nearly every site (grid and non grid) was the “title, thumbnail, short summary, more link” pattern. This pattern is generally used for indexing blog post summaries in sidebars, listing services, or creating small calls-to-action.

The XHTML markup generally looks something like this:

<div>
<h3><a href="http://leevigraham.com/">Title</a></h3>
<a href="http://leevigraham.com/"><img src="thumbnail.png" alt="thumbnail" /></a>
<p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
<a href="http://leevigraham.com/">Read More …</a>
</p>
</div>

One thing that always bugged me when implementing the code above, wasn’t necessarily the number of links inside a small block of content, it was the fact that only those small bits of sporadic content were clickable. Sure it’s not that hard for the user to hover over one of the three links, but I thought the user experience could be improved.

My feeling was that a user should be able to click anywhere in the content and navigate through to the target page — basically making the whole content block one big link.

Improving usability and the user experience with jQuery

Wrapping a single anchor around the whole content (title, thumbnail, summary) is a bad idea as it’s not standards compliant and renders the page invalid. So I turned to my good friend jQuery and threw together the following plugin using the ‘Learning jQuery’ plugin development pattern.

The concept is simple:

  1. Attach the plugin to any link in the content block.
  2. Pass through the click zone selector as a plugin option.
  3. The plugin then attaches onclick and hover events to the click zone.
  4. User clicks anywhere on the click zone.
  5. The original link href is retrieved.
  6. If the link has a rel attribute and it’s set to ‘external’, open the link target in a new window; otherwise open the link in the current browser window.

A working example

A list of entries without bigTarget.js applied

  1. Example Title 1

    thumbnail

    Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Morbi tempor posuere libero. In fringilla magna ut urna elementum condimentum. Aliquam erat volutpat. Fusce odio. Read More …

  2. Example Title 2

    thumbnail

    Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Morbi tempor posuere libero. In fringilla magna ut urna elementum condimentum. Aliquam erat volutpat. Fusce odio. Read More …

  3. Example Title 3

    thumbnail

    Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Morbi tempor posuere libero. In fringilla magna ut urna elementum condimentum. Aliquam erat volutpat. Fusce odio. Read More …

A list of articles with bigTarget.js applied

  1. Example Title 1

    thumbnail

    Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Morbi tempor posuere libero. In fringilla magna ut urna elementum condimentum. Aliquam erat volutpat. Fusce odio. Read More …

  2. Example Title 2

    thumbnail

    Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Morbi tempor posuere libero. In fringilla magna ut urna elementum condimentum. Aliquam erat volutpat. Fusce odio. Read More …

  3. Example Title

    thumbnail

    Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Morbi tempor posuere libero. In fringilla magna ut urna elementum condimentum. Aliquam erat volutpat. Fusce odio. Read More …

bigTarget.js

Now you know what bigTarget.js does, you’ll probably want to grab the code and start using it on your site.

Usage

Adding bigTarget.js functionality to your site is straight forward. First include the plugin code in the head of your document, and then when the page is ready, attach the bigTarget function to the target anchor — bigTarget.js will do the rest.

$(document).ready(function(){
$("ol.bigTarget h4 a").bigTarget();
});

Customising the hoverClass and clickZone

There are two options to further customise how bigTarget.js works — clickZone and hoverClass. By default, bigTarget.js will turn the first parent <li> tag of the target anchor into the click zone using li:eq(0) as the parent selector. The plugin will also add the class ‘hover’ to the click zone element.

This is fine for cases when your content is a series of ordered or unordered list elements. However you may prefer to use a series of <div> tags as the click zone elements and apply the class ‘over’ when the user hovers over the element. To do this just pass the options to the function like so:

$(document).ready(function(){
$("ol.bigTarget h4 a").bigTarget({
hoverClass: 'over', // CSS class applied to the click zone onHover
clickZone : 'div:eq(0)' // jQuery parent selector
});
});

The code

The plugin code for bigTarget.js is short and sweet.

Paste the code below into a new file called jquery.bigtarget.1.0.1.js or download it from here, then add a <script src="jquery.bigTarget.js.1.0.0" type="text/javascript"></script> to the <head> of your document before calling the bigTarget() method on the selected elements.

// bigTarget.js - A jQuery Plugin
// Version 1.0.1
// Written by Leevi Graham - Technical Director - Newism Web Design & Development
// http://newism.com.au
// Notes: Tooltip code from fitted.js - http://www.trovster.com/lab/plugins/fitted/

// create closure
(function($) {
// plugin definition
$.fn.bigTarget = function(options) {
debug(this);
// build main options before element iteration
var opts = $.extend({}, $.fn.bigTarget.defaults, options);
// iterate and reformat each matched element
return this.each(function() {
// set the anchor attributes
var $a = $(this);
var href = $a.attr('href');
var title = $a.attr('title');
// build element specific options
var o = $.meta ? $.extend({}, opts, $a.data()) : opts;
// update element styles
$a.parents(o.clickZone)
.hover(function() {
$h = $(this);
$h.addClass(o.hoverClass);
if(typeof o.title != 'undefined' && o.title === true && title != '') {
$h.attr('title',title);
}
}, function() {

$h.removeClass(o.hoverClass);
if(typeof o.title != 'undefined' && o.title === true && title != '') {
$h.removeAttr('title');
}
})
// click
.click(function() {
if(getSelectedText() == "")
{
if($a.is('[rel*=external]')){
window.open(href);
return false;
}
else {
//$a.click(); $a.trigger('click');
window.location = href;
}
}
});
});
};
// private function for debugging
function debug($obj) {
if (window.console && window.console.log)
window.console.log('bigTarget selection count: ' + $obj.size());
};
// get selected text
function getSelectedText(){
if(window.getSelection){
return window.getSelection().toString();
}
else if(document.getSelection){
return document.getSelection();
}
else if(document.selection){
return document.selection.createRange().text;
}
};
// plugin defaults
$.fn.bigTarget.defaults = {
hoverClass : 'hover',
clickZone : 'li:eq(0)',
title : true
};
// end of closure


1/1/08 8:51am — I have updated some of the plugin code for legibility and added a tooltip based on the work of Trevor Morris.

1/1/08 8:51am — My good friend Trovster (Trevor Morris) has independently published fitted.js which achieves the same goals as bigTarget.js in a slightly different manner.


})(jQuery);

Go forth and embiggen

bigTarget.js is a simple to use jQuery plugin that will give your visitors a better online experience. If you have any questions or feedback about bigTarget.js leave them in the comments below. If you find it useful, spread the bigTarget.js love through your preferred social network below.


by Anna 안나 2009. 2. 23. 17:31
16+ Top JavaScript/Ajax Effects for Modern Web Design 웹 개발자, 웹 디자이너를 위한 16가지의 자바 스크립트 / Ajax 효과 Aug 06, 2008, by Mohsen as Javascript/AJAX These days, I’m designing a new Wordpress theme for aComment. new logo, new design, more features and a better dress!The coding of the theme is nearly finished and just some minor details should be added. Okay, this post is related to JavaScript and its friends!
Currently there are a lot of JS scripts available for web developers. But all of them are not handy in the modern web design. Nowadays, web designers use some special effects more and more in their projects because those effects give usability and practicality as well as elegance to their projects. In this list, I’ve selected some of the most common in use JavaScript effects for modern web design.


1 - Easiest Tooltip and Image Preview Using jQuery - A clean and easy to use jQuery tooltip & image preview script (마우스 롤 오버 툴팁 및 이미지 미리보기) 2- jQuery idTabs - These days using tabs in Wordpress themes and websites is common. iTabs is a plugins for jQuery that makes adding tabs to a website really simple. (탭 기능 플러그인)
3- Coda-Slider - A jQuery plugins for tabs with sliding animation (슬라이딩 탭?)
4- prettyPhoto a jQuery lightbox clone - A very beautiful lightbox for images with next/previous buttons, caption and preload animation for both single images and galleries. (이미지 갤러리)
5- Glass Box - GlassBox is a compact Javascript User Interface (UI) library, which use Prototype and Script.aculo.us for some effects. With GlassBox you can build transparent border, colorful layouts and “Flash-like” effects. The GlassBox library .. (UI 라이브러리)
6- SimpleModal Dialog Box - it comes with 3 example, basic dialog box, contact form and confirm override. 7- CSS Text Gradient - “Text Gradient is a simple css trick that allows you to improve your site’s appearance by putting gradients on system font titles using nothing but css and a png image.” (텍스트 그레디언트 효과) 8- Simple Javascript Accordions - is a very small JS accordion script which is really handy in today’s web projects. 9- Custom JavaScript Dialog Boxes - “The script currently offers four dialog styles: alerts, warnings, prompts and success. There is nothing to add to your page except references to the JavaScript and CSS if you choose not to incorporate them in your existing files.” (커스텀 다이얼로그 박스) 10- Dynamic JavaScript Form Validation - It’s clear:) (자바스크립트 동적 폼 검사) 11- jQuery Lightbox Plugin (balupton edition) - another jQuery lightbox plugins with only 15KB size
12- AutoCompleter - This AutoCompleter script for MooTools provides the functionality for text suggestion and completion. It features different data-sources (local, JSON or XML), a variety of user interactions, custom formatting, multiple selection, animations and much more. (폼 자동 완성기능) 13- Top Floating message box using jQuery - This effect will be useful for advertising, hot news, etc 14- Easy AJAX inline text edit 2.0 - an easy to integrate inline text edit script. No JavaScript knowledge needed, just follow the five steps for integration. 15- Create site tours with Amberjack - Amberjack is a lightweight Open Source library, enabling webmasters to create cool site tours. 16- Accordion Menu script - It became really easy to make accordion menu using this script. 17- Create a Slick Tabbed Content Area using CSS & jQuery - Finally, this tutorial from NETTUTS demonstrates how to create a slick tabbed content area for your themes. You see tabbed content boxes in a lot of websites these days specially in Wordpress themes. 자바스크립트와 AJAX를 이용한 다양한 플러그인들. 실제 웹 개발에 유용하게 사용될 수 있는 것들이 모아져 있다. 이런 라이브러리들을 활용해서 좀 더 멋진 웹 사이트를 만들 수 있겠군..
by Anna 안나 2009. 1. 4. 21:33
웹사이트를 만들면서 풀다운메뉴나 Context메뉴를 한번쯤 만들어봤을것 같다.
div로 메뉴를 구성하고 마우스이벤트를 걸어 style.display=block, style.display=none 을 적절히 구현해하면 이런한 기능을 만들어낼수 있는다.
문제는 웹화면에서 레이어가 덮지 못하는 것이 존재한다.
Window를 넘기 못한다. 브라우져의 속으로 숨는다.
<frame>을 넘지 못한다. (<iframe> 덮어진다) 화면이 프레임으로 나눠져 있을 경우 자기가 속한 페이지에서만 보이고 넘어가는 부분은 속으로 숨는다.
이런 이유로 메뉴가 content페이지에 include형태로 매번 따라다닐 것이다.
<select>를 덮지 못한다. <select>의 특성상(내용이 펴서 보여줘야함) zIndex가 높게 설계가 되어 있어서 레이어가 구멍이 생기면서 select box가 보인다.
이걸 처리하려면 레이어에 걸치는 select box를 숨겨야한다.(코딩이 만만치 않음) <object>를 덮지 못한다. ActiveX의 화면에 보여지는 부분(그래프를 보여주는 화면이나 Windows Media Player)도 그 속으로 레이어가 숨는다. 위와 같은 많은 문제를 해결하기 위해 찾던 중 괘 유용한 사이트가 존재하여 소개할까 한다. http://webfx.eae.net/dhtml/dhtmlmenu4/iemenustructure.html URL을 클릭하여 데모를 보면 select뿐만 아니라 window틀 바깥에까지 나가는 걸 볼수 있다.
위 사이트에 있는 메뉴는 정말 막강하나 메뉴디자인이 너무 윈도우프로그램 같아서 일반 웹사이트에 적용하기는 어려울것 같다.
그래서 원리만 참조하고 새로 만들어서 각자 적용해보는게 낫지 않을까 싶다.
이 사이트에서도 설명이 있는데 방법은 window.createPopup() 에 있다.
http://msdn.microsoft.com/library/default.asp?url=/workshop/author/dhtml/reference/methods/createpopup.asp createPopup()으로 생성된 popup객체는 하나의 window객체다. (마치 window.open()으로 띄워진 새창처럼) 그래서 표시되는데 화면의 다른것에 영향을 받지 않는다. 그리고 자기 영역외의 곳을 클릭하면 자동으로 사라진다. popup객체를 이용할 경우 주의점 몇가지가 있다. 1. window.open()처럼 별도로 페이지를 둘수 없어 document.innerHTML로 내용을 세팅해줘야 한다. 2. 내용을 세팅되도 js나 css는 이미 떠 있는 상태이기 때문에 적용이 되지 않으므로 별도의 메소도로 추가시켜야한다. document.createStyleSheet('css/menu.css'); 3. 하나의 window는 하나의 popup만 가질 수 있다. window.createPopup()을 2번하면 이전 popup은 사라진다. 풀다운메뉴처럼 하위에 하위 메뉴가 나올려면 window.createPopup()로 띄운 popup객체의 window에서 createPopup()을 해야한다. 이상을 참고하여 한번 만들어보길 바란다. 그리고 webfx.eae.net 사이트의 xtree도 유용하게 사용할 수 있을것 같다. http://webfx.eae.net/dhtml/xtree/demo.html 윈도우탐색기처럼 방향키로도 탐색이 가능하며 사용법도 간단하고 script로 추가,삭제가 가능하여 메뉴외에 다른곳에도 응용할수 있을것 같다. 이외에도 다른것들 많이 있으니 한번씩 둘러보길 바란다. script로 이렇게 만들수 있다는게 대단하고 신기하기만 하다. ========================================================================= http://www.javajigi.net에서 허종진 님이 올려주신 글입니다^^ 신기하네용 ㅋㅋ 저도 개발할때 한번 써봐야겠습니다
by Anna 안나 2008. 10. 24. 18:41
<SCRIPT LANGUAGE="JavaScript">
<!--
var screenWidth;
var screenHeight;

if (navigator.appName.substring(0,9) != "Microsoft" && navigator.javaEnabled()) {
var toolkit = java.awt.Toolkit.getDefaultToolkit();
var screen_size = toolkit.getScreenSize();
screenWidth = screen_size.width;
}
else {screenWidth = screen.width;}
if (screenWidth <= 800) {screenWidth = 800;}
else
if (screenWidth <= 1024) {screenWidth = 1024;}

else
if (screenWidth <= 1152) {screenWidth = 1152;}
else
if (screenWidth <= 1280) {screenWidth = 1280;}
else
if (screenWidth <= 1600) {screenWidth = 1600;}

document.write("</head><body background="+screenWidth+".jpg>");


//-->
</SCRIPT>



-------------------

위 소스를 (head)와(/head)사이에 삽입합니다.

배경화면 파일명은 800.jpg, 1024.jpg, 1152.jpg, 1280.jpg, 1600.jpg 등으로 각 해상도에

맞추어서 만든뒤 위 소스가 삽입된 html파일과 같은 디렉토리에 넣어둡니다.



------------------

필요하면 1360같은 해상도도 소스를 추가 할 수 있습니다. (1600상위 해상도 등..) http://sir.co.kr/bbs/board.php?bo_table=g4_qa&wr_id=65161.
by Anna 안나 2008. 10. 17. 23:37
페이지 스크롤에 따라서 부드럽게 움직이는 레이어. 보통 화면 상단으로 올라가는 탑버튼이나 퀵메뉴, 윙배너 구현에 사용된다. IE6, IE7, FF2, Opera9, Safari3에서 테스트 완료. 위치(position)값이 양수이면 브라우저의 상단으로 부터의 거리, 음수이면 하단으로 부터의 거리로 계산이 된다. HTML 소스 <div id="gotop">
<a href="#head" title="상단으로"><img src="/images/nav/top.gif" alt="Top"></a>
</div>
<script type="text/javascript">initMoving(document.getElementById("gotop"), 66, 66, 250);</script> 개선할점 온로드(onload)시에 적용 : 온로드 이전에 적용하면 페이지 높이가 충분하지 않아서 하단쯤에 이동이 잘 되지 않는 경우가 발생 %단위 입력 참고링크 W3C DOM Compatibility - CSS Object Model View http://hyeonseok.com/pmwiki/index.php/Javascript/SmoothMovingLayer
by Anna 안나 2008. 7. 29. 15:54
http://dean.edwards.name/IE7/ 에 가시면 IE7, 8 라이브러리의 오픈소스 프로젝트 진행현황도 보실 수 있으며 현재까지 개발된 IE7, IE8 라이브러리도 배포하고 있습니다. 현재로써 최신 버전은 2.0이며 지금 가보니 Beta 1, 2, 3으로 나뉘어 있네요. 아무거나 쓰셔도 상관없습니다. http://forum.standardmag.org/viewtopic.php?id=1987
by Anna 안나 2008. 7. 29. 15:45
input box 위에 마우스 올리면 위 텍스트가 작은 창같이 떠서 그중에서 클릭하면 그 값이 input box 에 들어가도록 해주는 자바스크립트입니다. ※셀렉트박스가 아니지만, 셀렉트박스와 비슷한 기능을 내게 하는 것이랍니다.
-다른소스 <HTML>
<HEAD>
<TITLE> </TITLE>
<script>
function test(){
html = " <table width='200' cellpadding='1' cellspacing='1' bgcolor='#58aeca'>"
+ " <tr> "
+ " <td valign='bottom' bgcolor='#e0f6fd'><a href='javascript:setup(1);'>사과</a> | <a href='javascript:setup(2);'>바나나</a> | <a href='javascript:setup(3);'>수박</a></td>"
+ " </tr>"
+ " <tr> "
+ " <td align='right' valign='bottom' bgcolor='#e0f6fd'><a href='javascript:divClose();'>[닫기]&nbsp</a></td>"
+ " </tr>"
+ " </table>"

oElement = document.elementFromPoint(event.x, event.y); //마우스가 움직일때의 대상객체

prevcontent.style.display=''; //레이어를 보이고
prevcontent.style.visibility = "visible";
prevcontent.style.pixelLeft=event.x-100; //레이어의 가로 위치지정
prevcontent.style.pixelTop=document.body.scrollTop+event.y; //레이어의 세로위치 지정
prevcontent.innerHTML=html; //레이어의 내용 출력
}
function divClose(){
prevcontent.style.display='none';
prevcontent.style.visibility = "hidden";
} function setup(tmp){
//값을 셋업하는 부분입니다. 사실 위쪽에 html부분을 수정하면 바로 값을 받아서 셋팅할수도 있겠지요.
var f = document.f1;
if(tmp==1){
f.text1.value="사과";
}else if(tmp==2){
f.text1.value="바나나";
}else if(tmp==3){
f.text1.value="수박";
} }
</script> </HEAD> <BODY>
<div id="prevcontent" style="visibility:hidden;position:absolute;left:10;top:10;background:white;filter:alpha(opacity=90);border: 1px solid;padding:2 2 2 2"></div>
<form name="f1">
<a href="#" onmouseOver="test();"><input type="text" name="text1"></a>
</form>
</BODY>
</HTML>
http://kin.naver.com/detail/detail.php?d1id=1&dir_id=10105&eid=B3IGxpGX3apB9hTTyNDUHgufjkLCy6B0&qb=aW5wdXQgdGV4dCDA2rW/
by Anna 안나 2008. 7. 6. 22:03
11:11.11 이와같이 11분 11초 11 과 같이..타임단위로(형식으로) 자동변경합니다. 예를 들면 사용자가 텍스트 박스안에 111를 넣었을경우 00:01.11이 자동으로 반환되게 하는 자바 스크립입니다. 또다른 예로 1111를 입력받았을경우 00:11.11
만약 사용자가 00:11.11 를 입력받았을경우 이건 제대로 입력됐기 때문에 그냥 그 값을 반환하게 되는것이죠. http://kin.naver.com/detail/detail.php?d1id=1&dir_id=10105&eid=HeqLjkhKuPVbrCGeXv9UJ/mSA3BMErM6&qb=aW5wdXQgdGV4dCDA2rW/
by Anna 안나 2008. 7. 6. 22:01
http://www.ajaxlessons.com/2006/02/19/ajax-workshop-3-shopping-cart-using-scriptaculous/ This workshop we will be building a shopping cart that’s Ajax powered. This will be a drag and drop shopping cart using the Script.aculo.us JavaScript library. We will also be using PHP on the back end to store the user’s shopping cart in sessions. We will start this workshop off with the XHTML and CSS for the shopping cart and its products. Let’s take a look at the XHTML. <div id="products">
<div style="float:left; font-weight:bold">Products</div>
<div id="clearCart" onclick="clearCart();">Clear Cart</div>
<div id="loading">Loading...</div>
<br style="clear:both" />
<div class="box" id="product_1">1</div>
<div class="box" id="product_2">2</div>
<div class="box" id="product_3">3</div>
<div class="box" id="product_4">4</div>
<div class="box" id="product_5">5</div>
<div class="box" id="product_6">6</div>
</div>
<div id="cart">
<div style="float:left; font-weight:bold">Shopping Cart</div>
</div>
We start out with a product div; this div will hold all of our products. Inside the product div we have a new div for the product box label “Products”, a div to hold the clear cart button (which we attached an event to that will be discusses further in the workshop) and the loading status image. After we have a break tag with a clear:both this is needed because we floated the previous divs. We then have the products with their class “box” and a unique id. The ID is what we will be passing to the server side to add the product to our shopping cart. We then have the cart div. This is the actual shopping cart when you drag your products into to be saved server side. Let’s take a look at the CSS now. #cart {
background-color:#FFFF66;
border:dashed gray 1px;
height:100px;
width:500px;
padding:5px;
margin-top:10px;
overflow: auto;
}
#products {
background-color:#FFF;
border:dashed gray 1px;
height:100px;
width:500px;
padding:5px;
}
.box {
background-color:#CCFF33;
border:solid gray 1px;
margin:10px;
padding:4px;
width:50px;
height:50px;
float:left;
cursor:pointer;
}
#loading {
display:none;
float:right;
}
#clearCart {
text-decoration:underline;
cursor:pointer;
float:right
}
#clearCart:hover {
background-color:#CCFFCC;
color:#000099;
}
Nothing spectacular going on here for the most part, we are giving all of our divs some style, setting the height and width colors etc. Some things to point out are in the box class we are floating left so that the divs are horizontally aligned also we are setting display of the loading ID to none so that it’s not shown unless we are communicating with the server. You should now have something that looks like this: We now need to add the code for Script.aculo.us to create the drag and drop functionality. Add this code right before the closing of your body tag. <script type="text/javascript">
var products = document.getElementsByClassName('box');
for (var i = 0; i < products.length; i++) {
new Draggable(products[i].id, {ghosting:true, revert:true})
}
Droppables.add('cart', {onDrop:addProduct})
</script>
The first thing we are doing is getting each product as an object so we can add the drag ability from Script.aculo.us. We do this by getting all elements with the class name of “box” in an array then looping through and creating a new Draggable with the ID of the element. There are also two parameters: ghosting:true and revert:true. Ghosting makes the element transparent while dragging and revert sends the element back to it’s starting position on mouse out. We then make the cart div a droppable. What this does is allow us to catch the ID of which element was dropped and call a function. We set the onDrop parameter to onDrop:addProduct which means that when a draggable (product) is dropped on the droppable (cart) we call the function addProduct. Let’s take a look at the JavaScript now that contains all of our functions. function addProduct(element, dropon, event) {
sendData(element.id);
}
function sendData (prod) {
var url = 'cart.php';
var rand = Math.random(9999);
var pars = 'product_id=' + prod + '&rand=' + rand;
var myAjax = new Ajax.Request( url, {method: 'get', parameters: pars, onLoading: showLoad, onComplete: showResponse} );
}
function clearCart () {
var url = 'cart.php';
var rand = Math.random(9999);
var pars = 'clear=true&rand=' + rand;
var myAjax = new Ajax.Request( url, {method: 'get', parameters: pars, onLoading: showLoad, onComplete: showResponse} );
}
function clearProduct (id) {
var url = 'cart.php';
var rand = Math.random(9999);
var pars = 'clearProduct=true&id=' + id + '&rand=' + rand;
var myAjax = new Ajax.Request( url, {method: 'get', parameters: pars, onLoading: showLoad, onComplete: showResponse} );
}
function showResponse (originalRequest) {
$('loading').style.display = "none";
$('clearCart').style.display = "block";
$('cart').innerHTML = originalRequest.responseText;
}
function showLoad () {
$('clearCart').style.display = "none";
$('loading').style.display = "block";
}
The first function we created addProduct is what is called when a product is added to the shopping cart. We then call another function sendData and pass the ID of the product that was dropped in the cart. The next function sendData we send the product ID to the server to store in a SESSION. For more information using this function visit the previous workshops where we went into greater detail. The clearCart and clearProduct functions are almost identical to the sendData function, but instead we are clearing the cart and clearing the product respectively in the server side SESSION. The showResponse function is updating the shopping cart with products in the server side SESSION as well as hiding the loading div and showing the clear cart button. The showLoad function hides the clear cart button and shows the loading status div. Again we have covered all of these functions earlier in previous workshops. Here is the complete XHTML, CSS and JavaScript <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Ajax Workshop 3: Shopping Cart using Script.aculo.us</title>
<script src="prototype.js" type="text/javascript"></script>
<script src="scriptaculous.js" type="text/javascript"></script>
<style media="screen" type="text/css">
body {
font-family:"Trebuchet MS";
font-size:12px;
}
#cart {
background-color:#FFFF66;
border:dashed gray 1px;
height:100px;
width:500px;
padding:5px;
margin-top:10px;
overflow: auto;
}
#products {
background-color:#FFF;
border:dashed gray 1px;
height:100px;
width:500px;
padding:5px;
}
.box {
background-color:#CCFF33;
border:solid gray 1px;
margin:10px;
padding:4px;
width:50px;
height:50px;
float:left;
cursor:pointer;
}
#loading {
display:none;
float:right;
}
#clearCart {
color:blue;
text-decoration:underline;
cursor:pointer;
float:right
}
#clearCart:hover {
background-color:#CCFFCC;
color:#000099;
}
</style>
<script language="javascript" type="text/javascript">
function addProduct(element, dropon, event) {
sendData(element.id);
}
function sendData (prod) {
var url = 'cart.php';
var rand = Math.random(9999);
var pars = 'product_id=' + prod + '&rand=' + rand;
var myAjax = new Ajax.Request( url, {method: 'get', parameters: pars, onLoading: showLoad, onComplete: showResponse} );
}
function clearCart () {
var url = 'cart.php';
var rand = Math.random(9999);
var pars = 'clear=true&rand=' + rand;
var myAjax = new Ajax.Request( url, {method: 'get', parameters: pars, onLoading: showLoad, onComplete: showResponse} );
}
function clearProduct (id) {
var url = 'cart.php';
var rand = Math.random(9999);
var pars = 'clearProduct=true&id=' + id + '&rand=' + rand;
var myAjax = new Ajax.Request( url, {method: 'get', parameters: pars, onLoading: showLoad, onComplete: showResponse} );
}
function showResponse (originalRequest) {
$('loading').style.display = "none";
$('clearCart').style.display = "block";
$('cart').innerHTML = originalRequest.responseText;
}
function showLoad () {
$('clearCart').style.display = "none";
$('loading').style.display = "block";
}
</script>
</head>

<body>
<h1>Ajax Workshop 3: Shopping Cart using <a href="http://script.aculo.us">Script.aculo.us</a> </h1>
<h2>Drag the products into the shopping cart</h2>
<div id="products">
<div style="float:left; font-weight:bold">Products</div>
<div id="clearCart" onclick="clearCart();">Clear Cart</div>
<div id="loading"><img src="indicator.gif" alt="loading..." /></div>
<br style="clear:both" />
<div class="box" id="product_1">1</div>
<div class="box" id="product_2">2</div>
<div class="box" id="product_3">3</div>
<div class="box" id="product_4">4</div>
<div class="box" id="product_5">5</div>
<div class="box" id="product_6">6</div>
</div>
<div id="cart">
<div style="float:left; font-weight:bold">Shopping Cart</div>
</div>
<script type="text/javascript">
var products = document.getElementsByClassName('box');
for (var i = 0; i < products.length; i++) {
new Draggable(products[i].id, {ghosting:true, revert:true})
}
Droppables.add('cart', {onDrop:addProduct})
</script>
</body>
</html>
Time for the server side Cart.php. <?php
session_start();
function stringForJavascript($in_string) {
$str = ereg_replace("[\r\n]", " \\n\\\n", $in_string);
$str = ereg_replace('"', '\\"', $str);
Return $str;
}
if (isset($_GET['clearProduct'])) {
$_SESSION['cart'][$_GET['id']]--;
if ($_SESSION['cart'][$_GET['id']] == 0) {
unset($_SESSION['cart'][$_GET['id']]);
}
foreach ($_SESSION['cart'] as $key => $value) {
print "$key = $value <span style=\"color:blue; text-decoration:underline; cursor:pointer\" onclick=\"clearProduct('$key');\">DELETE</span><br />";
}
sleep(1);
die;
}
if (isset($_GET['clear'])) {
unset($_SESSION['cart']);
sleep(1);
die;
}
$prodid = $_GET['product_id'];
$_SESSION['cart'][$prodid] = 1 + $_SESSION['cart'][$prodid];
foreach ($_SESSION['cart'] as $key => $value) {
print "$key = $value <span style=\"color:blue; text-decoration:underline; cursor:pointer\" onclick=\"clearProduct('$key');\">DELETE</span><br />";
}
sleep(1);
?>
We start off by calling the session_start() function which allow us to access and modify the SESSION global variable. We then have created a function for returning a string that JavaScript can read. Next we are using a conditional statement to check whether we are adding a product, clearing the cart or removing a product. Depending on what action is called we manipulate the SESSION global variable and send back the contents of the shopping cart. I am not going to cover all the basics of the SESSION global variable but if you like you can read up on it at http://php.net/session. Here is what it looks like when complete
by Anna 안나 2008. 7. 6. 17:13
Browser-based file uploads, in particular those involving the HTML <input type="file"> tag, have always been rather lacking. As I am sure most of you are aware, uploading files exceeding 10MB often causes a very poor user experience. Once a user submits the file, the browser will appear to be inactive while it attempts to upload the file to the server. While this happening in the background, many impatient users would start to assume that the server is "hanging" and would try to submit the file again. This of course, only helps to make matters worse. In an attempt to make uploading of files more user-friendly, many sites display an indeterminate progress animation (such as a rotating icon) once the user submits the file. Although this technique may be useful in keeping the user distracted while the upload being submitted to the server, it offers very little information on the status of the file upload. Another attempt at solving the problem is to implement an applet that uploads the file to the server through FTP. The drawback with this solution is that it limits your audience to those that have a Java-enabled browser. In this article, we will take fresh approach and implement an AJAX-powered component that will not only upload the file to server, but also monitor the actual progress of a file upload request in "real time." The four stages of this component are illustrated below, in Figures 1, 2, 3, and 4: Figure 1. Stage 1: Selecting the file upload Figure 2. Stage 2: Uploading the file to the server Figure 3. Stage 3: Uploaded completed Figure 4. File upload summary Implementing the Component We will first walk through the process of creating the multipart filter that will allow us to handle and monitor the file upload. We will then move on to implementation of the JavaServer Faces component that will provide the user with continuous feedback in the form of an AJAX-enabled progress bar. The Multipart Filter: UploadMultipartFilter The responsibility of the multipart filter is to intercept the incoming file upload and write the file to a temporary directory on the server. At the same time, it will also monitor the amount of bytes received and determine how much of the file has been uploaded. Fortunately, there is an excellent Jakarta-Commons open source library available (FileUpload) that takes care of parsing an HTTP multipart request and writing a file upload to disk. We will be extend this library and add in the required "hooks" we need to monitor how many bytes have been processed. public class UploadMultipartFilter implements Filter{ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest hRequest = (HttpServletRequest)request; //Check whether we're dealing with a multipart request String contentHeader = hRequest.getHeader("content-type"); boolean isMultipart = ( contentHeader != null && contentHeader.indexOf("multipart/form-data") != -1); if(isMultipart == false){ chain.doFilter(request,response); }else{ UploadMultipartRequestWrapper wrapper = new UploadMultipartRequestWrapper(hRequest); chain.doFilter(wrapper,response); } ... } As you can see, the UploadMultipartFilter class simply checks to see whether the current request is a multipart request. If the request does not contain a file upload, the request is passed on to the next filter in the chain without any additional processing. Otherwise, the request is wrapped in an UploadMultipartRequestWrapper. The UploadMultipartRequestWrapper Class public class UploadMultipartRequestWrapper extends HttpServletRequestWrapper{ private Map<String,String> formParameters; private Map<String,FileItem> fileParameters; public UploadMultipartRequestWrapper(HttpServletRequest request) { super(request); try{ ServletFileUpload upload = new ServletFileUpload(); upload.setFileItemFactory(new ProgressMonitorFileItemFactory(request)); List fileItems = upload.parseRequest(request); formParameters = new HashMap<String,String>(); fileParameters = new HashMap<String,FileItem>(); for(int i=0;i<fileItems.size();i++){ FileItem item = (FileItem)fileItems.get(i); if(item.isFormField() == true){ formParameters.put(item.getFieldName(),item.getString()); }else{ fileParameters.put(item.getFieldName(),item); request.setAttribute(item.getFieldName(),item); } } }catch(FileUploadException fe){ //Request Timed out - user might have gone to other page. //Do some logging //... } ... In our UploadMultipartRequestWrapper class, we initialize the commons ServletFileUpload class that will parse our request and write the file to the default temporary directory on the server. The ServletFileUpload instance creates a FileItem instance for each field that is encountered in the request. These include both file uploads and normal form elements. A FileItem instance can then be used to retrieve the properties of a submitted field, or, in the case of a file upload, an InputStream to the underlying temporary file to which it has been saved. In summary, the UploadMultipartRequestWrapper basically parses the file and sets any FileItems that represent file uploads as attributes in the request. These can then be picked up by JSF components further down the line. The behavior of normal form fields remains the same. By default, the Commons FileUpload library use instances of the DiskFileItems class to handle file uploads. Although DiskFileItems are very useful in handling the whole temporary-file business, there is very little support for monitoring exactly how much of the file has been processed. Since version 1.1, the Commons FileUpload library provides developers with the ability to specify the factory that will be used to create the FileItem. We will use the ProgressMonitorFileItemFactory and ProgressMonitorFileItem classes to override the default behavior and monitor the progress file uploads. The ProgressMonitorFileItemFactory Class public class ProgressMonitorFileItemFactory extends DiskFileItemFactory { private File temporaryDirectory; private HttpServletRequest requestRef; private long requestLength; public ProgressMonitorFileItemFactory(HttpServletRequest request) { super(); temporaryDirectory = (File)request.getSession().getServletContext(). getAttribute("javax.servlet.context.tempdir"); requestRef = request; String contentLength = request.getHeader("content-length"); if(contentLength != null){ requestLength = Long.parseLong(contentLength.trim()); } } public FileItem createItem(String fieldName, String contentType, boolean isFormField, String fileName) { SessionUpdatingProgressObserver observer = null; if(isFormField == false) //This must be a file upload. observer = new SessionUpdatingProgressObserver(fieldName, fileName); ProgressMonitorFileItem item = new ProgressMonitorFileItem( fieldName, contentType, isFormField, fileName, 2048, temporaryDirectory, observer, requestLength); return item; } ... public class SessionUpdatingProgressObserver implements ProgressObserver { private String fieldName; private String fileName; ... public void setProgress(double progress) { if(request != null){ request.getSession().setAttribute("FileUpload.Progress." + fieldName, progress); request.getSession().setAttribute("FileUpload.FileName." + fieldName, fileName); } } } } The ProgressMonitorFileItemFactory uses the Content-Length header set by the browser and assumes it to be the accurate length of the upload file being sent. This method of determining the file length does limit you to uploading only one file per request--it's inaccurate if more than more file is encoded in the request. This is due to the fact that browsers only send one Content-Length header, regardless of the number of files in the upload. In addition to creating ProgressMonitorFileItem instances, the ProgressMonitorFileItemFactory also registers a ProgressObserver instance that will be used by the ProgressMonitorFileItem to send updates on the progress of the file upload. The implementation of the ProgressObserver used, SessionUpdatingProgressObserver, sets the progress percentage into the user's session under the id of the submitted field. This value can then be accessed by the JSF component in order to send updates to the user. The ProgressMonitorFileItem Class public class ProgressMonitorFileItem extends DiskFileItem { private ProgressObserver observer; private long passedInFileSize; ... private boolean isFormField; ... @Override public OutputStream getOutputStream() throws IOException { OutputStream baseOutputStream = super.getOutputStream(); if(isFormField == false){ return new BytesCountingOutputStream(baseOutputStream); }else{ return baseOutputStream; } } ... private class BytesCountingOutputStream extends OutputStream{ private long previousProgressUpdate; private OutputStream base; public BytesCountingOutputStream(OutputStream ous){ base = ous; } ... private void fireProgressEvent(int b){ bytesRead += b; ... double progress = (((double)(bytesRead)) / passedInFileSize); progress *= 100.0 observer.setProgress(); } } } The ProgressMonitorFileItem wraps the default OutputStream of the DiskFileItem in a BytesCountingOutputStream, which updates the associated ProgressObserver every time a certain number of bytes have been read. The AJAX-Enabled JavaServer Faces Upload Component This component is responsible for rendering the HTML file upload tag, displaying a progress bar to monitor the file upload, and rendering the components that need to be displayed once a file has been successfully uploaded. One of the main advantages to implementing this component using JavaServer Faces is the fact that most of the complexities are hidden from the page author. The page author only needs to add the component tag to the JSP and the component will take care of all of the AJAX and progress-monitoring details. Below is the JSP code snippet that is used to add the upload component to the page. <comp:fileUpload value="#{uploadPageBean.uploadedFile}" uploadIcon="images/upload.png" styleClass="progressBarDiv" progressBarStyleClass="progressBar" cellStyleClass="progressBarCell" activeStyleClass="progressBarActiveCell"> <%--Below are the components that will be visible once the file upload completes--%> <h:panelGrid columns="2" cellpadding="2" cellspacing="0" width="100%"> <f:facet name="header"> <h:outputText styleClass="text" value="File Upload Successful." /> </f:facet> <h:panelGroup style="text-align:left;display:block;width:100%;"> <h:commandButton action="#{uploadPageBean.reset}" image="images/reset.png"/> </h:panelGroup> <h:panelGroup style="text-align:right;display:block;width:100%;"> <h:commandButton action="#{uploadPageBean.nextPage}" image="images/continue.png"/> </h:panelGroup> </h:panelGrid> </comp:fileUpload> The value attribute of the file upload component needs to be bound to a bean with a property that holds a FileItem. The child components are only displayed once the file has been successfully received by the server. Implementing the AJAX File Upload Component The progress bar of the component was inspired by the " Progress Bar Using JavaServer Faces Component with AJAX" solution as detailed in the Java BluePrints Solution Catalog. In essence, the upload component either renders a complete version of itself, or in the case of an AJAX request, only a bit of XML to update the state of the progress bar on the page. In order to prevent JavaServer Faces from rendering the complete component tree (which would incur unnecessary overhead), we also need to implement a PhaseListener (PagePhaseListener) to abort the rest of the faces' request processing if an AJAX request is encountered. I have omitted all of the standard configuration (faces-config.xml and tag libraries) from the article, as these are very straightforward and have been covered before. Everything is, however, included in the source code download for this article (in the Resources section) if you wish to review them. The AJAX File Upload Component Renderer The implementation of the component and tag classes is rather straightforward. The bulk of the logic is contained in the renderer, which has the following responsibilities: Encode the full file upload component (complete with the HTML file upload tag), components to be displayed once a file has been uploaded, and the client-side JavaScript code to implement for the AJAX requests. Handle partial AJAX requests appropriately and send back the necessary XML. Decode a file upload and set it as a FileItem instance on the underlying value binding. Encoding the Full Upload Component As mentioned previously, the file upload component is composed of three stages. During the full encoding of the component, we will encode all three stages. Their visibility (using the CSS display property) on the page will then be controlled by the AJAX JavaScript. Stage 1 Figure 5 shows stage 1 of the upload component. Figure 5. Stage 1: Selecting the file upload In Stage 1, we need to render the HTML file upload tag and the button that will be responsible for starting off this process. Once the user clicks the upload button, the form is submitted through an IFRAME ( to prevent blocking on the page) and the second stage of the process is initiated. Below is an extract of the rendering code : //The File upload component writer.startElement("input", component); writer.writeAttribute("type", "file", null); writer.writeAttribute("name", component.getClientId(context), "id"); writer.writeAttribute("id", component.getClientId(context),"id"); if(input.getValue() != null){ //Render the name of the file if available. FileItem fileData = (FileItem)input.getValue(); writer.writeAttribute("value", fileData.getName(), fileData.getName()); } writer.endElement("input"); String iconURL = input.getUploadIcon(); //Render the image, and attach the JavaScript event to it. writer.startElement("div", component); writer.writeAttribute("style","display:block;width:100%;text-align:center;", "style"); writer.startElement("img", component); writer.writeAttribute("src",iconURL,"src"); writer.writeAttribute("type","image","type"); writer.writeAttribute("style","cursor:hand;cursor:pointer;","style"); UIForm form = FacesUtils.getForm(context,component); if(form != null) { String getFormJS = "document.getElementById('" + form.getClientId(context) + "')"; String jsFriendlyClientID = input.getClientId(context).replace(":","_"); //Sets the encoding of the form to be multipart required for file uploads and //to submit its content through an IFRAME. The second stage of the component is //also initialized after 500 milliseconds. writer.writeAttribute("onclick",getFormJS + ".encoding='multipart/form-data';" + getFormJS + ".target='" + iframeName + "';" + getFormJS + ".submit();" + getFormJS + ".encoding='application/x-www-form-urlencoded';" + getFormJS + ".target='_self';" + "setTimeout('refreshProgress" + jsFriendlyClientID + "();',500);", null); } ... writer.endElement("img"); //Now do the IFRAME we are going to submit the file/form to. writer.startElement("iframe", component); writer.writeAttribute("id", iframeName, null); writer.writeAttribute("name",iframeName,null); writer.writeAttribute("style","display:none;",null); writer.endElement("iframe"); writer.endElement("div"); writer.endElement("div"); //End of Stage1 Stage 2 Stage 2 of the component is the progress bar and the label that indicates the current percentage, as seen in Figure 6. The progress bar is implemented as a div tag with 100 embedded span tags. These will be set by the AJAX JavaScript based on the response received from the server. Figure 6. Stage 2: Uploading the file to the server writer.startElement("div", component); writer.writeAttribute("id", input.getClientId(context) + "_stage2", "id"); ... writer.writeAttribute("style","display:none", "style"); String progressBarID = component.getClientId(context) + "_progressBar"; String progressBarLabelID = component.getClientId(context) + "_progressBarlabel"; writer.startElement("div", component); writer.writeAttribute("id",progressBarID,"id"); String progressBarStyleClass = input.getProgressBarStyleClass(); if(progressBarStyleClass != null) writer.writeAttribute("class",progressBarStyleClass,"class"); for(int i=0;i<100;i++){ writer.write("<span> </span>"); } writer.endElement("div"); writer.startElement("div", component); writer.writeAttribute("id",progressBarLabelID,"id"); ... writer.endElement("div"); writer.endElement("div"); //End of Stage2 Stage 3 Finally, the components that need to be displayed once a file has been successfully uploaded, seen in Figure 7, are rendered as part of Stage 3. These are done in the encodeChildren method of the renderer. Figure 7. Stage 3: Uploaded completed public void encodeChildren(FacesContext context, UIComponent component) throws IOException { ResponseWriter writer = context.getResponseWriter(); UIFileUpload input = (UIFileUpload)component; //Do the children that will be shown once the //file has been successfully uploaded writer.startElement("div", component); writer.writeAttribute("id", input.getClientId(context) + "_stage3", "id"); //Stage3. if(input.getValue() == null){ writer.writeAttribute("style","display:none;",null); }else{ writer.writeAttribute("style","display:block",null); } List<UIComponent> children = input.getChildren(); for(UIComponent child : children){ FacesUtils.encodeRecursive(context,child); } writer.endElement("div"); //End of Stage3 } Handling AJAX Requests The rendering of AJAX requests is handled in the decode method of this component, in accordance with recommendations in the Java BluePrints Solution Catalog. We need to check whether this is in fact an AJAX request (to differentiate from normal decoding behavior) and then send back an XML response to the client based on the values that have been set in the session by the SessionUpdatingProgressObserver instance in the ProgressMonitorFileItemFactory class. public void decode(FacesContext context, UIComponent component) { UIFileUpload input = (UIFileUpload) component; //Check whether this is a request for the //progress of the upload, or if it is an actual // upload request. ExternalContext extContext = context.getExternalContext(); Map parameterMap = extContext.getRequestParameterMap(); String clientId = input.getClientId(context); Map requestMap = extContext.getRequestParameterMap(); if(requestMap.get(clientId) == null){ //Nothing to do. return; } if(parameterMap.containsKey(PROGRESS_REQUEST_PARAM_NAME)){ //This is a request to get the progress on the file request. //Get the progress and render it as XML HttpServletResponse response = (HttpServletResponse) context.getExternalContext().getResponse(); // set the header information for the response response.setContentType("text/xml"); response.setHeader("Cache-Control", "no-cache"); try { ResponseWriter writer = FacesUtils.setupResponseWriter(context); writer.startElement("progress", input); writer.startElement("percentage", input); //Get the current progress percentage from //the session (as set by the filter). Double progressCount = (Double)extContext.getSessionMap(). get("FileUpload.Progress." + input.getClientId(context)); if(progressCount != null){ writer.writeText(progressCount, null); }else{ //We haven't received the upload yet. writer.writeText("1", null); } writer.endElement("percentage"); writer.startElement("clientId", input); writer.writeText(input.getClientId(context), null); writer.endElement("clientId"); writer.endElement("progress"); } catch(Exception e){ //Do some sort of error logging... } }else{ //Normal decoding request. ... Normal Decoding Behavior During normal decoding, the file upload renderer retrieves the FileItem from the request attributes, where it has been set by the filter, and updates the component's value binding. The progress in the session is then updated to 100 percent so that the JavaScript on the page can move the component into Stage 3. //Normal decoding request. if(requestMap.get(clientId).toString().equals("file")){ try{ HttpServletRequest request = (HttpServletRequest)extContext.getRequest(); FileItem fileData = (FileItem)request.getAttribute(clientId); if(fileData != null) input.setSubmittedValue(fileData); //Now we need to clear any progress associated with this item. extContext.getSessionMap().put("FileUpload.Progress." + input.getClientId(context), new Double(100)); }catch(Exception e){ throw new RuntimeException("Could not handle file upload" + " - please configure the filter.",e); } } The client-side JavaScript is responsible for making progress requests to the server and for moving the component through the different stages. To cut out the usual boilerplate code associated with handling all of the browser-specific quirks of the XMLHttpRequest object, I've opted for the excellent AjaxRequest.js library provided by Matt Krause. This library allows us to considerably reduce the amount of JavaScript code we need to write to get this component working. Although it is probably best practice to package the JavaScript code as part of the component and then to render it from a PhaseListener (as detailed here ), I've tried to keep it simple by defining a link to the JavaScript library on the JSP page. The getProgressBarJavaScript method in the component is called to render the JavaScript. Getting the JavaScript correct is usually the most painful part of implementing any AJAX component; hopefully, the code below is clear enough to be easily understood. While the JavaScript in my example is embedded within the Java code, it is probably better practice to externalize it into a separate file. For the purposes of this article I wanted to keep it simple and to the point. Below is an example of the JavaScript that would be rendered by the component. It is assumed that fileUpload1 is the client-side JSF Id assigned to the file component, while uploadForm is the Id of the HTML form. function refreshProgress(){ // Assume we are entering stage 2. document.getElementById('fileUpload1_stage1').style.display = 'none'; document.getElementById('fileUpload1_stage2').style.display = ''; document.getElementById('fileUpload1_stage3').style.display = 'none'; // Create the AJAX post AjaxRequest.post( { //Specify the correct parameters so that //the component is correctly handled on //the server side. 'parameters':{ 'uploadForm':'uploadForm', 'fileUpload1':'fileUpload1', 'jsf.component.UIFileUpload':'1', 'ajax.abortPhase':'4' } //Abort at Phase 4. // Specify the callback method for successful processing. ,'onSuccess':function(req) { var xml = req.responseXML; if( xml.getElementsByTagName('clientId').length == 0) { setTimeout('refreshProgress()',200); return; } var clientId = xml.getElementsByTagName('clientId'); clientId = clientId[0].firstChild.nodeValue + '_progressBar'; //Get the percentage from the XML var percentage = xml.getElementsByTagName('percentage')[0].firstChild.nodeValue; var innerSpans = document.getElementById(clientId).getElementsByTagName('span'); document.getElementById(clientId + 'label').innerHTML = Math.round(percentage) + '%'; // Set the style classes of the spans based on the current progress. for(var i=0;i<innerSpans.length;i++){ if(i < percentage){ innerSpans[i].className = 'active'; }else{ innerSpans[i].className = 'passive'; } } // If the percentage is not 100, we need to carry // on polling the server for updates. if(percentage != 100){ setTimeout('refreshProgress()',400); } else { // The file upload is done - we now //need to move the component into stage 3. document.getElementById('fileUpload1_stage1').style.display = 'none'; document.getElementById('fileUpload1_stage2').style.display = 'none'; document.getElementById('fileUpload1_stage3').style.display = ''; } } }); } return builder.toString(); Conclusion Hopefully, this article offered you some insight on how to make file uploads more user-friendly, and on the possibilities of combining AJAX and JavaServer Faces for advanced user interface components. The solution in this article is by no means exhaustive and could probably be further improved. I would encourage you to look at the complete source code to gain a deeper understanding of the concepts discussed here. Resources Source code for this article Commons FileUpload library: The library we used process the file uploads Java BluePrints Solution Catalog: " Using JavaServer Faces Technology with AJAX" Ajax Toolbox for more information on the AjaxRequest API used in this article Jacobus Steenkamp has been developing in Java for the last 4.5 years and has worked in various sectors including the financial, pharmaceutical and energy industries. http://today.java.net/pub/a/today/2006/02/09/file-uploads-with-ajax-and-jsf.html
by Anna 안나 2008. 7. 6. 01:38
http://www.ajaxdomainsearch.com ajaxdomainsearch1.1.zip
by Anna 안나 2008. 5. 23. 19:05
리녈을 했는지 지금은 안보이는데 예전 엠에센 쇼핑의 상품관련된 자스중의 하나입니다. shopping_msn.zip
by Anna 안나 2008. 5. 23. 19:04
시간대별로 다른 CSS를 적용시킵니다.

'JS > 자바의심' 카테고리의 다른 글

input text 자동 형식으로 변경하기  (0) 2008.07.06
Ajax Shopping Cart  (0) 2008.07.06
Better File Uploads with AJAX and JavaServer Faces  (0) 2008.07.06
Ajax Domain Search  (0) 2008.05.23
플래시효과의 shopping msn (메뉴같습니다)  (0) 2008.05.23
win - jquery 이용  (0) 2008.05.23
Google-X  (0) 2008.05.23
폼안에 내용을 자동선택+자동복사해줍니다.  (0) 2008.03.21
옆에 따라다니는 퀵메뉴  (0) 2008.03.08
동적 탭 메뉴  (0) 2008.03.08
by Anna 안나 2008. 5. 23. 19:01
win__jquery.zip jquery를 이용하는데 살짝 무겁습니다. 드래그, 리사이즈 됨
by Anna 안나 2008. 5. 23. 19:00
메뉴효과입니다. 짱이쁩니다..- 한 메뉴당 두개의 이미지로 돌아갑니다. google_x.zip
by Anna 안나 2008. 5. 23. 18:59
폼안에 있는내용이 버튼을 누르면 자동으로 복사(클립보드에저장)되는
효과를 본적이 있을겁니다





- 소스 분석 -
<HTML>
<!--HTML의 시작을 알리는 문법-->
<HEAD>
<!--HEAD의 시작을 알림~(즉head 앞대가리)-->
<TITLE>폼안에 내용을 복사</TITLE>
<!--타이틀 지정 폼안에 내용을 복사라는 제목이 타이틀바(제목표시줄)에 나타납니다-->
<HEAD>
<SCRIPT LANGUAGE="JavaScript">
<!--스크립트를 쓰는데 그 언어가 자바스크립트다-->
function copyit(theField) {
<!--레코드를copyit이라고 설정하고괄호안에 필드이름을 집어넣는다고 선언해줌-->
var tempval=eval("document."+theField)
tempval.focus()
tempval.select()
therange=tempval.createTextRange()
therange.execCommand("Copy")
<!--복사한다-->
}
</script>
<!--자바스크립트 끝-->
</HEAD>
<!--앞대가리 설정 끝-->
<BODY>
<!--바디 몸이라는뜻으로 눈으로 보여질 부분을 작성-->
<form name="it">
<!--지금부터 폼이 시작되는데 그 이름하여 it라는 폼을 만든다-->
<div align="center">
<!--가운데 정렬(제로보드 게시판설정에도 있죠^^;)-->
<input onclick="copyit('it.select1')" type="button" value="누르면 복사됩니다" name="cpy">
<!--버튼을 만듭니다. 버튼이름은 cpy고 cpy버튼에 나타날 글자는 누르면 복사됩니다 입니다-->
<!--그리고 그 버튼을 클릭하면 copyit이라고 아까 선언해준 자바스크립트가 실행되는데(onclick가 클릭할때-->
<!--실행될 것을 입력한는거입니다) it이라는폼안에 sclect1이라는 글상자에있는 내용을 말하는것입니다-->
<p>
<!--표가 시작됩니다-->
<textarea name="select1" rows="5" cols="40">
위의 버튼을 누르면 이 부분이 선택되고 자동으로 복사됩니다.
브라우저의 주소입력란에 붙여넣기(Ctrl+V) 해보세요.
</textarea>
<!--글상자를 만드는데 글장자 이름이 select1이고 글상자 넓이가 40이고 5줄짜리를 만듭니다-->
<!--그리고 그안에 들어있는내용은 위의 버튼을 누르면 이 부분이 선택되고 자동으로 복사됩니다.브라우저의 주소입력란에 붙여넣기(Ctrl+V) 해보세요.입니다-->
</div>
<!--div가 끝났습니다. 앞에/를 붙여주는것은 그것을 닫는다는 뜻입니다-->
<!--아까 열어줬으니 닫아줘야줘~-->
</form>
<!--폼을 닫습니다-->
</BODY>
<!--몸둥아리를 닫습니다-->
</HTML>
<!--html이 끝났습니다-->

///////////////////////////////////////////
참고
<input onclick="copyit('it.select1')" type="button" value="누르면 복사됩니다" name="cpy" style="background-color:rgb(51,153,255); border-width:1; border-style:none;">
이렇게 버튼을 바꾸면
background-color:rgb(51,153,255); //배경화면이 rgb컬러로 51,153,225인 즉, 하늘색이된 배경화면을 만들수있습니다.
border-width:1; border-style:none;//모든 태두리가 없습니다

'JS > 자바의심' 카테고리의 다른 글

Ajax Domain Search  (0) 2008.05.23
플래시효과의 shopping msn (메뉴같습니다)  (0) 2008.05.23
시간대별로 다른 CSS  (0) 2008.05.23
win - jquery 이용  (0) 2008.05.23
Google-X  (0) 2008.05.23
옆에 따라다니는 퀵메뉴  (0) 2008.03.08
동적 탭 메뉴  (0) 2008.03.08
실시간 시간을 보여주는 자바스크립트  (0) 2008.03.08
랜덤스크립트 사용  (0) 2008.03.08
마우스 올려 놓으면 내용 저절로 변하는 탭메뉴  (0) 2008.03.08
by Anna 안나 2008. 3. 21. 20:20
응용하여 TOP메뉴와 BOTTOM 등등 아주 다양하게 쓸수있습니다.^^
by Anna 안나 2008. 3. 8. 17:36
-
by Anna 안나 2008. 3. 8. 17:35
-
by Anna 안나 2008. 3. 8. 17:34
잘쓰세요..^^
by Anna 안나 2008. 3. 8. 17:33
살과 옷을 입히는 일은 직접해보세요. ^^ <script>
function change(obj) {
First.style.display = "none";
Second.style.display = "none"; obj.style.display = "block";
}
</script> <div id="First" style="display:block">
<span style="background-color:yellow">첫번째</span> <span onMouseOver="change(Second)" style="background-color:gray">두번째</span>
<br>첫번째 내용
</div>
<div id="Second" style="display:none">
<span onMouseOver="change(First)" style="background-color:gray">첫번째</span> <span style="background-color:yellow">두번째</span>
<br>두번째 내용
</div>



부연설명 :
style속성의 display 스타일 속성 값을 block과 none으로 바꾸면서
해당 개체를 사리지거나 나타나게 할 수 있습니다.

이걸 이용해서,

First라고 id값을 준 div태그로 첫번째 메뉴 탭과 내용을 감싸고
화면에 보이는 상태(blick)로 해두고

Second라고 id값을 준 div태그로 두번째 메뉴 탭과 내용을 감싸고
화면에 보이지 않는 상태(none)로 해둡니다.

이후, 스크립트를 이용해서 현재 보여지는 First의 두번째 메뉴 탭에
onmouseover 이벤트가 발생했을 때(마우스를 가져갔을 때)
First를 사라지게 하고 Second를 나타나게 하는 것이고

Second에서는 첫번째 메뉴 탭에 onmouseover 이벤트가 발생했을 때
Second는 사라지게 First는 나타나게 하는 것입니다.
by Anna 안나 2008. 3. 8. 17:19
네이버 뉴스에서 사용된 간단한 스크립트를 이용한 탭메뉴입니다.
by Anna 안나 2008. 3. 8. 17:18
잘 응용하면 하나의 문서로 여러페이지를 보여줄 수 있는 유용한 스크립트 입니다
by Anna 안나 2008. 3. 8. 17:18
-
by Anna 안나 2008. 3. 8. 15:04
레이어가 마우스를 따라다닙니다.
by Anna 안나 2008. 3. 8. 15:03
멋진겝니다>_< ㅎㅎ
by Anna 안나 2008. 3. 8. 15:02
중복체크입니다.
by Anna 안나 2008. 3. 8. 15:02
전화번호받을때나 금액받을때^^
by Anna 안나 2008. 3. 8. 15:01
많이쓰이는 스크립트입니다.
by Anna 안나 2008. 3. 8. 15:00
유용합니다.^^
by Anna 안나 2008. 3. 8. 15:00
| 1 2 3 |