ソースを参照

Added arrival deadline date selection to booking/routing dmin interface, and some de-uglification

peter_backlund 18 年 前
コミット
bb7c704e5d

+ 7
- 1
dddsample/src/main/java/se/citerus/dddsample/application/web/CargoAdminController.java ファイルの表示

@@ -75,7 +75,13 @@ public final class CargoAdminController extends MultiActionController {
75 75
     final String trackingId = request.getParameter("trackingId");
76 76
     final List<ItineraryCandidateDTO> itineraryCandidates = bookingServiceFacade.requestPossibleRoutesForCargo(trackingId);
77 77
 
78
-    map.put("itineraryCandidates", itineraryCandidates);
78
+    if (request.getParameter("spec") != null) {
79
+      map.put("itineraryCandidates", itineraryCandidates);
80
+    }
81
+
82
+    final CargoRoutingDTO cargoDTO = bookingServiceFacade.loadCargoForRouting(trackingId);
83
+    map.put("origin", cargoDTO.getOrigin());
84
+    map.put("destination", cargoDTO.getFinalDestination());
79 85
     map.put("trackingId", trackingId);
80 86
     return map;
81 87
   }

+ 3
- 3
dddsample/src/main/webapp/WEB-INF/jsp/admin/registrationForm.jsp ファイルの表示

@@ -11,7 +11,7 @@
11 11
 <div id="container">
12 12
   <form action="<c:url value="/admin/register.html"/>" method="post">
13 13
   <table>
14
-    <caption>Register cargo</caption>
14
+    <caption>Book new cargo</caption>
15 15
     <tbody>
16 16
       <tr>
17 17
         <td>Origin</td>
@@ -24,7 +24,7 @@
24 24
         </td>
25 25
       </tr>
26 26
       <tr>
27
-        <td>Final destination</td>
27
+        <td>Destination</td>
28 28
         <td>
29 29
           <select name="destinationUnlocode">
30 30
             <c:forEach items="${unlocodes}" var="u">
@@ -38,7 +38,7 @@
38 38
       <tr>
39 39
         <td> </td>
40 40
         <td>
41
-          <input type="submit" value="Register"/>
41
+          <input type="submit" value="Book"/>
42 42
         </td>
43 43
       </tr>
44 44
     </tfoot>

+ 34
- 4
dddsample/src/main/webapp/WEB-INF/jsp/admin/selectItinerary.jsp ファイルの表示

@@ -1,20 +1,50 @@
1 1
 <html>
2 2
 <head>
3 3
   <title>Cargo Administration</title>
4
+  <script type="text/javascript" charset="UTF-8" src="<c:url value="/js/calendar.js"/>"></script>
5
+  <script type="text/javascript" charset="UTF-8" src="<c:url value="/js/YAHOO.js"/>"></script>
6
+  <script type="text/javascript" charset="UTF-8" src="<c:url value="/js/event.js"/>"></script>
7
+  <script type="text/javascript" charset="UTF-8" src="<c:url value="/js/dom.js"/>"></script>
8
+  <style type="text/css" title="style" media="screen">
9
+    @import "<c:url value="/calendar.css"/>";
10
+  </style>
4 11
 </head>
5 12
 <body>
6 13
 <div id="container">
7
-  <h1>Select itinerary</h1>
14
+  <form action="selectItinerary.html" method="GET">
15
+  <table>
16
+    <caption>Select route for cargo ${trackingId}</caption>
17
+    <tr>
18
+      <td><strong>Origin:</strong></td>
19
+      <td>${origin}</td>
20
+    </tr>
21
+    <tr>
22
+      <td><strong>Destination:</strong></td>
23
+      <td>${destination}</td>
24
+    </tr>
25
+    <tr>
26
+      <td><strong>Arrival deadline:</strong></td>
27
+      <td>
28
+        <input name="spec" type="text" size="10" id="cal1" value="${param.spec}"/>&nbsp;
29
+        <img alt="" src="<c:url value="/images/calendarTrigger.gif"/>" class="calendarTrigger" onclick="calendar.toggle( event, this, 'cal1')"/>
30
+      </td>
31
+    </tr>
32
+  </table>
33
+    <p>
34
+      <input type="hidden" name="trackingId" value="${trackingId}"/>
35
+      <input type="submit" value="Find routes"/>
36
+    </p>
37
+  </form>
8 38
   <c:url value="/admin/assignItinerary.html" var="postUrl"/>
9 39
 
10 40
   <c:forEach items="${itineraryCandidates}" var="it" varStatus="itStatus">
11 41
       <form action="${postUrl}" method="post">
12 42
         <input type="hidden" name="trackingId" value="${trackingId}"/>
13 43
         <table>
14
-          <caption>Itinerary ${itStatus.index + 1}</caption>
44
+          <caption>Route ${itStatus.index + 1}</caption>
15 45
           <thead>
16 46
             <tr>
17
-              <td>Carrier</td>
47
+              <td>Carrier Movement</td>
18 48
               <td>From</td>
19 49
               <td>To</td>
20 50
             </tr>
@@ -35,7 +65,7 @@
35 65
             <tr>
36 66
               <td colspan="3">
37 67
                 <p>
38
-                  <input type="submit" value="Select"/>
68
+                  <input type="submit" value="Assign cargo to this route"/>
39 69
                 </p>
40 70
               </td>
41 71
             </tr>

+ 1
- 1
dddsample/src/main/webapp/WEB-INF/jsp/admin/show.jsp ファイルの表示

@@ -12,7 +12,7 @@
12 12
         <td>${cargo.origin}</td>
13 13
       </tr>
14 14
       <tr>
15
-        <td>Final destination</td>
15
+        <td>Destination</td>
16 16
         <td>${cargo.finalDestination}</td>
17 17
       </tr>
18 18
     </tbody>

+ 3
- 2
dddsample/src/main/webapp/WEB-INF/jsp/adminDecorator.jsp ファイルの表示

@@ -12,7 +12,8 @@
12 12
 </head>
13 13
 <body>
14 14
   <div id="outer">
15
-    <h1>Cargo administration</h1>
15
+    <img id="logotype" src="<c:url value="/images/dddsample_logotype_small.png"/>" alt=""/>
16
+    <h1>Cargo Booking and Routing</h1>
16 17
     <ul id="menu">
17 18
       <li>
18 19
         <a href="${rc.contextPath}/admin/list.html">
@@ -21,7 +22,7 @@
21 22
       </li>
22 23
       <li>
23 24
         <a href="${rc.contextPath}/admin/registrationForm.html">
24
-          Register cargo
25
+          Book new cargo
25 26
         </a>
26 27
       </li>
27 28
     </ul>

+ 24
- 3
dddsample/src/main/webapp/admin.css ファイルの表示

@@ -1,21 +1,38 @@
1
-html,body {
1
+html, body {
2 2
   height: 100%;
3 3
 }
4 4
 
5 5
 body {
6
-  font: Arial, sans-serif; 
6
+  font: Verdana, Arial, sans-serif;
7 7
   color: black;
8 8
   padding: 10px;
9 9
 }
10 10
 
11
+h1 {
12
+  font-weight: lighter;
13
+  font-variant: small-caps;
14
+}
15
+
11 16
 ul#menu {
17
+  border: 1px solid #ccc;
18
+  margin: 40px 0 20px 0;
19
+  padding: 10px 0;
20
+  background: #eee;
12 21
 }
13 22
 
14 23
 ul#menu li {
15
-  margin: 5px;
24
+  margin: 0 0 0 10px;
16 25
   display: inline;
17 26
 }
18 27
 
28
+ul#menu a {
29
+  text-decoration: none;
30
+}
31
+
32
+ul#menu a:hover {
33
+  text-decoration: underline;
34
+}
35
+
19 36
 table {
20 37
 }
21 38
 
@@ -31,3 +48,7 @@ table caption {
31 48
   text-align: left;
32 49
   font-weight: bold;
33 50
 }
51
+
52
+img#logotype {
53
+  float: right;
54
+}

+ 87
- 0
dddsample/src/main/webapp/calendar.css ファイルの表示

@@ -0,0 +1,87 @@
1
+html, body {
2
+	background-color: white;
3
+	color: black;
4
+}
5
+
6
+.calendarTrigger {
7
+	width: 16px;
8
+	height: 16px;
9
+	cursor: pointer;
10
+	vertical-align: top;
11
+	margin-top: 1px;
12
+}
13
+
14
+.calendar {
15
+	position: absolute;
16
+	display: inherit;
17
+	
18
+	font-family: tahoma, verdana, arial, helvetica, sans-serif;
19
+	border: 1px solid blue;
20
+	background-color: white;
21
+}
22
+
23
+
24
+.calendar table {
25
+	border: 4px solid lightblue;
26
+	margin: 0px;
27
+	padding: 0px;
28
+	border-spacing: 2px;
29
+	border-collapse: separate;
30
+}
31
+
32
+.calendar table .goPrevious,
33
+.calendar table .goNext {
34
+	width: 12px;
35
+	background-repeat: no-repeat;
36
+	cursor: pointer;
37
+}
38
+
39
+.calendar table .goPrevious {
40
+	background-image: url( 'navigate_left.gif' );
41
+	background-position: left center;
42
+}
43
+
44
+.calendar table .goNext {
45
+	background-image: url( 'navigate_right.gif' );
46
+	background-position: right center;
47
+}
48
+
49
+.calendar table thead tr:first-child td {
50
+	font-weight: bold;
51
+}
52
+
53
+.calendar table td {
54
+	width: 15px;
55
+	height: 15px;
56
+	font-family: tahoma, verdana, arial, helvetica, sans-serif;
57
+	font-size: 8pt;
58
+	text-align: center;
59
+	padding: 0px 0px 0px 1px;
60
+	border: 0px;
61
+	vertical-align: middle;
62
+}
63
+.calendar table tbody td {
64
+	border: 1px solid gray;
65
+	cursor: pointer;
66
+}
67
+.calendar .disabled {
68
+	background-color: #BBBBBB;
69
+	color: #555555;
70
+}
71
+.calendar .past {
72
+	color: #AAAAAA;
73
+}
74
+.calendar .future {
75
+}
76
+.calendar .today {
77
+	background-color: pink;
78
+}
79
+.calendar .active {
80
+	background-color: #FFAA00;
81
+	border: 1px solid black;
82
+}
83
+
84
+.calendar table tbody td:hover {
85
+	border: 1px solid blue;
86
+	background-color: lightblue;
87
+}

バイナリ
dddsample/src/main/webapp/images/calendarTrigger.gif ファイルの表示


バイナリ
dddsample/src/main/webapp/images/dddsample_logotype_small.png ファイルの表示


+ 63
- 0
dddsample/src/main/webapp/js/YAHOO.js ファイルの表示

@@ -0,0 +1,63 @@
1
+/*
2
+Copyright (c) 2006 Yahoo! Inc. All rights reserved.
3
+version 0.9.0
4
+*/
5
+
6
+/**
7
+ * @class The Yahoo global namespace
8
+ */
9
+var YAHOO = function() {
10
+
11
+    return {
12
+
13
+        /**
14
+         * Yahoo presentation platform utils namespace
15
+         */
16
+        util: {},
17
+
18
+        /**
19
+         * Yahoo presentation platform widgets namespace
20
+         */
21
+        widget: {},
22
+
23
+        /**
24
+         * Yahoo presentation platform examples namespace
25
+         */
26
+        example: {},
27
+
28
+        /**
29
+         * Returns the namespace specified and creates it if it doesn't exist
30
+         *
31
+         * YAHOO.namespace("property.package");
32
+         * YAHOO.namespace("YAHOO.property.package");
33
+         *
34
+         * Either of the above would create YAHOO.property, then
35
+         * YAHOO.property.package
36
+         *
37
+         * @param  {String} sNameSpace String representation of the desired
38
+         *                             namespace
39
+         * @return {Object}            A reference to the namespace object
40
+         */
41
+        namespace: function( sNameSpace ) {
42
+
43
+            if (!sNameSpace || !sNameSpace.length) {
44
+                return null;
45
+            }
46
+
47
+            var levels = sNameSpace.split(".");
48
+
49
+            var currentNS = YAHOO;
50
+
51
+            // YAHOO is implied, so it is ignored if it is included
52
+            for (var i=(levels[0] == "YAHOO") ? 1 : 0; i<levels.length; ++i) {
53
+                currentNS[levels[i]] = currentNS[levels[i]] || {};
54
+                currentNS = currentNS[levels[i]];
55
+            }
56
+
57
+            return currentNS;
58
+
59
+        }
60
+    };
61
+
62
+} ();
63
+

+ 297
- 0
dddsample/src/main/webapp/js/calendar.js ファイルの表示

@@ -0,0 +1,297 @@
1
+function calendar_constructor() {
2
+	var DEFAULT_LANGUAGE = "en";
3
+
4
+	var WEEK_DAYS_LABELS = { 
5
+		en : [ "Su", "Mo", "Tu", "We", "Th", "Fr", "Sa" ],
6
+		pl : [ "Ni", "Po", "Wt", "&#x015A;r", "Cz", "Pt", "So" ]
7
+	};
8
+	var MONTH_NAMES_LABELS = {
9
+		en : [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ],
10
+		pl : [ "Stycze&#x0144;", "Luty", "Marzec", "Kwiecie&#x0144;", "Maj", "Czerwiec", "Lipiec", "Sierpie&#x0144;", "Wrzesie&#x0144;", "Pa&#x017A;dziernik", "Listopad", "Grudzie&#x0144;" ]
11
+	};
12
+	
13
+	var FORMATTERS = {
14
+		en : function( cDate ) {
15
+			return (cDate.getMonth()+1) + "/" + cDate.getDate() + "/" + cDate.getFullYear();
16
+			},
17
+		pl : function( cDate ) {
18
+			return cDate.getDate() + "." + (cDate.getMonth()+1) + "." + cDate.getFullYear();
19
+			}
20
+	}
21
+	var UNFORMATTERS = {
22
+		en : function( stringDate ) {
23
+				var elems = stringDate.split( "/" );
24
+				if ( elems.length != 3 ) return null;
25
+				for ( var i=0; i<elems.length; i++ ) {
26
+					if ( isNaN( elems[ i ] ) ) return null;
27
+				}
28
+				var year = parseInt( elems[ 2 ] );
29
+				if ( year < 100 ) {
30
+					year += 2000;
31
+				}
32
+				return new Date( year,
33
+					parseInt( elems[ 0 ] ) - 1,
34
+					parseInt( elems[ 1 ] ) );
35
+			},
36
+		pl : function( stringDate ) {
37
+				var elems = stringDate.split( "." );
38
+				if ( elems.length != 3 ) return null;
39
+				for ( var i=0; i<elems.length; i++ ) {
40
+					if ( isNaN( elems[ i ] ) ) return null;
41
+				}
42
+				var year = parseInt( elems[ 2 ] );
43
+				if ( year < 100 ) {
44
+					year += 2000;
45
+				}
46
+				return new Date( year,
47
+					parseInt( elems[ 1 ] ) - 1,
48
+					parseInt( elems[ 0 ] ) );
49
+			}
50
+	}
51
+
52
+	var invalidatorInitialized = false;
53
+	var _this = this;
54
+	
55
+	this.calendarBox = null;
56
+	
57
+	this.hideCurrent = function( event, triggerElem ) {
58
+		if ( triggerElem ) {
59
+			if ( event ) { // if manual show/hide do not propagate normal behaviour
60
+				YAHOO.util.Event.stopEvent( event );
61
+			}
62
+		}
63
+		if ( this.calendarBox ) {
64
+			this.calendarBox.style.display = "none";
65
+			if ( this.calendarBox.triggerElem == triggerElem ) {
66
+				this.calendarBox = null;
67
+				return true;
68
+			}
69
+			this.calendarBox = null;
70
+		}
71
+		return false;
72
+	};
73
+	
74
+	function cleanupMe( event ) {
75
+		this.hideCurrent( event );
76
+	}
77
+
78
+	function cleanupMeKey( event ) {
79
+		if ( event.keyCode == 27 ) {
80
+			this.hideCurrent( event );
81
+		} else {
82
+			if ( this.calendarBox ) {
83
+				if ( event.keyCode == 37 ) { // arrow left
84
+					this.calendarBox.prev()
85
+				} else if ( event.keyCode == 39 ) { // arrow right
86
+					this.calendarBox.next()
87
+				}
88
+			}
89
+		}
90
+	}
91
+	
92
+	function initializeCleanups() {
93
+		invalidatorInitialized = true;
94
+		YAHOO.util.Event.addListener( document, "click", cleanupMe, _this, true );
95
+		YAHOO.util.Event.addListener( document, "keypress", cleanupMeKey, _this, true );
96
+	}
97
+	
98
+	this.toggle = function ( event, triggerElem, inputId ) {
99
+	
100
+		if ( this.hideCurrent( event, triggerElem ) ) {
101
+			return false;
102
+		}
103
+		
104
+		// set the date that is set as actual in input field
105
+		var today = new Date();
106
+		today = new Date( today.getFullYear(), today.getMonth(), today.getDate() );
107
+		
108
+		var input = document.getElementById( inputId );
109
+		// (re)create the div container of calendar
110
+		var calendarShowed = document.createElement( "div" );
111
+		calendarShowed.input = input;
112
+		calendarShowed.triggerElem = triggerElem;
113
+		calendarShowed.className = "calendar";
114
+		// obtain language code (ISO 639) to use for formatting and labels 
115
+		calendarShowed.currentLang = document.getElementsByTagName( "html" )[ 0 ].lang;
116
+		if ( !calendarShowed.currentLang ) {
117
+			if ( navigator.userLanguage ) {
118
+				// obtain language from browser settings
119
+				calendarShowed.currentLang = navigator.userLanguage;
120
+			}
121
+		}
122
+		// -- decode current date set in textfield if possible
123
+		var unF = getLocalizedEntry( UNFORMATTERS, calendarShowed.currentLang );
124
+		var activeDate = unF( getDateValue( calendarShowed ) );
125
+		if ( !activeDate ) { // fallback if undecoding failed
126
+			activeDate = today;
127
+		}
128
+		calendarShowed.activeDate = activeDate;
129
+		
130
+		this.calendarBox = calendarShowed;
131
+		
132
+		var elementRegion = YAHOO.util.Dom.getRegion( triggerElem );
133
+		calendarShowed.style.top = ( elementRegion.bottom ) + "px";
134
+		calendarShowed.style.left = ( elementRegion.left ) + "px";
135
+	
136
+		//var calendarShowed = this.calendarShowed;
137
+		// fill the contents of calendar for a month taken from actual date	
138
+		calendarShowed.innerHTML = createContents( calendarShowed, 
139
+			activeDate.getFullYear(), activeDate.getMonth(), activeDate.getDate() );
140
+		
141
+		var _this = this;
142
+		calendarShowed.prev = function() {
143
+			calendarShowed.currentMonth.setMonth( calendarShowed.currentMonth.getMonth() - 1 );
144
+			calendarShowed.innerHTML = createContents( calendarShowed );
145
+		};
146
+		calendarShowed.next = function() {
147
+			calendarShowed.currentMonth.setMonth( calendarShowed.currentMonth.getMonth() + 1 );
148
+			calendarShowed.innerHTML = createContents( calendarShowed );
149
+		};
150
+		calendarShowed.select = function( tdElem ) {
151
+			calendarShowed.currentMonth.setDate( parseInt( tdElem.innerHTML ) );
152
+			var formattingF = getLocalizedEntry( FORMATTERS, calendarShowed.currentLang );
153
+			var inputToStoreValue = setDateValue( calendarShowed, formattingF( calendarShowed.currentMonth ) );
154
+			inputToStoreValue.focus();
155
+		}
156
+		
157
+		// add the calendar to document for display
158
+		document.getElementsByTagName("body")[0].appendChild( calendarShowed );
159
+
160
+		if ( !invalidatorInitialized ) {
161
+			initializeCleanups();
162
+		}
163
+
164
+		return false;
165
+	};
166
+	
167
+	function setDateValue( calendar, stringValue ) {
168
+		var inputToStoreValue = obtainInputField( calendar );
169
+		inputToStoreValue.value = stringValue;
170
+		return inputToStoreValue;
171
+	}
172
+
173
+	function getDateValue( calendar ) {
174
+		var inputToStoreValue = obtainInputField( calendar );
175
+		return inputToStoreValue.value;
176
+	}
177
+
178
+	// very private function
179
+	function obtainInputField( calendar ) {
180
+		var inputToStoreValue = null;
181
+		if ( calendar.input.dynamicId ) {
182
+			inputToStoreValue = document.getElementById( calendar.input.dynamicId );
183
+			if ( inputToStoreValue ) { // if found not a text input - use default one
184
+				//alert( inputToStoreValue.tagName );
185
+				if ( inputToStoreValue.tagName != "INPUT" ) {
186
+					inputToStoreValue = null; 
187
+				}
188
+			}
189
+		}
190
+		if ( !inputToStoreValue ) { // fallback
191
+			inputToStoreValue = calendar.input;
192
+		}
193
+		return inputToStoreValue;
194
+	}
195
+
196
+
197
+
198
+	function getLocalizedEntry( arr, language ) {
199
+		var entry = arr[ language ];
200
+		if ( !entry ) {
201
+			entry = arr[ DEFAULT_LANGUAGE ];
202
+		}
203
+		return entry;
204
+	}
205
+
206
+	function createContents( elem, year, month, day ) { // year, month, day are optional in nonfirst calls
207
+		if ( elem.currentMonth ) {
208
+			year = elem.currentMonth.getFullYear();
209
+			month = elem.currentMonth.getMonth();
210
+			day = elem.currentMonth.getDate();
211
+		} else {
212
+			elem.currentMonth = new Date( year, month, 1 );
213
+		}
214
+		
215
+		var dateC = new Date( elem.currentMonth.getFullYear(), elem.currentMonth.getMonth(), 1 );
216
+		var today = new Date();
217
+		today = new Date( today.getFullYear(), today.getMonth(), today.getDate() );
218
+		
219
+		var iHtml = "<table>\n";
220
+		iHtml += "<thead><tr>";
221
+		iHtml += "<td class=\"goPrevious\" onclick=\"calendar.calendarBox.prev()\"></td>";
222
+		iHtml += "<td colspan=\"5\">";
223
+		iHtml += getDateHeaderLabel( elem.currentLang, dateC );
224
+		iHtml += "</td>";
225
+		iHtml += "<td class=\"goNext\" onclick=\"calendar.calendarBox.next()\"></td>";
226
+		iHtml += "</tr>";
227
+		iHtml += "<tr>";
228
+		var wDL = getWeekDaysLabels( elem.currentLang );
229
+		for ( var i=0; i<wDL.length; i++ ) {
230
+			iHtml += "<td>" + wDL[ i ] + "</td>";
231
+		}
232
+		iHtml += "</tr>";
233
+		iHtml += "</thead>";
234
+	
235
+		iHtml += "<tbody>\n";
236
+		var dayOfWeek = dateC.getDay(); // 0 - sunday, ..
237
+		iHtml += "<tr>";
238
+		if ( dayOfWeek > 0 ) {
239
+			dateC.setDate( -dayOfWeek + 1 );
240
+			for ( var i=0; i<dayOfWeek; i++ ) {
241
+				iHtml += "<td class=\"disabled\">" + dateC.getDate() + "</td>";
242
+				dateC.setDate( dateC.getDate() + 1 );
243
+			}
244
+		}
245
+		var accu = dayOfWeek;
246
+		var tdClass = null;
247
+		while ( dateC.getMonth() == month ) {
248
+			if ( accu % 7 == 0 ) {
249
+				accu = 0;
250
+				iHtml += "<tr>";
251
+			}
252
+			// note: simple equality checking is not sufficient here as it will check for reference equality
253
+			if (!( dateC > elem.activeDate ) && !( dateC < elem.activeDate )) {
254
+				tdClass = "active";
255
+			} else {
256
+				if ( dateC < today ) {
257
+					tdClass = "past";
258
+				} else if ( dateC > today ) {
259
+					tdClass = "future";
260
+				} else {
261
+					tdClass = "today";
262
+				}
263
+			}
264
+			iHtml += "<td class='" + tdClass + "' onclick=\"calendar.calendarBox.select(this)\">" + dateC.getDate() + "</td>";
265
+			dateC.setDate( dateC.getDate() + 1 );
266
+			accu++;
267
+	
268
+			if ( accu % 7 == 0 ) {
269
+				iHtml += "</tr>\n";
270
+			}
271
+		}
272
+		//..
273
+		dayOfWeek = dateC.getDay();
274
+		if ( dayOfWeek != 0 ) {
275
+			for ( var i=dayOfWeek; i<7; i++ ) {
276
+				iHtml += "<td class=\"disabled\">" + dateC.getDate() + "</td>";
277
+				dateC.setDate( dateC.getDate() + 1 );
278
+			}
279
+			iHtml += "</tr>\n";
280
+		}
281
+		
282
+		iHtml += "</tbody>";
283
+		iHtml += "</table>";
284
+		return iHtml;
285
+	};
286
+	
287
+	function getWeekDaysLabels( languageCode ) {
288
+		return getLocalizedEntry( WEEK_DAYS_LABELS, languageCode );
289
+	}
290
+	
291
+	function getDateHeaderLabel( languageCode, curDate ) {
292
+		var labels = getLocalizedEntry( MONTH_NAMES_LABELS, languageCode );
293
+		return labels[ curDate.getMonth() ] + "&nbsp;" + curDate.getFullYear();
294
+	};
295
+
296
+}
297
+calendar = new calendar_constructor();

+ 433
- 0
dddsample/src/main/webapp/js/dom.js ファイルの表示

@@ -0,0 +1,433 @@
1
+/*
2
+Copyright (c) 2006 Yahoo! Inc. All rights reserved.
3
+version 0.9.0
4
+*/
5
+
6
+/**
7
+ * @class Provides helper methods for DOM elements.
8
+ */
9
+YAHOO.util.Dom = new function() {
10
+
11
+   /**
12
+    * Returns an HTMLElement reference
13
+    * @param {String | HTMLElement} Accepts either a string to use as an ID for getting a DOM reference, or an actual DOM reference.
14
+    * @return {HTMLElement} A DOM reference to an HTML element.
15
+    */
16
+   this.get = function(el) {
17
+      if (typeof el == 'string') { // accept object or id
18
+         el = document.getElementById(el);
19
+      }
20
+
21
+      return el;
22
+   };
23
+
24
+   /**
25
+    * Normalizes currentStyle and ComputedStyle.
26
+    * @param {String | HTMLElement} Accepts either a string to use as an ID for getting a DOM reference, or an actual DOM reference.
27
+    * @param {String} property The style property whose value is returned.
28
+    * @return {String} The current value of the style property.
29
+    */
30
+   this.getStyle = function(el, property) {
31
+      var value = null;
32
+      var dv = document.defaultView;
33
+
34
+      el = this.get(el);
35
+
36
+      if (property == 'opacity' && el.filters) {// IE opacity
37
+         value = 1;
38
+         try {
39
+            value = el.filters.item('DXImageTransform.Microsoft.Alpha').opacity / 100;
40
+         } catch(e) {
41
+            try {
42
+               value = el.filters.item('alpha').opacity / 100;
43
+            } catch(e) {}
44
+         }
45
+      }
46
+      else if (el.style[property]) {
47
+         value = el.style[property];
48
+      }
49
+      else if (el.currentStyle && el.currentStyle[property]) {
50
+         value = el.currentStyle[property];
51
+      }
52
+      else if ( dv && dv.getComputedStyle )
53
+      {  // convert camelCase to hyphen-case
54
+
55
+         var converted = '';
56
+         for(i = 0, len = property.length;i < len; ++i) {
57
+            if (property.charAt(i) == property.charAt(i).toUpperCase()) {
58
+               converted = converted + '-' + property.charAt(i).toLowerCase();
59
+            } else {
60
+               converted = converted + property.charAt(i);
61
+            }
62
+         }
63
+
64
+         if (dv.getComputedStyle(el, '').getPropertyValue(converted)) {
65
+            value = dv.getComputedStyle(el, '').getPropertyValue(converted);
66
+         }
67
+      }
68
+
69
+      return value;
70
+   };
71
+
72
+   /**
73
+    * Wrapper for setting style properties of HTMLElements.  Normalizes "opacity" across modern browsers.
74
+    * @param {String | HTMLElement} Accepts either a string to use as an ID for getting a DOM reference, or an actual DOM reference.
75
+    * @param {String} property The style property to be set.
76
+    * @param {String} val The value to apply to the given property.
77
+    */
78
+   this.setStyle = function(el, property, val) {
79
+      el = this.get(el);
80
+      switch(property) {
81
+         case 'opacity' :
82
+            if (el.filters) {
83
+               el.style.filter = 'alpha(opacity=' + val * 100 + ')';
84
+
85
+               if (!el.currentStyle.hasLayout) {
86
+                  el.style.zoom = 1;
87
+               }
88
+            } else {
89
+               el.style.opacity = val;
90
+               el.style['-moz-opacity'] = val;
91
+               el.style['-khtml-opacity'] = val;
92
+            }
93
+            break;
94
+         default :
95
+            el.style[property] = val;
96
+      }
97
+   };
98
+
99
+   /**
100
+    * Gets the current position of an element based on page coordinates.  Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
101
+    * @param {String | HTMLElement} Accepts either a string to use as an ID for getting a DOM reference, or an actual DOM reference.
102
+    */
103
+   this.getXY = function(el) {
104
+      el = this.get(el);
105
+
106
+      // has to be part of document to have pageXY
107
+      if (el.parentNode === null || this.getStyle(el, 'display') == 'none') {
108
+         return false;
109
+      }
110
+
111
+      /**
112
+       * Position of the html element (x, y)
113
+       * @private
114
+       * @type Array
115
+       */
116
+      var parent = null;
117
+      var pos = [];
118
+      var box;
119
+
120
+      if (el.getBoundingClientRect) { // IE
121
+         box = el.getBoundingClientRect();
122
+         var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
123
+         var scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft;
124
+
125
+         return [box.left + scrollLeft, box.top + scrollTop];
126
+      }
127
+      else if (document.getBoxObjectFor) { // gecko
128
+         box = document.getBoxObjectFor(el);
129
+         pos = [box.x, box.y];
130
+      }
131
+      else { // safari/opera
132
+         pos = [el.offsetLeft, el.offsetTop];
133
+         parent = el.offsetParent;
134
+         if (parent != el) {
135
+            while (parent) {
136
+               pos[0] += parent.offsetLeft;
137
+               pos[1] += parent.offsetTop;
138
+               parent = parent.offsetParent;
139
+            }
140
+         }
141
+
142
+         // opera & (safari absolute) incorrectly account for body offsetTop
143
+         var ua = navigator.userAgent.toLowerCase();
144
+         if (
145
+            ua.indexOf('opera') != -1
146
+            || ( ua.indexOf('safari') != -1 && this.getStyle(el, 'position') == 'absolute' )
147
+         ) {
148
+            pos[1] -= document.body.offsetTop;
149
+         }
150
+      }
151
+
152
+      if (el.parentNode) { parent = el.parentNode; }
153
+      else { parent = null; }
154
+
155
+      while (parent && parent.tagName != 'BODY' && parent.tagName != 'HTML') {
156
+         pos[0] -= parent.scrollLeft;
157
+         pos[1] -= parent.scrollTop;
158
+
159
+         if (parent.parentNode) { parent = parent.parentNode; }
160
+         else { parent = null; }
161
+      }
162
+
163
+      return pos;
164
+   };
165
+
166
+   /**
167
+    * Gets the current X position of an element based on page coordinates.  The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
168
+    * @param {String | HTMLElement} Accepts either a string to use as an ID for getting a DOM reference, or an actual DOM reference.
169
+    */
170
+   this.getX = function(el) {
171
+      return this.getXY(el)[0];
172
+   };
173
+
174
+   /**
175
+    * Gets the current Y position of an element based on page coordinates.  Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
176
+    * @param {String | HTMLElement} Accepts either a string to use as an ID for getting a DOM reference, or an actual DOM reference.
177
+    */
178
+   this.getY = function(el) {
179
+      return this.getXY(el)[1];
180
+   };
181
+
182
+   /**
183
+    * Set the position of an html element in page coordinates, regardless of how the element is positioned.
184
+    * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
185
+    * @param {String | HTMLElement} Accepts either a string to use as an ID for getting a DOM reference, or an actual DOM reference.
186
+    * @param {array} pos Contains X & Y values for new position (coordinates are page-based)
187
+    */
188
+   this.setXY = function(el, pos, noRetry) {
189
+      el = this.get(el);
190
+      var pageXY = YAHOO.util.Dom.getXY(el);
191
+      if (pageXY === false) { return false; } // has to be part of doc to have pageXY
192
+
193
+      if (this.getStyle(el, 'position') == 'static') { // default to relative
194
+         this.setStyle(el, 'position', 'relative');
195
+      }
196
+
197
+      var delta = [
198
+         parseInt( YAHOO.util.Dom.getStyle(el, 'left'), 10 ),
199
+         parseInt( YAHOO.util.Dom.getStyle(el, 'top'), 10 )
200
+      ];
201
+
202
+      if ( isNaN(delta[0]) ) { delta[0] = 0; } // defalts to 'auto'
203
+      if ( isNaN(delta[1]) ) { delta[1] = 0; }
204
+
205
+      if (pos[0] !== null) { el.style.left = pos[0] - pageXY[0] + delta[0] + 'px'; }
206
+      if (pos[1] !== null) { el.style.top = pos[1] - pageXY[1] + delta[1] + 'px'; }
207
+
208
+      var newXY = this.getXY(el);
209
+
210
+      // if retry is true, try one more time if we miss
211
+      if (!noRetry && (newXY[0] != pos[0] || newXY[1] != pos[1]) ) {
212
+         this.setXY(el, pos, true);
213
+      }
214
+
215
+      return true;
216
+   };
217
+
218
+   /**
219
+    * Set the X position of an html element in page coordinates, regardless of how the element is positioned.
220
+    * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
221
+    * @param {String | HTMLElement} Accepts either a string to use as an ID for getting a DOM reference, or an actual DOM reference.
222
+    * @param {Int} x to use as the X coordinate.
223
+    */
224
+   this.setX = function(el, x) {
225
+      return this.setXY(el, [x, null]);
226
+   };
227
+
228
+   /**
229
+    * Set the Y position of an html element in page coordinates, regardless of how the element is positioned.
230
+    * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
231
+    * @param {String | HTMLElement} Accepts either a string to use as an ID for getting a DOM reference, or an actual DOM reference.
232
+    * @param {Int} Value to use as the Y coordinate.
233
+    */
234
+   this.setY = function(el, y) {
235
+      return this.setXY(el, [null, y]);
236
+   };
237
+
238
+   /**
239
+    * Returns the region position of the given element.
240
+    * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
241
+    * @param {String | HTMLElement} Accepts either a string to use as an ID for getting a DOM reference, or an actual DOM reference.
242
+    * @return {Region} A Region instance containing "top, left, bottom, right" member data.
243
+    */
244
+   this.getRegion = function(el) {
245
+      el = this.get(el);
246
+      return new YAHOO.util.Region.getRegion(el);
247
+   };
248
+
249
+   /**
250
+    * Returns the width of the client (viewport).
251
+    * @return {Int} The width of the viewable area of the page.
252
+    */
253
+   this.getClientWidth = function() {
254
+      return (
255
+         document.documentElement.offsetWidth
256
+         || document.body.offsetWidth
257
+      );
258
+   };
259
+
260
+   /**
261
+    * Returns the height of the client (viewport).
262
+    * @return {Int} The height of the viewable area of the page.
263
+    */
264
+   this.getClientHeight = function() {
265
+      return (
266
+         self.innerHeight
267
+         || document.documentElement.clientHeight
268
+         || document.body.clientHeight
269
+      );
270
+   };
271
+};
272
+
273
+/**
274
+ * @class A region is a representation of an object on a grid.  It is defined
275
+ * by the top, right, bottom, left extents, so is rectangular by default.  If
276
+ * other shapes are required, this class could be extended to support it.
277
+ *
278
+ * @param {int} t the top extent
279
+ * @param {int} r the right extent
280
+ * @param {int} b the bottom extent
281
+ * @param {int} l the left extent
282
+ * @constructor
283
+ */
284
+YAHOO.util.Region = function(t, r, b, l) {
285
+
286
+    /**
287
+     * The region's top extent
288
+     * @type int
289
+     */
290
+    this.top = t;
291
+
292
+    /**
293
+     * The region's right extent
294
+     * @type int
295
+     */
296
+    this.right = r;
297
+
298
+    /**
299
+     * The region's bottom extent
300
+     * @type int
301
+     */
302
+    this.bottom = b;
303
+
304
+    /**
305
+     * The region's left extent
306
+     * @type int
307
+     */
308
+    this.left = l;
309
+};
310
+
311
+/**
312
+ * Returns true if this region contains the region passed in
313
+ *
314
+ * @param  {Region}  region The region to evaluate
315
+ * @return {boolean}        True if the region is contained with this region,
316
+ *                          else false
317
+ */
318
+YAHOO.util.Region.prototype.contains = function(region) {
319
+    return ( region.left   >= this.left   &&
320
+             region.right  <= this.right  &&
321
+             region.top    >= this.top    &&
322
+             region.bottom <= this.bottom    );
323
+};
324
+
325
+/**
326
+ * Returns the area of the region
327
+ *
328
+ * @return {int} the region's area
329
+ */
330
+YAHOO.util.Region.prototype.getArea = function() {
331
+    return ( (this.bottom - this.top) * (this.right - this.left) );
332
+};
333
+
334
+/**
335
+ * Returns the region where the passed in region overlaps with this one
336
+ *
337
+ * @param  {Region} region The region that intersects
338
+ * @return {Region}        The overlap region, or null if there is no overlap
339
+ */
340
+YAHOO.util.Region.prototype.intersect = function(region) {
341
+    var t = Math.max( this.top,    region.top    );
342
+    var r = Math.min( this.right,  region.right  );
343
+    var b = Math.min( this.bottom, region.bottom );
344
+    var l = Math.max( this.left,   region.left   );
345
+
346
+    if (b >= t && r >= l) {
347
+        return new YAHOO.util.Region(t, r, b, l);
348
+    } else {
349
+        return null;
350
+    }
351
+};
352
+
353
+/**
354
+ * Returns the region representing the smallest region that can contain both
355
+ * the passed in region and this region.
356
+ *
357
+ * @param  {Region} region The region that to create the union with
358
+ * @return {Region}        The union region
359
+ */
360
+YAHOO.util.Region.prototype.union = function(region) {
361
+    var t = Math.min( this.top,    region.top    );
362
+    var r = Math.max( this.right,  region.right  );
363
+    var b = Math.max( this.bottom, region.bottom );
364
+    var l = Math.min( this.left,   region.left   );
365
+
366
+    return new YAHOO.util.Region(t, r, b, l);
367
+};
368
+
369
+/**
370
+ * toString
371
+ * @return string the region properties
372
+ */
373
+YAHOO.util.Region.prototype.toString = function() {
374
+    return ( "Region {" +
375
+             "  t: "    + this.top    +
376
+             ", r: "    + this.right  +
377
+             ", b: "    + this.bottom +
378
+             ", l: "    + this.left   +
379
+             "}" );
380
+}
381
+
382
+/**
383
+ * Returns a region that is occupied by the DOM element
384
+ *
385
+ * @param  {HTMLElement} el The element
386
+ * @return {Region}         The region that the element occupies
387
+ * @static
388
+ */
389
+YAHOO.util.Region.getRegion = function(el) {
390
+    var p = YAHOO.util.Dom.getXY(el);
391
+
392
+    var t = p[1];
393
+    var r = p[0] + el.offsetWidth;
394
+    var b = p[1] + el.offsetHeight;
395
+    var l = p[0];
396
+
397
+    return new YAHOO.util.Region(t, r, b, l);
398
+};
399
+
400
+/////////////////////////////////////////////////////////////////////////////
401
+
402
+
403
+/**
404
+ * @class
405
+ *
406
+ * A point is a region that is special in that it represents a single point on
407
+ * the grid.
408
+ *
409
+ * @param {int} x The X position of the point
410
+ * @param {int} y The Y position of the point
411
+ * @constructor
412
+ * @extends Region
413
+ */
414
+YAHOO.util.Point = function(x, y) {
415
+    /**
416
+     * The X position of the point
417
+     * @type int
418
+     */
419
+    this.x      = x;
420
+
421
+    /**
422
+     * The Y position of the point
423
+     * @type int
424
+     */
425
+    this.y      = y;
426
+
427
+    this.top    = y;
428
+    this.right  = x;
429
+    this.bottom = y;
430
+    this.left   = x;
431
+};
432
+
433
+YAHOO.util.Point.prototype = new YAHOO.util.Region();

+ 901
- 0
dddsample/src/main/webapp/js/event.js ファイルの表示

@@ -0,0 +1,901 @@
1
+/*
2
+Copyright (c) 2006 Yahoo! Inc. All rights reserved.
3
+version 0.9.0
4
+*/
5
+
6
+/**
7
+ * @class The CustomEvent class lets you define events for your application
8
+ * that can be subscribed to by one or more independent component.
9
+ * @param {String} type The type of event, which is passed to the callback
10
+ *                 when the event fires
11
+ * @param {Object} oScope The context the event will fire from.  "this" will
12
+ *                 refer to this object in the callback.  Default value:
13
+ *                 the window object.  The listener can override this.
14
+ * @constructor
15
+ */
16
+YAHOO.util.CustomEvent = function(type, oScope) {
17
+    /**
18
+     * The type of event, returned to subscribers when the event fires
19
+     * @type string
20
+     */
21
+    this.type = type;
22
+
23
+    /**
24
+     * The scope the the event will fire from.  Defaults to the window obj
25
+     * @type object
26
+     */
27
+    this.scope = oScope || window;
28
+
29
+    /**
30
+     * The subscribers to this event
31
+     * @type array
32
+     */
33
+    this.subscribers = [];
34
+
35
+    // Register with the event utility for automatic cleanup.  Made optional
36
+    // so that CustomEvent can be used independently of pe.event
37
+    if (YAHOO.util["Event"]) {
38
+        YAHOO.util.Event.regCE(this);
39
+    }
40
+};
41
+
42
+YAHOO.util.CustomEvent.prototype = {
43
+    /**
44
+     * Subscribes the caller to this event
45
+     * @param {Function} fn       The function to execute
46
+     * @param {Object}   obj      An object to be passed along when the event fires
47
+     * @param {boolean}  bOverride If true, the obj passed in becomes the execution
48
+     *                            scope of the listener
49
+     */
50
+    subscribe: function(fn, obj, bOverride) {
51
+        this.subscribers.push( new YAHOO.util.Subscriber(fn, obj, bOverride) );
52
+    },
53
+
54
+    /**
55
+     * Unsubscribes the caller from this event
56
+     * @param {Function} fn  The function to execute
57
+     * @param {Object}   obj An object to be passed along when the event fires
58
+     * @return {boolean} True if the subscriber was found and detached.
59
+     */
60
+    unsubscribe: function(fn, obj) {
61
+        var found = false;
62
+        for (var i=0; i<this.subscribers.length; ++i) {
63
+            var s = this.subscribers[i];
64
+            if (s && s.contains(fn, obj)) {
65
+                this._delete(i);
66
+                found = true;
67
+            }
68
+        }
69
+
70
+        return found;
71
+    },
72
+
73
+    /**
74
+     * Notifies the subscribers.  The callback functions will be executed
75
+     * from the scope specified when the event was created, and with the following
76
+     * parameters:
77
+     *   <pre>
78
+     *   - The type of event
79
+     *   - All of the arguments fire() was executed with as an array
80
+     *   - The custom object (if any) that was passed into the subscribe() method
81
+     *   </pre>
82
+     *
83
+     * @param {Array} an arbitrary set of parameters to pass to the handler
84
+     */
85
+    fire: function() {
86
+        for (var i=0; i<this.subscribers.length; ++i) {
87
+            var s = this.subscribers[i];
88
+            if (s) {
89
+                var scope = (s.override) ? s.obj : this.scope;
90
+                s.fn.call(scope, this.type, arguments, s.obj);
91
+            }
92
+        }
93
+    },
94
+
95
+    /**
96
+     * Removes all listeners
97
+     */
98
+    unsubscribeAll: function() {
99
+        for (var i=0; i<this.subscribers.length; ++i) {
100
+            this._delete(i);
101
+        }
102
+    },
103
+
104
+    /**
105
+     * @private
106
+     */
107
+    _delete: function(index) {
108
+        var s = this.subscribers[index];
109
+        if (s) {
110
+            delete s.fn;
111
+            delete s.obj;
112
+        }
113
+
114
+        delete this.subscribers[index];
115
+    }
116
+};
117
+
118
+/////////////////////////////////////////////////////////////////////
119
+
120
+/**
121
+ * @class
122
+ * @param {Function} fn       The function to execute
123
+ * @param {Object}   obj      An object to be passed along when the event fires
124
+ * @param {boolean}  bOverride If true, the obj passed in becomes the execution
125
+ *                            scope of the listener
126
+ * @constructor
127
+ */
128
+YAHOO.util.Subscriber = function(fn, obj, bOverride) {
129
+    /**
130
+     * The callback that will be execute when the event fires
131
+     * @type function
132
+     */
133
+    this.fn = fn;
134
+
135
+    /**
136
+     * An optional custom object that will passed to the callback when
137
+     * the event fires
138
+     * @type object
139
+     */
140
+    this.obj = obj || null;
141
+
142
+    /**
143
+     * The default execution scope for the event listener is defined when the
144
+     * event is created (usually the object which contains the event).
145
+     * By setting override to true, the execution scope becomes the custom
146
+     * object passed in by the subscriber
147
+     * @type boolean
148
+     */
149
+    this.override = (bOverride);
150
+};
151
+
152
+/**
153
+ * Returns true if the fn and obj match this objects properties.
154
+ * Used by the unsubscribe method to match the right subscriber.
155
+ *
156
+ * @param {Function} fn the function to execute
157
+ * @param {Object} obj an object to be passed along when the event fires
158
+ * @return {boolean} true if the supplied arguments match this
159
+ *                   subscriber's signature.
160
+ */
161
+YAHOO.util.Subscriber.prototype.contains = function(fn, obj) {
162
+    return (this.fn == fn && this.obj == obj);
163
+};
164
+
165
+/* Copyright (c) 2006 Yahoo! Inc. All rights reserved. */
166
+
167
+// Only load this library once.  If it is loaded a second time, existing
168
+// events cannot be detached.
169
+if (!YAHOO.util.Event) {
170
+
171
+/**
172
+ * The event utility provides functions to add and remove event listeners,
173
+ * event cleansing.  It also tries to automatically remove listeners it
174
+ * registers during the unload event.
175
+ * @class
176
+ * @constructor
177
+ */
178
+    YAHOO.util.Event = function() {
179
+
180
+        /**
181
+         * True after the onload event has fired
182
+         * @type boolean
183
+         * @private
184
+         */
185
+        var loadComplete =  false;
186
+
187
+        /**
188
+         * Cache of wrapped listeners
189
+         * @type array
190
+         * @private
191
+         */
192
+        var listeners = [];
193
+
194
+        /**
195
+         * Listeners that will be attached during the onload event
196
+         * @type array
197
+         * @private
198
+         */
199
+        var delayedListeners = [];
200
+
201
+        /**
202
+         * User-defined unload function that will be fired before all events
203
+         * are detached
204
+         * @type array
205
+         * @private
206
+         */
207
+        var unloadListeners = [];
208
+
209
+        /**
210
+         * Cache of the custom events that have been defined.  Used for
211
+         * automatic cleanup
212
+         * @type array
213
+         * @private
214
+         */
215
+        var customEvents = [];
216
+
217
+        /**
218
+         * Cache of DOM0 event handlers to work around issues with DOM2 events
219
+         * in Safari
220
+         * @private
221
+         */
222
+        var legacyEvents = [];
223
+
224
+        /**
225
+         * Listener stack for DOM0 events
226
+         * @private
227
+         */
228
+        var legacyHandlers = [];
229
+
230
+        return { // PREPROCESS
231
+
232
+            /**
233
+             * Element to bind, int constant
234
+             * @type int
235
+             */
236
+            EL: 0,
237
+
238
+            /**
239
+             * Type of event, int constant
240
+             * @type int
241
+             */
242
+            TYPE: 1,
243
+
244
+            /**
245
+             * Function to execute, int constant
246
+             * @type int
247
+             */
248
+            FN: 2,
249
+
250
+            /**
251
+             * Function wrapped for scope correction and cleanup, int constant
252
+             * @type int
253
+             */
254
+            WFN: 3,
255
+
256
+            /**
257
+             * Object passed in by the user that will be returned as a
258
+             * parameter to the callback, int constant
259
+             * @type int
260
+             */
261
+            SCOPE: 3,
262
+
263
+            /**
264
+             * Adjusted scope, either the element we are registering the event
265
+             * on or the custom object passed in by the listener, int constant
266
+             * @type int
267
+             */
268
+            ADJ_SCOPE: 4,
269
+
270
+            /**
271
+             * Safari detection is necessary to work around the preventDefault
272
+             * bug that makes it so you can't cancel a href click from the
273
+             * handler.  There is not a capabilities check we can use here.
274
+             * @private
275
+             */
276
+            isSafari: (navigator.userAgent.match(/safari/gi)),
277
+
278
+            /**
279
+             * @private
280
+             * IE detection needed to properly calculate pageX and pageY.
281
+             * capabilities checking didn't seem to work because another
282
+             * browser that does not provide the properties have the values
283
+             * calculated in a different manner than IE.
284
+             */
285
+            isIE: (!this.isSafari && navigator.userAgent.match(/msie/gi)),
286
+
287
+            /**
288
+             * Appends an event handler
289
+             *
290
+             * @param {Object}   el        The html element to assign the
291
+             *                             event to
292
+             * @param {String}   sType     The type of event to append
293
+             * @param {Function} fn        The method the event invokes
294
+             * @param {Object}   oScope    An arbitrary object that will be
295
+             *                             passed as a parameter to the handler
296
+             * @param {boolean}  bOverride If true, the obj passed in becomes
297
+             *                             the execution scope of the listener
298
+             * @return {boolean} True if the action was successful or defered,
299
+             *                        false if one or more of the elements
300
+             *                        could not have the event bound to it.
301
+             */
302
+            addListener: function(el, sType, fn, oScope, bOverride) {
303
+
304
+                // The el argument can be an array of elements or element ids.
305
+                if ( this._isValidCollection(el)) {
306
+                    var ok = true;
307
+                    for (var i=0; i< el.length; ++i) {
308
+                        ok = ( this.on(el[i],
309
+                                       sType,
310
+                                       fn,
311
+                                       oScope,
312
+                                       bOverride) && ok );
313
+                    }
314
+                    return ok;
315
+
316
+                } else if (typeof el == "string") {
317
+                    // If the el argument is a string, we assume it is
318
+                    // actually the id of the element.  If the page is loaded
319
+                    // we convert el to the actual element, otherwise we
320
+                    // defer attaching the event until onload event fires
321
+
322
+                    // check to see if we need to delay hooking up the event
323
+                    // until after the page loads.
324
+                    if (loadComplete) {
325
+                        el = this.getEl(el);
326
+                    } else {
327
+                        // defer adding the event until onload fires
328
+                        delayedListeners[delayedListeners.length] =
329
+                            [el, sType, fn, oScope, bOverride];
330
+
331
+                        return true;
332
+                    }
333
+                }
334
+
335
+                // Element should be an html element or an array if we get
336
+                // here.
337
+                if (!el) {
338
+                    return false;
339
+                }
340
+
341
+                // we need to make sure we fire registered unload events
342
+                // prior to automatically unhooking them.  So we hang on to
343
+                // these instead of attaching them to the window and fire the
344
+                // handles explicitly during our one unload event.
345
+                if ("unload" == sType && oScope !== this) {
346
+                    unloadListeners[unloadListeners.length] =
347
+                            [el, sType, fn, oScope, bOverride];
348
+                    return true;
349
+                }
350
+
351
+
352
+                // if the user chooses to override the scope, we use the custom
353
+                // object passed in, otherwise the executing scope will be the
354
+                // HTML element that the event is registered on
355
+                var scope = (bOverride) ? oScope : el;
356
+
357
+                // wrap the function so we can return the oScope object when
358
+                // the event fires;
359
+                var wrappedFn = function(e) {
360
+                        return fn.call(scope, YAHOO.util.Event.getEvent(e),
361
+                                oScope);
362
+                    };
363
+
364
+                var li = [el, sType, fn, wrappedFn, scope];
365
+                var index = listeners.length;
366
+                // cache the listener so we can try to automatically unload
367
+                listeners[index] = li;
368
+
369
+                if (this.useLegacyEvent(el, sType)) {
370
+                    var legacyIndex = this.getLegacyIndex(el, sType);
371
+                    if (legacyIndex == -1) {
372
+
373
+                        legacyIndex = legacyEvents.length;
374
+                        // cache the signature for the DOM0 event, and
375
+                        // include the existing handler for the event, if any
376
+                        legacyEvents[legacyIndex] =
377
+                            [el, sType, el["on" + sType]];
378
+                        legacyHandlers[legacyIndex] = [];
379
+
380
+                        el["on" + sType] =
381
+                            function(e) {
382
+                                YAHOO.util.Event.fireLegacyEvent(
383
+                                    YAHOO.util.Event.getEvent(e), legacyIndex);
384
+                            };
385
+                    }
386
+
387
+                    // add a reference to the wrapped listener to our custom
388
+                    // stack of events
389
+                    legacyHandlers[legacyIndex].push(index);
390
+
391
+                // DOM2 Event model
392
+                } else if (el.addEventListener) {
393
+                    el.addEventListener(sType, wrappedFn, false);
394
+                // Internet Explorer abstraction
395
+                } else if (el.attachEvent) {
396
+                    el.attachEvent("on" + sType, wrappedFn);
397
+                }
398
+
399
+                return true;
400
+
401
+            },
402
+
403
+            /**
404
+             * Shorthand for YAHOO.util.Event.addListener
405
+             * @type function
406
+             */
407
+            // on: this.addListener,
408
+
409
+            /**
410
+             * When using legacy events, the handler is routed to this object
411
+             * so we can fire our custom listener stack.
412
+             * @private
413
+             */
414
+            fireLegacyEvent: function(e, legacyIndex) {
415
+                // alert("fireLegacyEvent " + legacyIndex);
416
+                var ok = true;
417
+
418
+                // var el = legacyEvents[YAHOO.util.Event.EL];
419
+
420
+                /* this is not working because the property may get populated
421
+                // fire the event we replaced, if it exists
422
+                var origHandler = legacyEvents[2];
423
+                alert(origHandler);
424
+                if (origHandler && origHandler.call) {
425
+                    var ret = origHandler.call(el, e);
426
+                    ok = (ret);
427
+                }
428
+                */
429
+
430
+                var le = legacyHandlers[legacyIndex];
431
+                for (i=0; i < le.length; ++i) {
432
+                    var index = le[i];
433
+                    // alert(index);
434
+                    if (index) {
435
+                        var li = listeners[index];
436
+                        var scope = li[this.ADJ_SCOPE];
437
+                        var ret = li[this.WFN].call(scope, e);
438
+                        ok = (ok && ret);
439
+                        // alert(ok);
440
+                    }
441
+                }
442
+
443
+                return ok;
444
+            },
445
+
446
+            /**
447
+             * Returns the legacy event index that matches the supplied
448
+             * signature
449
+             * @private
450
+             */
451
+            getLegacyIndex: function(el, sType) {
452
+                for (var i=0; i < legacyEvents.length; ++i) {
453
+                    var le = legacyEvents[i];
454
+                    if (le && le[0] == el && le[1] == sType) {
455
+                        return i;
456
+                    }
457
+                }
458
+
459
+                return -1;
460
+            },
461
+
462
+            /**
463
+             * Logic that determines when we should automatically use legacy
464
+             * events instead of DOM2 events.
465
+             * @private
466
+             */
467
+            useLegacyEvent: function(el, sType) {
468
+
469
+                return ( (!el.addEventListener && !el.attachEvent) ||
470
+                                (sType == "click" && this.isSafari) );
471
+            },
472
+
473
+            /**
474
+             * Removes an event handler
475
+             *
476
+             * @param {Object} el the html element or the id of the element to
477
+             * assign the event to.
478
+             * @param {String} sType the type of event to remove
479
+             * @param {Function} fn the method the event invokes
480
+             * @return {boolean} true if the unbind was successful, false
481
+             * otherwise
482
+             */
483
+            removeListener: function(el, sType, fn) {
484
+
485
+                // The el argument can be a string
486
+                if (typeof el == "string") {
487
+                    el = this.getEl(el);
488
+                // The el argument can be an array of elements or element ids.
489
+                } else if ( this._isValidCollection(el)) {
490
+                    var ok = true;
491
+                    for (var i=0; i< el.length; ++i) {
492
+                        ok = ( this.removeListener(el[i], sType, fn) && ok );
493
+                    }
494
+                    return ok;
495
+                }
496
+
497
+                var cacheItem = null;
498
+                var index = this._getCacheIndex(el, sType, fn);
499
+
500
+                if (index >= 0) {
501
+                    cacheItem = listeners[index];
502
+                }
503
+
504
+                if (!el || !cacheItem) {
505
+                    return false;
506
+                }
507
+
508
+
509
+                if (el.removeEventListener) {
510
+                    el.removeEventListener(sType, cacheItem[this.WFN], false);
511
+                    // alert("adsf");
512
+                } else if (el.detachEvent) {
513
+                    el.detachEvent("on" + sType, cacheItem[this.WFN]);
514
+                }
515
+
516
+                // removed the wrapped handler
517
+                delete listeners[index][this.WFN];
518
+                delete listeners[index][this.FN];
519
+                delete listeners[index];
520
+
521
+                return true;
522
+
523
+            },
524
+
525
+            /**
526
+             * Returns the event's target element
527
+             * @param {Event} ev the event
528
+             * @param {boolean} resolveTextNode when set to true the target's
529
+             *                  parent will be returned if the target is a
530
+             *                  text node
531
+             * @return {HTMLElement} the event's target
532
+             */
533
+            getTarget: function(ev, resolveTextNode) {
534
+                var t = ev.target || ev.srcElement;
535
+
536
+                if (resolveTextNode && t && "#text" == t.nodeName) {
537
+                    return t.parentNode;
538
+                } else {
539
+                    return t;
540
+                }
541
+            },
542
+
543
+            /**
544
+             * Returns the event's pageX
545
+             * @param {Event} ev the event
546
+             * @return {int} the event's pageX
547
+             */
548
+            getPageX: function(ev) {
549
+                var x = ev.pageX;
550
+                if (!x && 0 !== x) {
551
+                    x = ev.clientX || 0;
552
+
553
+                    if ( this.isIE ) {
554
+                        x += this._getScrollLeft();
555
+                    }
556
+                }
557
+
558
+                return x;
559
+            },
560
+
561
+            /**
562
+             * Returns the event's pageY
563
+             * @param {Event} ev the event
564
+             * @return {int} the event's pageY
565
+             */
566
+            getPageY: function(ev) {
567
+                var y = ev.pageY;
568
+                if (!y && 0 !== y) {
569
+                    y = ev.clientY || 0;
570
+
571
+                    if ( this.isIE ) {
572
+                        y += this._getScrollTop();
573
+                    }
574
+                }
575
+
576
+                return y;
577
+            },
578
+
579
+            /**
580
+             * Returns the event's related target
581
+             * @param {Event} ev the event
582
+             * @return {HTMLElement} the event's relatedTarget
583
+             */
584
+            getRelatedTarget: function(ev) {
585
+                var t = ev.relatedTarget;
586
+                if (!t) {
587
+                    if (ev.type == "mouseout") {
588
+                        t = ev.toElement;
589
+                    } else if (ev.type == "mouseover") {
590
+                        t = ev.fromElement;
591
+                    }
592
+                }
593
+
594
+                return t;
595
+            },
596
+
597
+            /**
598
+             * Returns the time of the event.  If the time is not included, the
599
+             * event is modified using the current time.
600
+             * @param {Event} ev the event
601
+             * @return {Date} the time of the event
602
+             */
603
+            getTime: function(ev) {
604
+                if (!ev.time) {
605
+                    var t = new Date().getTime();
606
+                    try {
607
+                        ev.time = t;
608
+                    } catch(e) {
609
+                        // can't set the time property
610
+                        return t;
611
+                    }
612
+                }
613
+
614
+                return ev.time;
615
+            },
616
+
617
+            /**
618
+             * Convenience method for stopPropagation + preventDefault
619
+             * @param {Event} ev the event
620
+             */
621
+            stopEvent: function(ev) {
622
+                this.stopPropagation(ev);
623
+                this.preventDefault(ev);
624
+            },
625
+
626
+            /**
627
+             * Stops event propagation
628
+             * @param {Event} ev the event
629
+             */
630
+            stopPropagation: function(ev) {
631
+                if (ev.stopPropagation) {
632
+                    ev.stopPropagation();
633
+                } else {
634
+                    ev.cancelBubble = true;
635
+                }
636
+            },
637
+
638
+            /**
639
+             * Prevents the default behavior of the event
640
+             * @param {Event} ev the event
641
+             */
642
+            preventDefault: function(ev) {
643
+                if (ev.preventDefault) {
644
+                    ev.preventDefault();
645
+                } else {
646
+                    ev.returnValue = false;
647
+                }
648
+            },
649
+
650
+            /**
651
+             * Returns the event, should not be necessary for user to call
652
+             * @param {Event} the event parameter from the handler
653
+             * @return {Event} the event
654
+             */
655
+            getEvent: function(e) {
656
+                var ev = e || window.event;
657
+
658
+                if (!ev) {
659
+                    var c = this.getEvent.caller;
660
+                    while (c) {
661
+                        ev = c.arguments[0];
662
+                        if (ev && Event == ev.constructor) {
663
+                            break;
664
+                        }
665
+                        c = c.caller;
666
+                    }
667
+                }
668
+
669
+                return ev;
670
+            },
671
+
672
+            /**
673
+             * Returns the charcode for an event
674
+             * @param {Event} ev the event
675
+             * @return {int} the event's charCode
676
+             */
677
+            getCharCode: function(ev) {
678
+                return ev.charCode || (ev.type == "keypress") ? ev.keyCode : 0;
679
+            },
680
+
681
+            /**
682
+             * @private
683
+             * Locating the saved event handler data by function ref
684
+             */
685
+            _getCacheIndex: function(el, sType, fn) {
686
+                for (var i=0; i< listeners.length; ++i) {
687
+                    var li = listeners[i];
688
+                    if ( li                 &&
689
+                         li[this.FN] == fn  &&
690
+                         li[this.EL] == el  &&
691
+                         li[this.TYPE] == sType ) {
692
+                        return i;
693
+                    }
694
+                }
695
+
696
+                return -1;
697
+            },
698
+
699
+            /**
700
+             * We want to be able to use getElementsByTagName as a collection
701
+             * to attach a group of events to.  Unfortunately, different
702
+             * browsers return different types of collections.  This function
703
+             * tests to determine if the object is array-like.  It will also
704
+             * fail if the object is an array, but is empty.
705
+             * @param o the object to test
706
+             * @return {boolean} true if the object is array-like and populated
707
+             */
708
+            _isValidCollection: function(o) {
709
+                // alert(o.constructor.toString())
710
+                // alert(typeof o)
711
+
712
+                return ( o                    && // o is something
713
+                         o.length             && // o is indexed
714
+                         typeof o != "string" && // o is not a string
715
+                         !o.tagName           && // o is not an HTML element
716
+                         !o.alert             && // o is not a window
717
+                         typeof o[0] != "undefined" );
718
+
719
+            },
720
+
721
+            /**
722
+             * @private
723
+             * DOM element cache
724
+             */
725
+            elCache: {},
726
+
727
+            /**
728
+             * We cache elements bound by id because when the unload event
729
+             * fires, we can no longer use document.getElementById
730
+             * @private
731
+             */
732
+            getEl: function(id) {
733
+                /*
734
+                // this is a problem when replaced via document.getElementById
735
+                if (! this.elCache[id]) {
736
+                    try {
737
+                        var el = document.getElementById(id);
738
+                        if (el) {
739
+                            this.elCache[id] = el;
740
+                        }
741
+                    } catch (er) {
742
+                    }
743
+                }
744
+                return this.elCache[id];
745
+                */
746
+
747
+                return document.getElementById(id);
748
+            },
749
+
750
+            /**
751
+             * Clears the element cache
752
+             */
753
+            clearCache: function() {
754
+                for (i in this.elCache) {
755
+                    delete this.elCache[i];
756
+                }
757
+            },
758
+
759
+            /**
760
+             * Called by CustomEvent instances to provide a handle to the
761
+             * event * that can be removed later on.  Should be package
762
+             * protected.
763
+             * @private
764
+             */
765
+            regCE: function(ce) {
766
+                customEvents.push(ce);
767
+            },
768
+
769
+            /**
770
+             * @private
771
+             * hook up any deferred listeners
772
+             */
773
+            _load: function(e) {
774
+                loadComplete = true;
775
+            },
776
+
777
+            /**
778
+             * Polling function that runs before the onload event fires,
779
+             * attempting * to attach to DOM Nodes as soon as they are
780
+             * available
781
+             * @private
782
+             */
783
+            _tryPreloadAttach: function() {
784
+
785
+                // keep trying until after the page is loaded.  We need to
786
+                // check the page load state prior to trying to bind the
787
+                // elements so that we can be certain all elements have been
788
+                // tested appropriately
789
+                var tryAgain = !loadComplete;
790
+
791
+                for (var i=0; i < delayedListeners.length; ++i) {
792
+                    var d = delayedListeners[i];
793
+                    // There may be a race condition here, so we need to
794
+                    // verify the array element is usable.
795
+                    if (d) {
796
+
797
+                        // el will be null if document.getElementById did not
798
+                        // work
799
+                        var el = this.getEl(d[this.EL]);
800
+
801
+                        if (el) {
802
+                            this.on(el, d[this.TYPE], d[this.FN],
803
+                                    d[this.SCOPE], d[this.ADJ_SCOPE]);
804
+                            delete delayedListeners[i];
805
+                        }
806
+                    }
807
+                }
808
+
809
+                if (tryAgain) {
810
+                    setTimeout("YAHOO.util.Event._tryPreloadAttach()", 50);
811
+                }
812
+            },
813
+
814
+            /**
815
+             * Removes all listeners registered by pe.event.  Called
816
+             * automatically during the unload event.
817
+             */
818
+            _unload: function(e, me) {
819
+                for (var i=0; i < unloadListeners.length; ++i) {
820
+                    var l = unloadListeners[i];
821
+                    if (l) {
822
+                        var scope = (l[this.ADJ_SCOPE]) ? l[this.SCOPE]: window;
823
+                        l[this.FN].call(scope, this.getEvent(e), l[this.SCOPE] );
824
+                    }
825
+                }
826
+
827
+                if (listeners && listeners.length > 0) {
828
+                    for (i = 0; i < listeners.length; ++i) {
829
+                        l = listeners[i];
830
+                        if (l) {
831
+                            this.removeListener(l[this.EL], l[this.TYPE],
832
+                                    l[this.FN]);
833
+                        }
834
+                    }
835
+
836
+                    this.clearCache();
837
+                }
838
+
839
+                for (i = 0; i < customEvents.length; ++i) {
840
+                    customEvents[i].unsubscribeAll();
841
+                    delete customEvents[i];
842
+                }
843
+
844
+                for (i = 0; i < legacyEvents.length; ++i) {
845
+                    // dereference the element
846
+                    delete legacyEvents[i][0];
847
+                    // delete the array item
848
+                    delete legacyEvents[i];
849
+                }
850
+            },
851
+
852
+            /**
853
+             * Returns scrollLeft
854
+             * @private
855
+             */
856
+            _getScrollLeft: function() {
857
+                return this._getScroll()[1];
858
+            },
859
+
860
+            /**
861
+             * Returns scrollTop
862
+             * @private
863
+             */
864
+            _getScrollTop: function() {
865
+                return this._getScroll()[0];
866
+            },
867
+
868
+            /**
869
+             * Returns the scrollTop and scrollLeft.  Used to calculate the
870
+             * pageX and pageY in Internet Explorer
871
+             * @private
872
+             */
873
+            _getScroll: function() {
874
+                var dd = document.documentElement; db = document.body;
875
+                if (dd && dd.scrollTop) {
876
+                    return [dd.scrollTop, dd.scrollLeft];
877
+                } else if (db) {
878
+                    return [db.scrollTop, db.scrollLeft];
879
+                } else {
880
+                    return [0, 0];
881
+                }
882
+            }
883
+        };
884
+    } ();
885
+
886
+    YAHOO.util.Event.on = YAHOO.util.Event.addListener;
887
+
888
+    if (document && document.body) {
889
+        YAHOO.util.Event._load();
890
+    } else {
891
+        YAHOO.util.Event.on(window, "load", YAHOO.util.Event._load,
892
+                YAHOO.util.Event, true);
893
+    }
894
+
895
+    YAHOO.util.Event.on(window, "unload", YAHOO.util.Event._unload,
896
+                YAHOO.util.Event, true);
897
+
898
+    YAHOO.util.Event._tryPreloadAttach();
899
+
900
+}
901
+