Index: lams_webct_integration/DeployableComponentConfig.xml =================================================================== RCS file: /usr/local/cvsroot/lams_webct_integration/DeployableComponentConfig.xml,v diff -u -r1.2 -r1.3 --- lams_webct_integration/DeployableComponentConfig.xml 19 Nov 2007 22:57:42 -0000 1.2 +++ lams_webct_integration/DeployableComponentConfig.xml 27 Nov 2007 23:13:09 -0000 1.3 @@ -4,7 +4,7 @@ - 0.0.12 + 0.0.13 1.0 lams.integration @@ -191,6 +191,15 @@ optional="false" read-only="false" default-value="@reqSrc@" /> + + Index: lams_webct_integration/build.properties =================================================================== RCS file: /usr/local/cvsroot/lams_webct_integration/build.properties,v diff -u -r1.1 -r1.2 --- lams_webct_integration/build.properties 19 Nov 2007 22:57:42 -0000 1.1 +++ lams_webct_integration/build.properties 27 Nov 2007 23:13:09 -0000 1.2 @@ -32,4 +32,6 @@ # Resuest source name for your WebCt server reqSrc=WebCt +# Url location of image folder containing the images for this integration +imgUrl=/webct/images/ ############################# \ No newline at end of file Index: lams_webct_integration/build.xml =================================================================== RCS file: /usr/local/cvsroot/lams_webct_integration/build.xml,v diff -u -r1.2 -r1.3 --- lams_webct_integration/build.xml 19 Nov 2007 22:57:42 -0000 1.2 +++ lams_webct_integration/build.xml 27 Nov 2007 23:13:09 -0000 1.3 @@ -79,13 +79,26 @@ + - + - + + + + + + + + + + + + + @@ -107,6 +120,8 @@ + + Index: lams_webct_integration/db/sql/createTable.sql =================================================================== RCS file: /usr/local/cvsroot/lams_webct_integration/db/sql/Attic/createTable.sql,v diff -u -r1.1 -r1.2 Binary files differ Index: lams_webct_integration/src/org/lamsfoundation/integration/dao/LamsLessonDaoJDBC.java =================================================================== RCS file: /usr/local/cvsroot/lams_webct_integration/src/org/lamsfoundation/integration/dao/LamsLessonDaoJDBC.java,v diff -u -r1.2 -r1.3 --- lams_webct_integration/src/org/lamsfoundation/integration/dao/LamsLessonDaoJDBC.java 20 Nov 2007 23:52:39 -0000 1.2 +++ lams_webct_integration/src/org/lamsfoundation/integration/dao/LamsLessonDaoJDBC.java 27 Nov 2007 23:13:09 -0000 1.3 @@ -5,6 +5,7 @@ import java.sql.SQLException; import java.sql.Statement; import java.sql.ResultSet; +import java.sql.Timestamp; import java.util.ArrayList; import org.apache.log4j.Logger; @@ -134,8 +135,8 @@ lesson.setOwnerLastName(rs.getString("owner_last_name")); lesson.setHidden(rs.getBoolean("hidden")); lesson.setSchedule(rs.getBoolean("schedule")); - lesson.setStartDate(rs.getDate("start_date_time")); - lesson.setEndDate(rs.getDate("end_date_time")); + lesson.setStartTimestamp(rs.getTimestamp("start_date_time")); + lesson.setEndTimestamp(rs.getTimestamp("end_date_time")); lessons.add(lesson); } @@ -151,6 +152,83 @@ return lessons; } + public ArrayList getDBLessonsForLearner(long learningContextId, + long ptId, + Timestamp now) throws Exception + { + ArrayList lessons = new ArrayList(); + Connection connection; + try + { + connection = getConnection(); + Statement stmt = connection.createStatement(); + + String query = "SELECT [lesson_id]," + + "[learning_context_id]," + + "[sequence_id]," + + "[owner_id]," + + "[owner_first_name]," + + "[owner_last_name]," + + "[title]," + + "[description]," + + "[hidden]," + + "[schedule]," + + "[start_date_time]," + + "[end_date_time] " + + "FROM [webctdatabase].[dbo].[LAMS_LESSON] " + + "WHERE " + + "(" + + "(learning_context_id=" +learningContextId+ ") " + + "AND (pt_id=" +ptId+ ") " + + "AND (hidden='false') " + + "AND (" + + "(schedule='false') " + + "OR (" + + "(start_date_time <= '" +now.toString()+ "') " + + "AND (end_date_time >='" +now.toString()+ "\')" + + ")" + + "OR (" + + "(start_date_time <= '" +now.toString()+ "') " + + "AND (end_date_time IS null)" + + ")" + + ")" + + ")"; + + + System.out.println("SQL INSERT: " +query); + + ResultSet rs = stmt.executeQuery(query); + + while (rs.next()) + { + LamsLesson lesson = new LamsLesson(); + lesson.setLessonId(rs.getLong("lesson_id")); + lesson.setLearningContextId(rs.getLong("learning_context_id")); + lesson.setSequenceId(rs.getLong("sequence_id")); + lesson.setTitle(rs.getString("title")); + lesson.setDescription(rs.getString("description")); + lesson.setOwnerId(rs.getString("owner_id")); + lesson.setOwnerFirstName(rs.getString("owner_first_name")); + lesson.setOwnerLastName(rs.getString("owner_last_name")); + lesson.setHidden(rs.getBoolean("hidden")); + lesson.setSchedule(rs.getBoolean("schedule")); + lesson.setStartTimestamp(rs.getTimestamp("start_date_time")); + lesson.setEndTimestamp(rs.getTimestamp("end_date_time")); + + lessons.add(lesson); + } + + stmt.close(); + connection.close(); + } + catch (SQLException e) + { + log.error("Failed to get a list of LAMS lessons.", e); + throw new Exception ("Failed to get a list of LAMS lessons."); + } + return lessons; + } + public boolean createDbLesson(LamsLesson lesson) throws Exception { Connection connection; @@ -163,6 +241,24 @@ if (lesson.getHidden()) {hidden=1;} if (lesson.getSchedule()) {schedule=1;} + String startTimeStamp = "null"; + if (lesson.getStartTimestamp()!=null) + { + startTimeStamp = "\'" +lesson.getStartTimestamp(); + startTimeStamp = startTimeStamp.replaceAll("-", "") + "\'"; + } + + String endTimeStamp = "null"; + if (lesson.getEndTimestamp()!=null) + { + endTimeStamp = "\'" + lesson.getEndTimestamp(); + endTimeStamp = endTimeStamp.replaceAll("-", "") + "\'"; + } + + System.out.println("START: " +startTimeStamp); + System.out.println("END: " +endTimeStamp); + + try { connection = getConnection(); @@ -195,8 +291,8 @@ "\'" +lesson.getDescription()+ "\'," + "" +hidden+ ","+ "" +schedule+ "," + - "\'" +lesson.getStartDate()+ "\'," + - "\'" +lesson.getEndDate()+ "\')"; + "" +startTimeStamp+ "," + + "" +endTimeStamp+ ")"; System.out.println("SQL INSERT: " +insert); @@ -227,6 +323,15 @@ connection = getConnection(); Statement stmt = connection.createStatement(); + String startTimeStamp = "null"; + if (lesson.getStartTimestamp()!=null) + startTimeStamp = lesson.getStartTimestamp().toString().replaceAll("-", ""); + + String endTimeStamp = "null"; + if (lesson.getEndTimestamp()!=null) + endTimeStamp = lesson.getEndTimestamp().toString().replaceAll("-", ""); + + String update="UPDATE [webctdatabase].[dbo].[LAMS_LESSON]" + " SET [pt_id] = " +lesson.getPtId()+ ",[learning_context_id] = " +lesson.getLearningContextId()+ @@ -238,10 +343,10 @@ ",[description] = \'" +lesson.getDescription()+ "\'" + ",[hidden] = \'" +lesson.getHidden()+ "\'" + ",[schedule] = \'" +lesson.getSchedule()+ "\'" + - ",[start_date_time] = \'" +lesson.getStartDate()+ "\'" + - ",[end_date_time] = \'" +lesson.getEndDate()+ "\' " + + ",[start_date_time] = \'" +startTimeStamp+ "\'" + + ",[end_date_time] = \'" +endTimeStamp+ "\' " + "WHERE [lesson_id] = " + lesson.getLessonId(); - + System.out.println("UPDATE: " + update); rows = stmt.executeUpdate(update); @@ -335,8 +440,8 @@ lesson.setOwnerLastName(rs.getString("owner_last_name")); lesson.setHidden(rs.getBoolean("hidden")); lesson.setSchedule(rs.getBoolean("schedule")); - lesson.setStartDate(rs.getDate("start_date_time")); - lesson.setEndDate(rs.getDate("end_date_time")); + lesson.setStartTimestamp(rs.getTimestamp("start_date_time")); + lesson.setEndTimestamp(rs.getTimestamp("end_date_time")); stmt.close(); connection.close(); Index: lams_webct_integration/src/org/lamsfoundation/integration/util/Constants.java =================================================================== RCS file: /usr/local/cvsroot/lams_webct_integration/src/org/lamsfoundation/integration/util/Constants.java,v diff -u -r1.2 -r1.3 --- lams_webct_integration/src/org/lamsfoundation/integration/util/Constants.java 19 Nov 2007 22:57:42 -0000 1.2 +++ lams_webct_integration/src/org/lamsfoundation/integration/util/Constants.java 27 Nov 2007 23:13:10 -0000 1.3 @@ -29,6 +29,9 @@ */ public class Constants { + public static final String DEFAULT_LANGUAGE="en"; + public static final String DEFAULT_COUNTRY="US"; + public static final String PARAM_USER_ID = "uid"; public static final String PARAM_SERVER_ID = "sid"; public static final String PARAM_TIMESTAMP = "ts"; Index: lams_webct_integration/src/org/lamsfoundation/integration/webct/LamsLesson.java =================================================================== RCS file: /usr/local/cvsroot/lams_webct_integration/src/org/lamsfoundation/integration/webct/LamsLesson.java,v diff -u -r1.1 -r1.2 --- lams_webct_integration/src/org/lamsfoundation/integration/webct/LamsLesson.java 19 Nov 2007 22:57:42 -0000 1.1 +++ lams_webct_integration/src/org/lamsfoundation/integration/webct/LamsLesson.java 27 Nov 2007 23:13:09 -0000 1.2 @@ -1,7 +1,7 @@ package org.lamsfoundation.integration.webct; -import java.sql.Date; +import java.sql.Timestamp; /** @@ -23,8 +23,8 @@ private String ownerLastName; // webct user second name private boolean hidden; // only visible to owner if true private boolean schedule; - private Date startDate; - private Date endDate; + private Timestamp startTimestamp; + private Timestamp endTimestamp; @@ -57,8 +57,8 @@ String ownerLastName, boolean hidden, boolean schedule, - Date startDate, - Date endDate) + Timestamp startTimestamp, + Timestamp endTimestamp) { this.lessonId = lessonId; this.ptId = ptId; @@ -71,8 +71,8 @@ this.ownerLastName = ownerLastName; this.hidden = hidden; this.schedule = schedule; - this.startDate = startDate; - this.endDate = endDate; + this.startTimestamp = startTimestamp; + this.endTimestamp = endTimestamp; } @@ -125,17 +125,17 @@ public void setSchedule(boolean schedule) { this.schedule = schedule; } - public Date getStartDate() { - return startDate; + public Timestamp getStartTimestamp() { + return startTimestamp; } - public void setStartDate(Date startDate) { - this.startDate = startDate; + public void setStartTimestamp(Timestamp startTimestamp) { + this.startTimestamp = startTimestamp; } - public Date getEndDate() { - return endDate; + public Timestamp getEndTimestamp() { + return endTimestamp; } - public void setEndDate(Date endDate) { - this.endDate = endDate; + public void setEndTimestamp(Timestamp endTimestamp) { + this.endTimestamp = endTimestamp; } public long getLearningContextId() { @@ -179,8 +179,8 @@ + "ownerLastName = " + this.ownerLastName + TAB + "hidden = " + this.hidden + TAB + "schedule = " + this.schedule + TAB - + "startDate = " + this.startDate + TAB - + "endDate = " + this.endDate + TAB + + "startTimestamp = " + this.startTimestamp + TAB + + "endTimestamp = " + this.endTimestamp + TAB + " )"; return retValue; Index: lams_webct_integration/src/org/lamsfoundation/integration/webct/LamsModule.java =================================================================== RCS file: /usr/local/cvsroot/lams_webct_integration/src/org/lamsfoundation/integration/webct/LamsModule.java,v diff -u -r1.3 -r1.4 --- lams_webct_integration/src/org/lamsfoundation/integration/webct/LamsModule.java 20 Nov 2007 23:52:40 -0000 1.3 +++ lams_webct_integration/src/org/lamsfoundation/integration/webct/LamsModule.java 27 Nov 2007 23:13:09 -0000 1.4 @@ -8,38 +8,24 @@ import java.util.Iterator; import java.util.Map; import java.util.List; -import java.util.ArrayList; import java.util.Properties; import javax.security.auth.Subject; import javax.security.auth.callback.CallbackHandler; +import java.sql.Date; +import java.sql.Timestamp; import javax.security.auth.login.LoginException; import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import com.webct.platform.sdk.context.gen.*; -import com.webct.platform.sdk.context.client.*; + + import com.webct.platform.sdk.security.authentication.module.AuthenticationModule; -import com.webct.platform.sdk.proxytool.common.ProcessCallback; -import com.webct.platform.sdk.security.authentication.module.WebCTSSOContext; -import com.webct.platform.sdk.context.client.ContextSDK; -import com.webct.platform.sdk.context.gen.SessionVO; -import com.webct.platform.sdk.context.gen.LearningCtxtVO; import com.webct.platform.sdkext.authmoduledata.*; -import com.webct.platform.sdk.context.gen.SessionVO; -//-------- Velocity imports -------------- -import java.io.StringWriter; -import java.rmi.RemoteException; -import java.sql.Date; import org.apache.velocity.VelocityContext; import org.apache.velocity.Template; import org.apache.velocity.app.VelocityEngine; -import org.apache.velocity.exception.*; -//import org.apache.axis.AxisFault; - -import java.net.URL; import org.apache.log4j.Logger; import org.lamsfoundation.integration.webct.LamsSecurityUtil; @@ -229,7 +215,10 @@ // test //List lessons = lessonDao.getDBLessons(1); - List lessons = lessonDao.getDBLessons(lcID.longValue(), Long.parseLong(ptid)); + java.util.Date today = new java.util.Date(); + Timestamp now = new Timestamp(today.getTime()); + + List lessons = lessonDao.getDBLessonsForLearner(lcID.longValue(), Long.parseLong(ptid), now); params.put("lessons", lessons); @@ -306,8 +295,8 @@ webctRequestSource, user.getUserId(), "" + seqID, - "en", - "US", + Constants.DEFAULT_LANGUAGE, + Constants.DEFAULT_COUNTRY, user.getFirstname(), user.getLastname(), user.getEmail(), @@ -323,7 +312,30 @@ } else { - LamsLessonDaoJDBC lessonDao = new LamsLessonDaoJDBC(settings); + Timestamp start = null; + Timestamp end = null; + + if (request.getParameter("schedule").equals("true")) + { + if (request.getParameter("dateStart")!=null && !request.getParameter("dateStart").equals("")) + { + start = getTimeStamp(request.getParameter("dateStart"), + request.getParameter("startHour"), + request.getParameter("startMin"), + request.getParameter("startAMPM")); + } + + if (request.getParameter("dateEnd")!=null && !request.getParameter("dateEnd").equals("")) + { + + end = getTimeStamp(request.getParameter("dateEnd"), + request.getParameter("endHour"), + request.getParameter("endMin"), + request.getParameter("endAMPM")); + } + } + + LamsLessonDaoJDBC lessonDao = new LamsLessonDaoJDBC(settings); LamsLesson lesson = new LamsLesson( lsID, Long.parseLong(ptid), @@ -334,10 +346,10 @@ user.getUserId(), user.getFirstname(), user.getLastname(), - false, - false, - new Date(0), - new Date(0) + request.getParameter("isAvailable").equals("false"), + request.getParameter("schedule").equals("true"), + start, + end ); try{ @@ -388,8 +400,8 @@ webctRequestSource, user.getUserId(), "" + lcID, - "en", - "US", + Constants.DEFAULT_LANGUAGE, + Constants.DEFAULT_COUNTRY, user.getFirstname(), user.getLastname(), user.getEmail(), @@ -419,8 +431,8 @@ params.put("lsID", request.getParameter("lsID")); params.put("title", modLesson.getTitle()); params.put("description", modLesson.getDescription()); - params.put("start", modLesson.getStartDate()); - params.put("end", modLesson.getEndDate()); + params.put("start", modLesson.getStartTimestamp()); + params.put("end", modLesson.getEndTimestamp()); if (modLesson.getHidden()) @@ -470,10 +482,6 @@ modLesson.setSchedule(request.getParameter("schedule").equals("true")); - //TODO: DO SOMETHING ABOUT DATES - //Date start = new Date(0); - //Date end = new Date(0); - boolean success = lessonDao.updateLesson(modLesson); @@ -551,8 +559,8 @@ webctRequestSource, user.getUserId(), "" + lcID, - "en", - "AU", + Constants.DEFAULT_LANGUAGE, + Constants.DEFAULT_COUNTRY, user.getFirstname(), user.getLastname(), user.getEmail(), @@ -583,8 +591,8 @@ lamsServerSecretKey, user.getUserId(), "" + lcID, - "en", - "AU", + Constants.DEFAULT_LANGUAGE, + Constants.DEFAULT_COUNTRY, user.getFirstname(), user.getLastname(), user.getEmail(), @@ -604,7 +612,29 @@ } } - + public Timestamp getTimeStamp(String date, String hours, String minutes, String ampm) + { + + String dateSplit[] = date.split("/"); + + date = dateSplit[2] + "-" + dateSplit[1] + "-" + dateSplit[0]; + + if (ampm.equals("PM")) + { + int hoursInt = Integer.parseInt(hours); + hoursInt += 12; + hours = "" + hoursInt; + } + + String timestampStr = date + " " + hours + ":" + minutes + ":" + "00"; + System.out.println("TIMESTAMP: " + timestampStr); + + + Timestamp t = Timestamp.valueOf(timestampStr); + System.out.println("TIMESTAMP To String: " + t.toString()); + return t; + + } public boolean logout() throws LoginException { return super.logout(); Index: lams_webct_integration/web/create.vm =================================================================== RCS file: /usr/local/cvsroot/lams_webct_integration/web/create.vm,v diff -u -r1.5 -r1.6 Binary files differ Index: lams_webct_integration/web/modify.vm =================================================================== RCS file: /usr/local/cvsroot/lams_webct_integration/web/modify.vm,v diff -u -r1.2 -r1.3 Binary files differ Index: lams_webct_integration/web/teach.vm =================================================================== RCS file: /usr/local/cvsroot/lams_webct_integration/web/teach.vm,v diff -u -r1.4 -r1.5 Binary files differ Fisheye: Tag 1.2 refers to a dead (removed) revision in file `lams_webct_integration/web/css/styles.css'. Fisheye: No comparison available. Pass `N' to diff? Index: lams_webct_integration/web/lib/jquery/jquery-1.2.1.js =================================================================== RCS file: /usr/local/cvsroot/lams_webct_integration/web/lib/jquery/jquery-1.2.1.js,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ lams_webct_integration/web/lib/jquery/jquery-1.2.1.js 27 Nov 2007 23:13:09 -0000 1.1 @@ -0,0 +1,2992 @@ +(function(){ +/* + * jQuery 1.2.1 - New Wave Javascript + * + * Copyright (c) 2007 John Resig (jquery.com) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * $Date: 2007/11/27 23:13:09 $ + * $Rev: 3353 $ + */ + +// Map over jQuery in case of overwrite +if ( typeof jQuery != "undefined" ) + var _jQuery = jQuery; + +var jQuery = window.jQuery = function(selector, context) { + // If the context is a namespace object, return a new object + return this instanceof jQuery ? + this.init(selector, context) : + new jQuery(selector, context); +}; + +// Map over the $ in case of overwrite +if ( typeof $ != "undefined" ) + var _$ = $; + +// Map the jQuery namespace to the '$' one +window.$ = jQuery; + +var quickExpr = /^[^<]*(<(.|\s)+>)[^>]*$|^#(\w+)$/; + +jQuery.fn = jQuery.prototype = { + init: function(selector, context) { + // Make sure that a selection was provided + selector = selector || document; + + // Handle HTML strings + if ( typeof selector == "string" ) { + var m = quickExpr.exec(selector); + if ( m && (m[1] || !context) ) { + // HANDLE: $(html) -> $(array) + if ( m[1] ) + selector = jQuery.clean( [ m[1] ], context ); + + // HANDLE: $("#id") + else { + var tmp = document.getElementById( m[3] ); + if ( tmp ) + // Handle the case where IE and Opera return items + // by name instead of ID + if ( tmp.id != m[3] ) + return jQuery().find( selector ); + else { + this[0] = tmp; + this.length = 1; + return this; + } + else + selector = []; + } + + // HANDLE: $(expr) + } else + return new jQuery( context ).find( selector ); + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( jQuery.isFunction(selector) ) + return new jQuery(document)[ jQuery.fn.ready ? "ready" : "load" ]( selector ); + + return this.setArray( + // HANDLE: $(array) + selector.constructor == Array && selector || + + // HANDLE: $(arraylike) + // Watch for when an array-like object is passed as the selector + (selector.jquery || selector.length && selector != window && !selector.nodeType && selector[0] != undefined && selector[0].nodeType) && jQuery.makeArray( selector ) || + + // HANDLE: $(*) + [ selector ] ); + }, + + jquery: "1.2.1", + + size: function() { + return this.length; + }, + + length: 0, + + get: function( num ) { + return num == undefined ? + + // Return a 'clean' array + jQuery.makeArray( this ) : + + // Return just the object + this[num]; + }, + + pushStack: function( a ) { + var ret = jQuery(a); + ret.prevObject = this; + return ret; + }, + + setArray: function( a ) { + this.length = 0; + Array.prototype.push.apply( this, a ); + return this; + }, + + each: function( fn, args ) { + return jQuery.each( this, fn, args ); + }, + + index: function( obj ) { + var pos = -1; + this.each(function(i){ + if ( this == obj ) pos = i; + }); + return pos; + }, + + attr: function( key, value, type ) { + var obj = key; + + // Look for the case where we're accessing a style value + if ( key.constructor == String ) + if ( value == undefined ) + return this.length && jQuery[ type || "attr" ]( this[0], key ) || undefined; + else { + obj = {}; + obj[ key ] = value; + } + + // Check to see if we're setting style values + return this.each(function(index){ + // Set all the styles + for ( var prop in obj ) + jQuery.attr( + type ? this.style : this, + prop, jQuery.prop(this, obj[prop], type, index, prop) + ); + }); + }, + + css: function( key, value ) { + return this.attr( key, value, "curCSS" ); + }, + + text: function(e) { + if ( typeof e != "object" && e != null ) + return this.empty().append( document.createTextNode( e ) ); + + var t = ""; + jQuery.each( e || this, function(){ + jQuery.each( this.childNodes, function(){ + if ( this.nodeType != 8 ) + t += this.nodeType != 1 ? + this.nodeValue : jQuery.fn.text([ this ]); + }); + }); + return t; + }, + + wrapAll: function(html) { + if ( this[0] ) + // The elements to wrap the target around + jQuery(html, this[0].ownerDocument) + .clone() + .insertBefore(this[0]) + .map(function(){ + var elem = this; + while ( elem.firstChild ) + elem = elem.firstChild; + return elem; + }) + .append(this); + + return this; + }, + + wrapInner: function(html) { + return this.each(function(){ + jQuery(this).contents().wrapAll(html); + }); + }, + + wrap: function(html) { + return this.each(function(){ + jQuery(this).wrapAll(html); + }); + }, + + append: function() { + return this.domManip(arguments, true, 1, function(a){ + this.appendChild( a ); + }); + }, + + prepend: function() { + return this.domManip(arguments, true, -1, function(a){ + this.insertBefore( a, this.firstChild ); + }); + }, + + before: function() { + return this.domManip(arguments, false, 1, function(a){ + this.parentNode.insertBefore( a, this ); + }); + }, + + after: function() { + return this.domManip(arguments, false, -1, function(a){ + this.parentNode.insertBefore( a, this.nextSibling ); + }); + }, + + end: function() { + return this.prevObject || jQuery([]); + }, + + find: function(t) { + var data = jQuery.map(this, function(a){ return jQuery.find(t,a); }); + return this.pushStack( /[^+>] [^+>]/.test( t ) || t.indexOf("..") > -1 ? + jQuery.unique( data ) : data ); + }, + + clone: function(events) { + // Do the clone + var ret = this.map(function(){ + return this.outerHTML ? jQuery(this.outerHTML)[0] : this.cloneNode(true); + }); + + // Need to set the expando to null on the cloned set if it exists + // removeData doesn't work here, IE removes it from the original as well + // this is primarily for IE but the data expando shouldn't be copied over in any browser + var clone = ret.find("*").andSelf().each(function(){ + if ( this[ expando ] != undefined ) + this[ expando ] = null; + }); + + // Copy the events from the original to the clone + if (events === true) + this.find("*").andSelf().each(function(i) { + var events = jQuery.data(this, "events"); + for ( var type in events ) + for ( var handler in events[type] ) + jQuery.event.add(clone[i], type, events[type][handler], events[type][handler].data); + }); + + // Return the cloned set + return ret; + }, + + filter: function(t) { + return this.pushStack( + jQuery.isFunction( t ) && + jQuery.grep(this, function(el, index){ + return t.apply(el, [index]); + }) || + + jQuery.multiFilter(t,this) ); + }, + + not: function(t) { + return this.pushStack( + t.constructor == String && + jQuery.multiFilter(t, this, true) || + + jQuery.grep(this, function(a) { + return ( t.constructor == Array || t.jquery ) + ? jQuery.inArray( a, t ) < 0 + : a != t; + }) + ); + }, + + add: function(t) { + return this.pushStack( jQuery.merge( + this.get(), + t.constructor == String ? + jQuery(t).get() : + t.length != undefined && (!t.nodeName || jQuery.nodeName(t, "form")) ? + t : [t] ) + ); + }, + + is: function(expr) { + return expr ? jQuery.multiFilter(expr,this).length > 0 : false; + }, + + hasClass: function(expr) { + return this.is("." + expr); + }, + + val: function( val ) { + if ( val == undefined ) { + if ( this.length ) { + var elem = this[0]; + + // We need to handle select boxes special + if ( jQuery.nodeName(elem, "select") ) { + var index = elem.selectedIndex, + a = [], + options = elem.options, + one = elem.type == "select-one"; + + // Nothing was selected + if ( index < 0 ) + return null; + + // Loop through all the selected options + for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) { + var option = options[i]; + if ( option.selected ) { + // Get the specifc value for the option + var val = jQuery.browser.msie && !option.attributes["value"].specified ? option.text : option.value; + + // We don't need an array for one selects + if ( one ) + return val; + + // Multi-Selects return an array + a.push(val); + } + } + + return a; + + // Everything else, we just grab the value + } else + return this[0].value.replace(/\r/g, ""); + } + } else + return this.each(function(){ + if ( val.constructor == Array && /radio|checkbox/.test(this.type) ) + this.checked = (jQuery.inArray(this.value, val) >= 0 || + jQuery.inArray(this.name, val) >= 0); + else if ( jQuery.nodeName(this, "select") ) { + var tmp = val.constructor == Array ? val : [val]; + + jQuery("option", this).each(function(){ + this.selected = (jQuery.inArray(this.value, tmp) >= 0 || + jQuery.inArray(this.text, tmp) >= 0); + }); + + if ( !tmp.length ) + this.selectedIndex = -1; + } else + this.value = val; + }); + }, + + html: function( val ) { + return val == undefined ? + ( this.length ? this[0].innerHTML : null ) : + this.empty().append( val ); + }, + + replaceWith: function( val ) { + return this.after( val ).remove(); + }, + + eq: function(i){ + return this.slice(i, i+1); + }, + + slice: function() { + return this.pushStack( Array.prototype.slice.apply( this, arguments ) ); + }, + + map: function(fn) { + return this.pushStack(jQuery.map( this, function(elem,i){ + return fn.call( elem, i, elem ); + })); + }, + + andSelf: function() { + return this.add( this.prevObject ); + }, + + domManip: function(args, table, dir, fn) { + var clone = this.length > 1, a; + + return this.each(function(){ + if ( !a ) { + a = jQuery.clean(args, this.ownerDocument); + if ( dir < 0 ) + a.reverse(); + } + + var obj = this; + + if ( table && jQuery.nodeName(this, "table") && jQuery.nodeName(a[0], "tr") ) + obj = this.getElementsByTagName("tbody")[0] || this.appendChild(document.createElement("tbody")); + + jQuery.each( a, function(){ + var elem = clone ? this.cloneNode(true) : this; + if ( !evalScript(0, elem) ) + fn.call( obj, elem ); + }); + }); + } +}; + +function evalScript(i, elem){ + var script = jQuery.nodeName(elem, "script"); + + if ( script ) { + if ( elem.src ) + jQuery.ajax({ url: elem.src, async: false, dataType: "script" }); + else + jQuery.globalEval( elem.text || elem.textContent || elem.innerHTML || "" ); + + if ( elem.parentNode ) + elem.parentNode.removeChild(elem); + + } else if ( elem.nodeType == 1 ) + jQuery("script", elem).each(evalScript); + + return script; +} + +jQuery.extend = jQuery.fn.extend = function() { + // copy reference to target object + var target = arguments[0] || {}, a = 1, al = arguments.length, deep = false; + + // Handle a deep copy situation + if ( target.constructor == Boolean ) { + deep = target; + target = arguments[1] || {}; + } + + // extend jQuery itself if only one argument is passed + if ( al == 1 ) { + target = this; + a = 0; + } + + var prop; + + for ( ; a < al; a++ ) + // Only deal with non-null/undefined values + if ( (prop = arguments[a]) != null ) + // Extend the base object + for ( var i in prop ) { + // Prevent never-ending loop + if ( target == prop[i] ) + continue; + + // Recurse if we're merging object values + if ( deep && typeof prop[i] == 'object' && target[i] ) + jQuery.extend( target[i], prop[i] ); + + // Don't bring in undefined values + else if ( prop[i] != undefined ) + target[i] = prop[i]; + } + + // Return the modified object + return target; +}; + +var expando = "jQuery" + (new Date()).getTime(), uuid = 0, win = {}; + +jQuery.extend({ + noConflict: function(deep) { + window.$ = _$; + if ( deep ) + window.jQuery = _jQuery; + return jQuery; + }, + + // This may seem like some crazy code, but trust me when I say that this + // is the only cross-browser way to do this. --John + isFunction: function( fn ) { + return !!fn && typeof fn != "string" && !fn.nodeName && + fn.constructor != Array && /function/i.test( fn + "" ); + }, + + // check if an element is in a XML document + isXMLDoc: function(elem) { + return elem.documentElement && !elem.body || + elem.tagName && elem.ownerDocument && !elem.ownerDocument.body; + }, + + // Evalulates a script in a global context + // Evaluates Async. in Safari 2 :-( + globalEval: function( data ) { + data = jQuery.trim( data ); + if ( data ) { + if ( window.execScript ) + window.execScript( data ); + else if ( jQuery.browser.safari ) + // safari doesn't provide a synchronous global eval + window.setTimeout( data, 0 ); + else + eval.call( window, data ); + } + }, + + nodeName: function( elem, name ) { + return elem.nodeName && elem.nodeName.toUpperCase() == name.toUpperCase(); + }, + + cache: {}, + + data: function( elem, name, data ) { + elem = elem == window ? win : elem; + + var id = elem[ expando ]; + + // Compute a unique ID for the element + if ( !id ) + id = elem[ expando ] = ++uuid; + + // Only generate the data cache if we're + // trying to access or manipulate it + if ( name && !jQuery.cache[ id ] ) + jQuery.cache[ id ] = {}; + + // Prevent overriding the named cache with undefined values + if ( data != undefined ) + jQuery.cache[ id ][ name ] = data; + + // Return the named cache data, or the ID for the element + return name ? jQuery.cache[ id ][ name ] : id; + }, + + removeData: function( elem, name ) { + elem = elem == window ? win : elem; + + var id = elem[ expando ]; + + // If we want to remove a specific section of the element's data + if ( name ) { + if ( jQuery.cache[ id ] ) { + // Remove the section of cache data + delete jQuery.cache[ id ][ name ]; + + // If we've removed all the data, remove the element's cache + name = ""; + for ( name in jQuery.cache[ id ] ) break; + if ( !name ) + jQuery.removeData( elem ); + } + + // Otherwise, we want to remove all of the element's data + } else { + // Clean up the element expando + try { + delete elem[ expando ]; + } catch(e){ + // IE has trouble directly removing the expando + // but it's ok with using removeAttribute + if ( elem.removeAttribute ) + elem.removeAttribute( expando ); + } + + // Completely remove the data cache + delete jQuery.cache[ id ]; + } + }, + + // args is for internal usage only + each: function( obj, fn, args ) { + if ( args ) { + if ( obj.length == undefined ) + for ( var i in obj ) + fn.apply( obj[i], args ); + else + for ( var i = 0, ol = obj.length; i < ol; i++ ) + if ( fn.apply( obj[i], args ) === false ) break; + + // A special, fast, case for the most common use of each + } else { + if ( obj.length == undefined ) + for ( var i in obj ) + fn.call( obj[i], i, obj[i] ); + else + for ( var i = 0, ol = obj.length, val = obj[0]; + i < ol && fn.call(val,i,val) !== false; val = obj[++i] ){} + } + + return obj; + }, + + prop: function(elem, value, type, index, prop){ + // Handle executable functions + if ( jQuery.isFunction( value ) ) + value = value.call( elem, [index] ); + + // exclude the following css properties to add px + var exclude = /z-?index|font-?weight|opacity|zoom|line-?height/i; + + // Handle passing in a number to a CSS property + return value && value.constructor == Number && type == "curCSS" && !exclude.test(prop) ? + value + "px" : + value; + }, + + className: { + // internal only, use addClass("class") + add: function( elem, c ){ + jQuery.each( (c || "").split(/\s+/), function(i, cur){ + if ( !jQuery.className.has( elem.className, cur ) ) + elem.className += ( elem.className ? " " : "" ) + cur; + }); + }, + + // internal only, use removeClass("class") + remove: function( elem, c ){ + elem.className = c != undefined ? + jQuery.grep( elem.className.split(/\s+/), function(cur){ + return !jQuery.className.has( c, cur ); + }).join(" ") : ""; + }, + + // internal only, use is(".class") + has: function( t, c ) { + return jQuery.inArray( c, (t.className || t).toString().split(/\s+/) ) > -1; + } + }, + + swap: function(e,o,f) { + for ( var i in o ) { + e.style["old"+i] = e.style[i]; + e.style[i] = o[i]; + } + f.apply( e, [] ); + for ( var i in o ) + e.style[i] = e.style["old"+i]; + }, + + css: function(e,p) { + if ( p == "height" || p == "width" ) { + var old = {}, oHeight, oWidth, d = ["Top","Bottom","Right","Left"]; + + jQuery.each( d, function(){ + old["padding" + this] = 0; + old["border" + this + "Width"] = 0; + }); + + jQuery.swap( e, old, function() { + if ( jQuery(e).is(':visible') ) { + oHeight = e.offsetHeight; + oWidth = e.offsetWidth; + } else { + e = jQuery(e.cloneNode(true)) + .find(":radio").removeAttr("checked").end() + .css({ + visibility: "hidden", position: "absolute", display: "block", right: "0", left: "0" + }).appendTo(e.parentNode)[0]; + + var parPos = jQuery.css(e.parentNode,"position") || "static"; + if ( parPos == "static" ) + e.parentNode.style.position = "relative"; + + oHeight = e.clientHeight; + oWidth = e.clientWidth; + + if ( parPos == "static" ) + e.parentNode.style.position = "static"; + + e.parentNode.removeChild(e); + } + }); + + return p == "height" ? oHeight : oWidth; + } + + return jQuery.curCSS( e, p ); + }, + + curCSS: function(elem, prop, force) { + var ret, stack = [], swap = []; + + // A helper method for determining if an element's values are broken + function color(a){ + if ( !jQuery.browser.safari ) + return false; + + var ret = document.defaultView.getComputedStyle(a,null); + return !ret || ret.getPropertyValue("color") == ""; + } + + if (prop == "opacity" && jQuery.browser.msie) { + ret = jQuery.attr(elem.style, "opacity"); + return ret == "" ? "1" : ret; + } + + if (prop.match(/float/i)) + prop = styleFloat; + + if (!force && elem.style[prop]) + ret = elem.style[prop]; + + else if (document.defaultView && document.defaultView.getComputedStyle) { + + if (prop.match(/float/i)) + prop = "float"; + + prop = prop.replace(/([A-Z])/g,"-$1").toLowerCase(); + var cur = document.defaultView.getComputedStyle(elem, null); + + if ( cur && !color(elem) ) + ret = cur.getPropertyValue(prop); + + // If the element isn't reporting its values properly in Safari + // then some display: none elements are involved + else { + // Locate all of the parent display: none elements + for ( var a = elem; a && color(a); a = a.parentNode ) + stack.unshift(a); + + // Go through and make them visible, but in reverse + // (It would be better if we knew the exact display type that they had) + for ( a = 0; a < stack.length; a++ ) + if ( color(stack[a]) ) { + swap[a] = stack[a].style.display; + stack[a].style.display = "block"; + } + + // Since we flip the display style, we have to handle that + // one special, otherwise get the value + ret = prop == "display" && swap[stack.length-1] != null ? + "none" : + document.defaultView.getComputedStyle(elem,null).getPropertyValue(prop) || ""; + + // Finally, revert the display styles back + for ( a = 0; a < swap.length; a++ ) + if ( swap[a] != null ) + stack[a].style.display = swap[a]; + } + + if ( prop == "opacity" && ret == "" ) + ret = "1"; + + } else if (elem.currentStyle) { + var newProp = prop.replace(/\-(\w)/g,function(m,c){return c.toUpperCase();}); + ret = elem.currentStyle[prop] || elem.currentStyle[newProp]; + + // From the awesome hack by Dean Edwards + // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291 + + // If we're not dealing with a regular pixel number + // but a number that has a weird ending, we need to convert it to pixels + if ( !/^\d+(px)?$/i.test(ret) && /^\d/.test(ret) ) { + var style = elem.style.left; + var runtimeStyle = elem.runtimeStyle.left; + elem.runtimeStyle.left = elem.currentStyle.left; + elem.style.left = ret || 0; + ret = elem.style.pixelLeft + "px"; + elem.style.left = style; + elem.runtimeStyle.left = runtimeStyle; + } + } + + return ret; + }, + + clean: function(a, doc) { + var r = []; + doc = doc || document; + + jQuery.each( a, function(i,arg){ + if ( !arg ) return; + + if ( arg.constructor == Number ) + arg = arg.toString(); + + // Convert html string into DOM nodes + if ( typeof arg == "string" ) { + // Fix "XHTML"-style tags in all browsers + arg = arg.replace(/(<(\w+)[^>]*?)\/>/g, function(m, all, tag){ + return tag.match(/^(abbr|br|col|img|input|link|meta|param|hr|area)$/i)? m : all+">"; + }); + + // Trim whitespace, otherwise indexOf won't work as expected + var s = jQuery.trim(arg).toLowerCase(), div = doc.createElement("div"), tb = []; + + var wrap = + // option or optgroup + !s.indexOf("", ""] || + + !s.indexOf("", ""] || + + s.match(/^<(thead|tbody|tfoot|colg|cap)/) && + [1, "", "
"] || + + !s.indexOf("", ""] || + + // matched above + (!s.indexOf("", ""] || + + !s.indexOf("", ""] || + + // IE can't serialize and