Property changes on: . ___________________________________________________________________ Modified: svn:mergeinfo Merged /evaluation/branches/unicon-ucb:r78148-81089 Index: pom.xml =================================================================== --- pom.xml (revision 81089) +++ pom.xml (working copy) @@ -328,7 +328,8 @@ **/js/jquery/** **/js/ui.* **/js/yahoo* - **/css/jquery* + **/css/jquery/** + **/css/scss/** LICENSE* **/README Index: impl/src/test/org/sakaiproject/evaluation/test/EvalTestDataLoad.java =================================================================== --- impl/src/test/org/sakaiproject/evaluation/test/EvalTestDataLoad.java (revision 81089) +++ impl/src/test/org/sakaiproject/evaluation/test/EvalTestDataLoad.java (working copy) @@ -91,7 +91,9 @@ public final static String SITE2_CONTEXT = "siteC2"; public final static String SITE2_REF = "/sites/ref-222222"; public final static String SITE2_TITLE = "Site2 title"; - public final static String SITE3_REF = "/sites/ref-333333"; + public final static String SITE3_CONTEXT = "siteC3"; + public final static String SITE3_REF = "/sites/ref-222222"; + public final static String SITE3_TITLE = "Site3 title"; public final static String SITE4_REF = "/sites/ref-444444"; public final static String SITE5_REF = "/sites/ref-555555"; public final static String SITE6_REF = "/sites/ref-666666"; @@ -365,22 +367,22 @@ * Evaluation which is in its grace period */ public EvalEvaluation evaluationGracePeriod; - + /** * Evaluation which is active for testing view_ignore_date */ public EvalEvaluation evaluationActive_viewIgnoreDates; - + /** * Evaluation which is due for testing view_ignore_date */ public EvalEvaluation evaluationDue_viewIgnoreDates; - + /** * Evaluation which is closed for testing evaluationClosed_viewIgnoreDates */ public EvalEvaluation evaluationClosed_viewIgnoreDates; - + /** * Evaluation which has allRolesCanParticipate set to true * Site 3 group has 1 maintain and 1 access user @@ -513,7 +515,7 @@ * Group Assignment: MAIN_USER_ID_2, SITE6_REF, {@link #evaluation_allRoleAssignments_notAllRolesParticipate} */ public EvalAssignGroup assign17; - + /** * Group Assignment: MAIN_USER2, EVALSYS_1007_SITE_REF_01. {@link #evaluationActive_viewIgnoreDates} */ @@ -526,7 +528,7 @@ * Group Assignment: MAIN_USER2, EVALSYS_1007_SITE_REF_01. {@link #evaluationClosed_viewIgnoreDates} */ public EvalAssignGroup evalsys_1007_assign01; - + /** * Group Assignment: ADMIN_USER_ID, SITE2_REF, {@link #evaluationNewAdmin} + eid */ @@ -860,7 +862,7 @@ EvalConstants.SHARING_PRIVATE, NOT_EXPERT, "expert desc", null, LOCKED, false); templateUser_4 = new EvalTemplate(MAINT_USER_ID_3, EvalConstants.TEMPLATE_TYPE_STANDARD, - "Template user 4", "description", + "Template user 4", "description", EvalConstants.SHARING_PRIVATE, NOT_EXPERT, "expert desc", null, LOCKED, false); @@ -1216,7 +1218,7 @@ EvalConstants.EVALUATION_STATE_DELETED, EvalConstants.SHARING_PUBLIC, EvalConstants.INSTRUCTOR_REQUIRED, new Integer(0), null, null, null, null, templateUser, null, Boolean.TRUE, Boolean.FALSE, Boolean.FALSE, UNLOCKED, EvalConstants.EVALUATION_AUTHCONTROL_NONE, null, null); - + /* * Evaluation which has allRolesCanParticipate set to true * Site 3 group has 1 maintain and 1 access user @@ -1297,8 +1299,8 @@ templateAdmin, null, Boolean.TRUE, Boolean.FALSE, Boolean.TRUE, EvalTestDataLoad.LOCKED, EvalConstants.EVALUATION_AUTHCONTROL_AUTH_REQ, null, null); - - + + // evaluation Complete (ended yesterday, viewable tomorrow), recent close, still evaluationGracePeriod = new EvalEvaluation(EvalConstants.EVALUATION_TYPE_EVALUATION, EvalTestDataLoad.ADMIN_USER_ID, "Eval grace period two", null, @@ -1314,25 +1316,25 @@ EvalConstants.EVALUATION_STATE_ACTIVE, EvalConstants.SHARING_PUBLIC, EvalConstants.INSTRUCTOR_REQUIRED, new Integer(0), null, null, null, null, evalsys_1007_templateUser01, null, Boolean.TRUE, Boolean.FALSE, Boolean.FALSE, UNLOCKED, EvalConstants.EVALUATION_AUTHCONTROL_AUTH_REQ, null, null); - + evaluationDue_viewIgnoreDates = new EvalEvaluation(EvalConstants.EVALUATION_TYPE_EVALUATION, EVALSYS_1007_MAINT_USER_ID_01, "evaluationDue_viewIgnoreDates", null, threeDaysAgo, yesterday, tomorrow, tomorrow, true, tomorrow, true, tomorrow, EvalConstants.EVALUATION_STATE_GRACEPERIOD, EvalConstants.SHARING_PUBLIC, EvalConstants.INSTRUCTOR_REQUIRED, new Integer(0), null, null, null, null, evalsys_1007_templateUser01, null, Boolean.TRUE, Boolean.FALSE, Boolean.FALSE, UNLOCKED, EvalConstants.EVALUATION_AUTHCONTROL_AUTH_REQ, null, null); - + evaluationClosed_viewIgnoreDates = new EvalEvaluation(EvalConstants.EVALUATION_TYPE_EVALUATION, EVALSYS_1007_MAINT_USER_ID_01, "evaluationClosed_viewIgnoreDates", null, fourDaysAgo, threeDaysAgo, yesterday, tomorrow, true, tomorrow, true, tomorrow, EvalConstants.EVALUATION_STATE_CLOSED, EvalConstants.SHARING_PUBLIC, EvalConstants.INSTRUCTOR_REQUIRED, new Integer(0), null, null, null, null, evalsys_1007_templateUser01, null, Boolean.TRUE, Boolean.FALSE, Boolean.FALSE, UNLOCKED, EvalConstants.EVALUATION_AUTHCONTROL_AUTH_REQ, null, null); - + evaluationPartial_noAuthNoGroups = new EvalEvaluation(EvalConstants.EVALUATION_TYPE_EVALUATION, MAINT_USER_ID_3, "evaluationInque_noAuthNoGroups", null, tomorrow, fourDaysFuture, null, null, false, null, false, null, EvalConstants.EVALUATION_STATE_PARTIAL, EvalConstants.SHARING_PUBLIC, EvalConstants.INSTRUCTOR_REQUIRED, new Integer(0), null, null, null, null, templateUser_4, null, Boolean.TRUE, Boolean.FALSE, Boolean.FALSE, UNLOCKED, EvalConstants.EVALUATION_AUTHCONTROL_NONE, null, null); - + // email templates emailTemplate1 = new EvalEmailTemplate(ADMIN_USER_ID, EvalConstants.EMAIL_TEMPLATE_AVAILABLE, "Email Subject 1", "Email Template 1"); evaluationNew.setAvailableEmailTemplate(emailTemplate1); @@ -1369,7 +1371,7 @@ dao.save(evaluationProvided); dao.save(evaluationDeleted); dao.save(evaluationGracePeriod); - + //evaluation used to test allRolesCanParticipate property dao.save(evaluation_simpleAssignments_allRolesParticipate); dao.save(evaluation_simpleAssignments_notAllRolesParticipate); @@ -1405,26 +1407,26 @@ assign10 = new EvalAssignGroup( MAINT_USER_ID, SITE1_REF, EvalConstants.GROUP_TYPE_SITE, evaluationClosedUntaken, Boolean.TRUE, Boolean.TRUE, Boolean.FALSE); assign11 = new EvalAssignGroup(MAINT_USER_ID, SITE1_REF, EvalConstants.GROUP_TYPE_SITE, - evaluationGracePeriod, Boolean.TRUE, Boolean.TRUE, Boolean.FALSE); + evaluationGracePeriod, Boolean.TRUE, Boolean.TRUE, Boolean.FALSE); assign12 = new EvalAssignGroup(MAINT_USER_ID_3, SITE4_REF, EvalConstants.GROUP_TYPE_SITE, - evaluation_simpleAssignments_allRolesParticipate, Boolean.TRUE, Boolean.TRUE, Boolean.FALSE); + evaluation_simpleAssignments_allRolesParticipate, Boolean.TRUE, Boolean.TRUE, Boolean.FALSE); assign13 = new EvalAssignGroup(MAINT_USER_ID_3, SITE4_REF, EvalConstants.GROUP_TYPE_SITE, - evaluation_simpleAssignments_notAllRolesParticipate, Boolean.TRUE, Boolean.TRUE, Boolean.FALSE); + evaluation_simpleAssignments_notAllRolesParticipate, Boolean.TRUE, Boolean.TRUE, Boolean.FALSE); assign14 = new EvalAssignGroup(MAINT_USER_ID_3, SITE5_REF, EvalConstants.GROUP_TYPE_SITE, - evaluation_noAssignments_allRolesParticipate, Boolean.TRUE, Boolean.TRUE, Boolean.FALSE); + evaluation_noAssignments_allRolesParticipate, Boolean.TRUE, Boolean.TRUE, Boolean.FALSE); assign15 = new EvalAssignGroup(MAINT_USER_ID_3, SITE5_REF, EvalConstants.GROUP_TYPE_SITE, - evaluation_noAssignments_notAllRolesParticipate, Boolean.TRUE, Boolean.TRUE, Boolean.FALSE); + evaluation_noAssignments_notAllRolesParticipate, Boolean.TRUE, Boolean.TRUE, Boolean.FALSE); assign16 = new EvalAssignGroup(MAINT_USER_ID_3, SITE6_REF, EvalConstants.GROUP_TYPE_SITE, - evaluation_allRoleAssignments_allRolesParticipate, Boolean.TRUE, Boolean.TRUE, Boolean.FALSE); + evaluation_allRoleAssignments_allRolesParticipate, Boolean.TRUE, Boolean.TRUE, Boolean.FALSE); assign17 = new EvalAssignGroup(MAINT_USER_ID_3, SITE6_REF, EvalConstants.GROUP_TYPE_SITE, - evaluation_allRoleAssignments_notAllRolesParticipate, Boolean.TRUE, Boolean.TRUE, Boolean.FALSE); - + evaluation_allRoleAssignments_notAllRolesParticipate, Boolean.TRUE, Boolean.TRUE, Boolean.FALSE); + evalsys_1007_assign03 = new EvalAssignGroup( EVALSYS_1007_MAINT_USER_ID_01, EVALSYS_1007_SITE_REF_01, EvalConstants.GROUP_TYPE_SITE, evaluationActive_viewIgnoreDates, Boolean.TRUE, Boolean.TRUE, Boolean.TRUE); evalsys_1007_assign02 = new EvalAssignGroup( EVALSYS_1007_MAINT_USER_ID_01, EVALSYS_1007_SITE_REF_01, EvalConstants.GROUP_TYPE_SITE, - evaluationDue_viewIgnoreDates, Boolean.TRUE, Boolean.TRUE, Boolean.TRUE); + evaluationDue_viewIgnoreDates, Boolean.TRUE, Boolean.TRUE, Boolean.TRUE); evalsys_1007_assign01 = new EvalAssignGroup( EVALSYS_1007_MAINT_USER_ID_01, EVALSYS_1007_SITE_REF_01, EvalConstants.GROUP_TYPE_SITE, - evaluationClosed_viewIgnoreDates, Boolean.TRUE, Boolean.TRUE, Boolean.TRUE); + evaluationClosed_viewIgnoreDates, Boolean.TRUE, Boolean.TRUE, Boolean.TRUE); // Dick, you cannot assign 2 groups to an eval with the same evalGroupId... I have fixed this by making up a fake id -AZ assignGroupProvided = new EvalAssignGroup( ADMIN_USER_ID, "AZ-new-ref", EvalConstants.GROUP_TYPE_SITE, evaluationNewAdmin, Boolean.TRUE, Boolean.TRUE, Boolean.FALSE); Index: impl/src/test/org/sakaiproject/evaluation/dao/EvaluationDaoImplTest.java =================================================================== --- impl/src/test/org/sakaiproject/evaluation/dao/EvaluationDaoImplTest.java (revision 81089) +++ impl/src/test/org/sakaiproject/evaluation/dao/EvaluationDaoImplTest.java (working copy) @@ -15,6 +15,7 @@ package org.sakaiproject.evaluation.dao; import java.util.Date; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -141,7 +142,7 @@ evaluationDao.findAll(EvalEmailTemplate.class); } - public void testGetPaticipants() { + public void testGetParticipants() { List l = null; long start = 0l; @@ -163,10 +164,8 @@ assertNotNull(l); assertEquals(2, l.size()); - start = System.currentTimeMillis(); l = evaluationDao.getParticipantsForEval(etdl.evaluationActive.getId(), null, new String[] {EvalTestDataLoad.SITE2_REF}, null, null, null, null); - System.out.println("Query executed in " + (System.currentTimeMillis()-start) + " ms"); assertNotNull(l); assertEquals(0, l.size()); @@ -187,12 +186,109 @@ assertEquals(11, l.size()); // get all active evals a user is assigned to - start = System.currentTimeMillis(); l = evaluationDao.getParticipantsForEval(null, EvalTestDataLoad.USER_ID, null, EvalAssignUser.TYPE_EVALUATOR, null, null, EvalConstants.EVALUATION_STATE_ACTIVE); - System.out.println("Query executed in " + (System.currentTimeMillis()-start) + " ms"); assertNotNull(l); assertEquals(2, l.size()); + + // test the way that the reminders email gets participants + //evaluationService.getParticipantsForEval(evaluationId, null, limitGroupIds, null, null, includeConstant, null); + l = evaluationDao.getParticipantsForEval(etdl.evaluationActiveUntaken.getId(), null, null, + null, null, EvalConstants.EVAL_INCLUDE_NONTAKERS, null); + assertNotNull(l); + assertEquals(1, l.size()); + + l = evaluationDao.getParticipantsForEval(etdl.evaluationActiveUntaken.getId(), null, null, + null, null, EvalConstants.EVAL_INCLUDE_IN_PROGRESS, null); + assertNotNull(l); + assertEquals(0, l.size()); + + l = evaluationDao.getParticipantsForEval(etdl.evaluationActive.getId(), null, null, + null, null, EvalConstants.EVAL_INCLUDE_NONTAKERS, null); + assertNotNull(l); + assertEquals(0, l.size()); + + l = evaluationDao.getParticipantsForEval(etdl.evaluationActive.getId(), null, null, + null, null, EvalConstants.EVAL_INCLUDE_IN_PROGRESS, null); + assertNotNull(l); + assertEquals(0, l.size()); + + + // test fetching various sets of participants (using the untaken eval) + // first it has to have 3 users assigned to it so we assign 2 more (EvalTestDataLoad.USER_ID is already assigned) + evaluationDao.save( new EvalAssignUser(EvalTestDataLoad.USER_ID_4, etdl.evaluationActiveUntaken, EvalTestDataLoad.SITE1_REF, EvalTestDataLoad.MAINT_USER_ID) ); + evaluationDao.save( new EvalAssignUser(EvalTestDataLoad.USER_ID_5, etdl.evaluationActiveUntaken, EvalTestDataLoad.SITE1_REF, EvalTestDataLoad.MAINT_USER_ID) ); + + l = evaluationDao.getParticipantsForEval(etdl.evaluationActiveUntaken.getId(), null, null, + null, null, EvalConstants.EVAL_INCLUDE_ALL, null); + assertNotNull(l); + assertEquals(3, l.size()); + + l = evaluationDao.getParticipantsForEval(etdl.evaluationActiveUntaken.getId(), null, null, + null, null, EvalConstants.EVAL_INCLUDE_NONTAKERS, null); + assertNotNull(l); + assertEquals(3, l.size()); + + l = evaluationDao.getParticipantsForEval(etdl.evaluationActiveUntaken.getId(), null, null, + null, null, EvalConstants.EVAL_INCLUDE_IN_PROGRESS, null); + assertNotNull(l); + assertEquals(0, l.size()); + + l = evaluationDao.getParticipantsForEval(etdl.evaluationActiveUntaken.getId(), null, null, + null, null, EvalConstants.EVAL_INCLUDE_RESPONDENTS, null); + assertNotNull(l); + assertEquals(0, l.size()); + + // add in a saved response + EvalResponse r1 = new EvalResponse(EvalTestDataLoad.USER_ID, EvalTestDataLoad.SITE2_REF, etdl.evaluationActiveUntaken, new Date(), null, null); + r1.setAnswers( new HashSet() ); + evaluationDao.save(r1); + + l = evaluationDao.getParticipantsForEval(etdl.evaluationActiveUntaken.getId(), null, null, + null, null, EvalConstants.EVAL_INCLUDE_ALL, null); + assertNotNull(l); + assertEquals(3, l.size()); + + l = evaluationDao.getParticipantsForEval(etdl.evaluationActiveUntaken.getId(), null, null, + null, null, EvalConstants.EVAL_INCLUDE_NONTAKERS, null); + assertNotNull(l); + assertEquals(2, l.size()); + + l = evaluationDao.getParticipantsForEval(etdl.evaluationActiveUntaken.getId(), null, null, + null, null, EvalConstants.EVAL_INCLUDE_IN_PROGRESS, null); + assertNotNull(l); + assertEquals(1, l.size()); + + l = evaluationDao.getParticipantsForEval(etdl.evaluationActiveUntaken.getId(), null, null, + null, null, EvalConstants.EVAL_INCLUDE_RESPONDENTS, null); + assertNotNull(l); + assertEquals(0, l.size()); + + // add in a completed response + EvalResponse r2 = new EvalResponse(EvalTestDataLoad.USER_ID_4, EvalTestDataLoad.SITE2_REF, etdl.evaluationActiveUntaken, etdl.yesterday, new Date(), null); + r2.setAnswers( new HashSet() ); + evaluationDao.save(r2); + + l = evaluationDao.getParticipantsForEval(etdl.evaluationActiveUntaken.getId(), null, null, + null, null, EvalConstants.EVAL_INCLUDE_ALL, null); + assertNotNull(l); + assertEquals(3, l.size()); + + l = evaluationDao.getParticipantsForEval(etdl.evaluationActiveUntaken.getId(), null, null, + null, null, EvalConstants.EVAL_INCLUDE_NONTAKERS, null); + assertNotNull(l); + assertEquals(1, l.size()); + + l = evaluationDao.getParticipantsForEval(etdl.evaluationActiveUntaken.getId(), null, null, + null, null, EvalConstants.EVAL_INCLUDE_IN_PROGRESS, null); + assertNotNull(l); + assertEquals(1, l.size()); + + l = evaluationDao.getParticipantsForEval(etdl.evaluationActiveUntaken.getId(), null, null, + null, null, EvalConstants.EVAL_INCLUDE_RESPONDENTS, null); + assertNotNull(l); + assertEquals(1, l.size()); + } public void testGetEvalsUserCanTake() { @@ -1105,25 +1201,37 @@ Set userIds = null; // check getting responders from complete evaluation - userIds = evaluationDao.getResponseUserIds(etdl.evaluationClosed.getId(), null); + userIds = evaluationDao.getResponseUserIds(etdl.evaluationClosed.getId(), null, true); assertNotNull(userIds); assertEquals(2, userIds.size()); assertTrue(userIds.contains(EvalTestDataLoad.USER_ID)); assertTrue(userIds.contains(EvalTestDataLoad.STUDENT_USER_ID)); + // check getting incomplete responders from complete evaluation + userIds = evaluationDao.getResponseUserIds(etdl.evaluationClosed.getId(), null, false); + assertNotNull(userIds); + assertEquals(0, userIds.size()); + + // check getting all responders from complete evaluation + userIds = evaluationDao.getResponseUserIds(etdl.evaluationClosed.getId(), null, null); + assertNotNull(userIds); + assertEquals(2, userIds.size()); + assertTrue(userIds.contains(EvalTestDataLoad.USER_ID)); + assertTrue(userIds.contains(EvalTestDataLoad.STUDENT_USER_ID)); + // test getting from subset of the groups - userIds = evaluationDao.getResponseUserIds(etdl.evaluationClosed.getId(), new String[] {EvalTestDataLoad.SITE1_REF}); + userIds = evaluationDao.getResponseUserIds(etdl.evaluationClosed.getId(), new String[] {EvalTestDataLoad.SITE1_REF}, true); assertNotNull(userIds); assertEquals(1, userIds.size()); assertTrue(userIds.contains(EvalTestDataLoad.USER_ID)); // test getting none - userIds = evaluationDao.getResponseUserIds(etdl.evaluationActiveUntaken.getId(), null); + userIds = evaluationDao.getResponseUserIds(etdl.evaluationActiveUntaken.getId(), null, true); assertNotNull(userIds); assertEquals(0, userIds.size()); // test using invalid group ids retrieves no results - userIds = evaluationDao.getResponseUserIds(etdl.evaluationClosed.getId(), new String[] {"xxxxxx", "fakeyandnotreal"}); + userIds = evaluationDao.getResponseUserIds(etdl.evaluationClosed.getId(), new String[] {"xxxxxx", "fakeyandnotreal"}, true); assertNotNull(userIds); assertEquals(0, userIds.size()); @@ -1697,10 +1805,10 @@ assertNotNull(eauId); eau.setCompletedDate(new Date()); evaluationDao.update(eau); + EvalAssignUser eau0 = evaluationDao.findById(EvalAssignUser.class, eau.getId()); + assertNotNull(eau0); + assertNotNull(eau0.getCompletedDate()); } - EvalAssignUser eau0 = evaluationDao.findById(EvalAssignUser.class, eau.getId()); - assertNotNull(eau0); - assertNotNull(eau0.getCompletedDate()); int count9 = this.evaluationDao.selectConsolidatedEmailRecipients(false, (Date) null, true, new Date(System.currentTimeMillis() + MILLISECONDS_PER_DAY), EvalConstants.EMAIL_TEMPLATE_CONSOLIDATED_REMINDER); assertEquals(0,count9); List> mapping9 = this.evaluationDao.getConsolidatedEmailMapping(false, 100, 0); Index: impl/src/test/org/sakaiproject/evaluation/logic/EvalEvaluationSetupServiceImplTest.java =================================================================== --- impl/src/test/org/sakaiproject/evaluation/logic/EvalEvaluationSetupServiceImplTest.java (revision 81089) +++ impl/src/test/org/sakaiproject/evaluation/logic/EvalEvaluationSetupServiceImplTest.java (working copy) @@ -531,12 +531,12 @@ } /** - * Test method for {@link org.sakaiproject.evaluation.logic.EvalEvaluationSetupServiceImpl.getEvaluationsForEvaluatee(java.lang.String)}. + * Test method for getEvaluationsForEvaluatee */ public void testGetEvaluationsForEvaluatee() { List evals = null; - evals = this.evaluationSetupService.getEvaluationsForEvaluatee(EvalTestDataLoad.MAINT_USER_ID); + evals = this.evaluationSetupService.getEvaluationsForEvaluatee(EvalTestDataLoad.MAINT_USER_ID, null); assertNotNull(evals); assertEquals(7, evals.size()); @@ -545,12 +545,20 @@ null, EvalAssignUser.TYPE_EVALUATEE, null, null, null); assertNotNull(assignUsers); } - - evals = this.evaluationSetupService.getEvaluationsForEvaluatee(EvalTestDataLoad.STUDENT_USER_ID); + + evals = this.evaluationSetupService.getEvaluationsForEvaluatee(EvalTestDataLoad.MAINT_USER_ID, true); + assertNotNull(evals); + assertEquals(6, evals.size()); + + evals = this.evaluationSetupService.getEvaluationsForEvaluatee(EvalTestDataLoad.MAINT_USER_ID, false); + assertNotNull(evals); + assertEquals(4, evals.size()); + + evals = this.evaluationSetupService.getEvaluationsForEvaluatee(EvalTestDataLoad.STUDENT_USER_ID, null); assertNotNull(evals); assertEquals(0,evals.size()); - evals = this.evaluationSetupService.getEvaluationsForEvaluatee(EvalTestDataLoad.USER_ID); + evals = this.evaluationSetupService.getEvaluationsForEvaluatee(EvalTestDataLoad.USER_ID, null); assertNotNull(evals); assertEquals(0,evals.size()); } Index: impl/src/java/org/sakaiproject/evaluation/dao/PreloadDataImpl.java =================================================================== --- impl/src/java/org/sakaiproject/evaluation/dao/PreloadDataImpl.java (revision 81089) +++ impl/src/java/org/sakaiproject/evaluation/dao/PreloadDataImpl.java (working copy) @@ -443,6 +443,7 @@ evalConfigMap.put(EvalSettings.STUDENT_ALLOWED_LEAVE_UNANSWERED, true); evalConfigMap.put(EvalSettings.STUDENT_MODIFY_RESPONSES, false); evalConfigMap.put(EvalSettings.STUDENT_SAVE_WITHOUT_SUBMIT, false); + evalConfigMap.put(EvalSettings.STUDENT_CANCEL_ALLOWED, false); evalConfigMap.put(EvalSettings.STUDENT_ALLOWED_VIEW_RESULTS, false); // Default Admin settings @@ -468,6 +469,7 @@ evalConfigMap.put(EvalSettings.USE_EXPERT_ITEMS, true); evalConfigMap.put(EvalSettings.REQUIRE_COMMENTS_BLOCK, false); evalConfigMap.put(EvalSettings.EVAL_RECENTLY_CLOSED_DAYS, 10); + evalConfigMap.put(EvalSettings.EVAL_EVALUATEE_RECENTLY_CLOSED_DAYS, 10); evalConfigMap.put(EvalSettings.ENABLE_SUMMARY_SITES_BOX, false); evalConfigMap.put(EvalSettings.ENABLE_EVAL_CATEGORIES, false); Index: impl/src/java/org/sakaiproject/evaluation/dao/EvaluationDao.java =================================================================== --- impl/src/java/org/sakaiproject/evaluation/dao/EvaluationDao.java (revision 81089) +++ impl/src/java/org/sakaiproject/evaluation/dao/EvaluationDao.java (working copy) @@ -302,8 +302,7 @@ * if null then return all responses * @return a list of response ids (Long) for {@link EvalResponse} objects */ - public List getResponseIds(Long evalId, String[] evalGroupIds, String[] userIds, - Boolean completed); + public List getResponseIds(Long evalId, String[] evalGroupIds, String[] userIds, Boolean completed); /** * Removes an array of responses and all their associated answers at @@ -341,9 +340,12 @@ * @param evaluationId a unique id for an {@link EvalEvaluation} * @param evalGroupIds the unique eval group ids associated with this evaluation, * can be null or empty to get all responses for this evaluation + * @param completed if true only return the completed responses, + * if false only return the incomplete responses, + * if null then return all responses * @return a set of internal userIds */ - public Set getResponseUserIds(Long evaluationId, String[] evalGroupIds); + public Set getResponseUserIds(Long evaluationId, String[] evalGroupIds, Boolean completed); /** * Get all the evalGroupIds for an evaluation which are viewable by Index: impl/src/java/org/sakaiproject/evaluation/dao/EvaluationDaoImpl.java =================================================================== --- impl/src/java/org/sakaiproject/evaluation/dao/EvaluationDaoImpl.java (revision 81089) +++ impl/src/java/org/sakaiproject/evaluation/dao/EvaluationDaoImpl.java (working copy) @@ -14,6 +14,7 @@ */ package org.sakaiproject.evaluation.dao; +import java.io.Serializable; import java.util.ArrayList; import java.util.Collections; import java.util.Date; @@ -115,6 +116,30 @@ } } + /** + * This really does not work for most cases so be very careful with it + * @param object + */ + protected void forceEvict(Serializable object) { + boolean active = false; + try { + Session session = getSession(); + if (session.isOpen() && session.isConnected()) { + if (session.contains(object)) { + active = true; + session.evict(object); + } + } else { + log.warn("Session is not open OR not connected, cannot evict objects"); + } + if (!active) { + log.info("Unable to evict object ("+object.getClass().getName()+") from session, it is not persistent: "+object); + } + } catch (Exception e) { + log.warn("Failure while attempting to evict object ("+object.getClass().getName()+") from session", e); + } + } + public void fixupDatabase() { // fix up some of the null fields long count = 0; @@ -245,18 +270,19 @@ assignTypeHQL = " and eau.type = :assignType"; // now set up the filter if (EvalConstants.EVAL_INCLUDE_NONTAKERS.equals(includeConstant)) { - // get all users who have NOT responded - userFilter = getResponseUserIds(evaluationId, groupIds); - includeFilterUsers = false; + // get all users who have responded either way + userFilter = getResponseUserIds(evaluationId, groupIds, null); // exclude + includeFilterUsers = false; // INVERT the search } else if (EvalConstants.EVAL_INCLUDE_RESPONDENTS.equals(includeConstant)) { // get all users who have responded - userFilter = getResponseUserIds(evaluationId, groupIds); + userFilter = getResponseUserIds(evaluationId, groupIds, true); includeFilterUsers = true; + } else if (EvalConstants.EVAL_INCLUDE_IN_PROGRESS.equals(includeConstant)) { + // get all users who have saved + userFilter = getResponseUserIds(evaluationId, groupIds, false); + includeFilterUsers = true; } else if (EvalConstants.EVAL_INCLUDE_ALL.equals(includeConstant)) { // do nothing - } else if (EvalConstants.EVAL_INCLUDE_IN_PROGRESS.equals(includeConstant)) { - userFilter = getResponseIncompleteUserIds(evaluationId, groupIds); - includeFilterUsers = true; } else { throw new IllegalArgumentException("Unknown includeConstant: " + includeConstant); } @@ -270,20 +296,30 @@ List assignments = new ArrayList( results ); // This code is potentially expensive but there is not really a better way to handle it -AZ - if (userFilter != null && ! userFilter.isEmpty()) { - // filter the results based on the userFilter - for (Iterator iterator = assignments.iterator(); iterator.hasNext();) { - EvalAssignUser evalAssignUser = iterator.next(); - String uid = evalAssignUser.getUserId(); + if (userFilter != null) { + if (userFilter.isEmpty()) { + // employ shortcuts when the filter set is empty if (includeFilterUsers) { - // only include users in the filter - if (! userFilter.contains(uid)) { - iterator.remove(); - } + // no one to include so just wipe the set + assignments.clear(); } else { - // exclude all users in the filter - if (userFilter.contains(uid)) { - iterator.remove(); + // no one to exclude to just return the complete set + } + } else { + // filter the results based on the userFilter + for (Iterator iterator = assignments.iterator(); iterator.hasNext();) { + EvalAssignUser evalAssignUser = iterator.next(); + String uid = evalAssignUser.getUserId(); + if (includeFilterUsers) { + // only include users in the filter + if (! userFilter.contains(uid)) { + iterator.remove(); + } + } else { + // exclude all users in the filter + if (userFilter.contains(uid)) { + iterator.remove(); + } } } } @@ -1172,61 +1208,42 @@ /** - * Get all the users who have completely responded to an evaluation + * Get all the users who have responded to an evaluation (completely or partly) * and optionally within group(s) assigned to that evaluation * * @param evaluationId a unique id for an {@link EvalEvaluation} - * @param evalGroupIds the unique eval group ids associated with this evaluation, + * @param evalGroupIds [OPTIONAL] the unique eval group ids associated with this evaluation, * can be null or empty to get all responses for this evaluation + * @param completed [OPTIONAL] if true then only completed (submitted) responses, + * if false, then only incomplete (saved) responses, + * if null, then retrieve all responses (incomplete and complete) * @return a set of internal userIds */ - public Set getResponseUserIds(Long evaluationId, String[] evalGroupIds) { + public Set getResponseUserIds(Long evaluationId, String[] evalGroupIds, Boolean completed) { Map params = new HashMap(); String groupsHQL = ""; if (evalGroupIds != null && evalGroupIds.length > 0) { groupsHQL = " and response.evalGroupId in (:evalGroupIds) "; params.put("evalGroupIds", evalGroupIds); } + String completeHQL = ""; + if (completed != null) { + completeHQL = " and response.endTime is "+(completed ? "not" : "")+" null "; + } params.put("evaluationId", evaluationId); String hql = "SELECT response.owner from EvalResponse as response where response.evaluation.id = :evaluationId " - + " and response.endTime is not null " + groupsHQL + " order by response.id"; + + completeHQL + groupsHQL + " order by response.id"; List results = executeHqlQuery(hql, params, 0, 0); // put the results into a set and convert them to strings Set responseUsers = new HashSet(); for (Object object : results) { responseUsers.add((String) object); } + if (log.isDebugEnabled()) log.debug("ResponseUserIds(eval:"+evaluationId+", groups:" + +ArrayUtils.arrayToString(evalGroupIds)+", completed="+completed+"): users="+responseUsers); return responseUsers; } - /** - * Get all the users who have saved but not completed a response to an evaluation - * and optionally within group(s) assigned to that evaluation - * - * @param evaluationId a unique id for an {@link EvalEvaluation} - * @param evalGroupIds the unique eval group ids associated with this evaluation, - * can be null or empty to get all responses for this evaluation - * @return a set of internal userIds - */ - private Set getResponseIncompleteUserIds(Long evaluationId, String[] evalGroupIds) { - Map params = new HashMap(); - String groupsHQL = ""; - if (evalGroupIds != null && evalGroupIds.length > 0) { - groupsHQL = " and response.evalGroupId in (:evalGroupIds) "; - params.put("evalGroupIds", evalGroupIds); - } - params.put("evaluationId", evaluationId); - String hql = "SELECT response.owner from EvalResponse as response where response.evaluation.id = :evaluationId " - + " and response.endTime is null " + groupsHQL + " order by response.id"; - List results = executeHqlQuery(hql, params, 0, 0); - // put the results into a set and convert them to strings - Set responseUsers = new HashSet(); - for (Object object : results) { - responseUsers.add((String) object); - } - return responseUsers; - } - /** getResponsesSavedInProgress returns a List of EvalResponses that have been saved * but not submitted, meaning that they will not be included in any statistics. * @param activeEvaluationsOnly If true, only include responses associated with Evaluations @@ -1577,8 +1594,10 @@ lockTemplate(template, Boolean.TRUE); } + // This is a horrible hack to try to work around hibernate stupidity evaluation.setLocked(Boolean.TRUE); - getHibernateTemplate().update(evaluation); + getSession().merge(evaluation); + getSession().evict(evaluation); return true; } } else { @@ -1588,8 +1607,10 @@ return false; } else { // unlock evaluation + // This is a horrible hack to try to work around hibernate stupidity evaluation.setLocked(Boolean.FALSE); - getHibernateTemplate().update(evaluation); + getSession().merge(evaluation); + getSession().evict(evaluation); // unlock associated templates if there are any if (evaluation.getTemplate() != null) { Index: impl/src/java/org/sakaiproject/evaluation/logic/EvalCommonLogicImpl.java =================================================================== --- impl/src/java/org/sakaiproject/evaluation/logic/EvalCommonLogicImpl.java (revision 81089) +++ impl/src/java/org/sakaiproject/evaluation/logic/EvalCommonLogicImpl.java (working copy) @@ -96,11 +96,14 @@ public void setEvalGroupsProvider(EvalGroupsProvider evalGroupsProvider) { this.evalGroupsProvider = evalGroupsProvider; } - + public EvalGroupsProvider getEvalGroupsProvider() { + return evalGroupsProvider; + } + public void init() { log.debug("init, register security perms"); - // setup provider + // auto setup provider if (evalGroupsProvider == null) { evalGroupsProvider = (EvalGroupsProvider) externalLogic.getBean(EvalGroupsProvider.class); if (evalGroupsProvider != null) @@ -235,6 +238,7 @@ return user; } + @SuppressWarnings("null") public List getEvalUsersByIds(String[] userIds) { List users = new ArrayList(); boolean foundAll = false; @@ -409,7 +413,7 @@ } public int countEvalGroupsForUser(String userId, String permission) { - log.debug("userId: " + userId + ", permission: " + permission); + if (log.isDebugEnabled()) log.debug("userId: " + userId + ", permission: " + permission); int count = externalLogic.countEvalGroupsForUser(userId, permission); @@ -428,12 +432,13 @@ } } + if (log.isDebugEnabled()) log.debug("userId: " + userId + ", permission: " + permission + ", count: " + count); return count; } @SuppressWarnings("rawtypes") public List getEvalGroupsForUser(String userId, String permission) { - log.debug("userId: " + userId + ", permission: " + permission); + if (log.isDebugEnabled()) log.debug("userId: " + userId + ", permission: " + permission); List l = new ArrayList(); @@ -525,6 +530,21 @@ return userIds; } + public String calculateViewability(String state) { + Boolean viewResultsIgnoreDate = (Boolean) evalSettings.get(EvalSettings.VIEW_SURVEY_RESULTS_IGNORE_DATES); + + if(viewResultsIgnoreDate != null && viewResultsIgnoreDate) { + if(EvalConstants.EVALUATION_STATE_ACTIVE.equals(state) || + EvalConstants.EVALUATION_STATE_GRACEPERIOD.equals(state) || + EvalConstants.EVALUATION_STATE_CLOSED.equals(state)) { + + return EvalConstants.EVALUATION_STATE_VIEWABLE; + } + } + + return state; + } + public boolean isUserAllowedInEvalGroup(String userId, String permission, String evalGroupId) { /* NOTE: false checks end up being really costly and should probably be cached @@ -587,8 +607,11 @@ // FIXME: this is not implemented correctly, needs to be fixed so it works with adhoc and provided groups, forcing this to true for now so it does not break things -AZ public boolean isEvalGroupPublished(String evalGroupId) { - return true; - //return externalLogic.isEvalGroupPublished(evalGroupId); + if ((Boolean) evalSettings.get(EvalSettings.ENABLE_SITE_GROUP_PUBLISH_CHECK)) { + // FIXME this is NOT implemented correctly and will return false for all non-sakai Site type groups + return externalLogic.isEvalGroupPublished(evalGroupId); + } + return true; // default to true (all groups published) } @@ -846,4 +869,17 @@ return this.externalLogic.scheduleCronJob(jobClassBeanId, dataMap); } + /* (non-Javadoc) + * @see org.sakaiproject.evaluation.logic.EvalCommonLogic#registerEvalGroupsProvider(org.sakaiproject.evaluation.providers.EvalGroupsProvider) + */ + public void registerEvalGroupsProvider(EvalGroupsProvider provider) { + if (provider != null) { + log.info("Registered EvalGroupProvider: "+provider.getClass().getName()); + this.evalGroupsProvider = provider; + } else { + log.info("Unregistered EvalGroupProvider"); + this.evalGroupsProvider = null; + } + } + } Index: impl/src/java/org/sakaiproject/evaluation/logic/EvalEmailsLogicImpl.java =================================================================== --- impl/src/java/org/sakaiproject/evaluation/logic/EvalEmailsLogicImpl.java (revision 81089) +++ impl/src/java/org/sakaiproject/evaluation/logic/EvalEmailsLogicImpl.java (working copy) @@ -28,7 +28,6 @@ import org.apache.commons.logging.LogFactory; import org.sakaiproject.evaluation.constant.EvalConstants; import org.sakaiproject.evaluation.jobmonitor.JobStatusReporter; -import org.sakaiproject.evaluation.jobmonitor.LoggingJobStatusReporter; import org.sakaiproject.evaluation.logic.entity.EvalReportsEntityProvider; import org.sakaiproject.evaluation.logic.model.EvalEmailMessage; import org.sakaiproject.evaluation.logic.model.EvalGroup; @@ -105,8 +104,8 @@ log.debug("Found " + groups.size() + " groups for new evaluation: " + evaluationId); } + String sampleEmail = null; List sentEmails = new ArrayList(); - int emailsSentCt=0; // loop through contexts and send emails to correct users in each evalGroupId for (int i = 0; i < groups.size(); i++) { EvalGroup group = (EvalGroup) groups.get(i); @@ -140,31 +139,28 @@ // replace the text of the template with real values EvalEmailMessage em = makeEmailMessage(emailTemplate.getMessage(), emailTemplate.getSubject(), eval, group); + if (sampleEmail == null && em.message != null) { + sampleEmail = em.message; + } // send the actual emails for this evalGroupId String[] emailAddresses = sendUsersEmails(from, toUserIds, em.subject, em.message); log.info("Sent evaluation created message to " + emailAddresses.length + " users (attempted to send to "+toUserIds.length+")"); - emailsSentCt++; // store sent emails to return for (int j = 0; j < emailAddresses.length; j++) { sentEmails.add(emailAddresses[j]); } commonLogic.registerEntityEvent(EVENT_EMAIL_CREATED, eval); } - + + if (sampleEmail == null && emailTemplate != null) { + sampleEmail = emailTemplate.getMessage(); + } + String[] emailsSent = sentEmails.toArray(new String[sentEmails.size()]); // send email to admin that reminders are finished. - boolean sendJobCompletion = (Boolean) settings.get(EvalSettings.ENABLE_JOB_COMPLETION_EMAIL); - if (sendJobCompletion) { - Map replacementValues = new HashMap(); - replacementValues.put("HelpdeskEmail", from); - replacementValues.put("EvalTitle", eval.getTitle()); - Integer iEmailsSentCt = Integer.valueOf(emailsSentCt); - replacementValues.put("NumEmailsSent", iEmailsSentCt.toString()); - replacementValues.put("JobType", EvalConstants.JOB_TYPE_CREATED.substring(9)); - sendEmailJobCompleted(eval.getId(), replacementValues); - } - - return (String[]) sentEmails.toArray(new String[] {}); + handleJobCompletion(eval, emailsSent, EvalConstants.JOB_TYPE_CREATED, from, sampleEmail); + + return emailsSent; } @@ -188,13 +184,14 @@ evaluationService.getAssignGroupsForEvals(new Long[] { evaluationId }, true, null); List assignGroups = evalAssignGroups.get(evaluationId); + String sampleEmail = null; List sentEmails = new ArrayList(); - int emailsSentCt=0; // loop through groups and send emails to correct users group for (int i = 0; i < assignGroups.size(); i++) { EvalAssignGroup assignGroup = assignGroups.get(i); if(! commonLogic.isEvalGroupPublished(assignGroup.getEvalGroupId())) { + log.info("Skipping available email for evaluationId ("+evaluationId+") and group ("+assignGroup.getEvalGroupId()+") because the group is not published"); continue; } @@ -227,7 +224,10 @@ } // skip ahead if there is no one to send to - if (userIdsSet.size() == 0) continue; + if (userIdsSet.size() == 0) { + log.info("Skipping available email for evaluationId ("+evaluationId+") and group ("+assignGroup.getEvalGroupId()+") because there is no one (instructors or participants) to send the email to"); + continue; + } // turn the set into an array String[] toUserIds = (String[]) userIdsSet.toArray(new String[] {}); @@ -244,31 +244,27 @@ currentTemplate = emailOptInTemplate; } EvalEmailMessage em = makeEmailMessage(currentTemplate.getMessage(), currentTemplate.getSubject(), eval, group); + if (sampleEmail == null && em.message != null) { + sampleEmail = em.message; + } // send the actual emails for this evalGroupId String[] emailAddresses = sendUsersEmails(from, toUserIds, em.subject, em.message); log.info("Sent evaluation available message to " + emailAddresses.length + " users (attempted to send to "+toUserIds.length+")"); - emailsSentCt++; // store sent emails to return for (int j = 0; j < emailAddresses.length; j++) { sentEmails.add(emailAddresses[j]); } commonLogic.registerEntityEvent(EVENT_EMAIL_AVAILABLE, eval); } - - // send email to admin that reminders are finished. - boolean sendJobCompletion = (Boolean) settings.get(EvalSettings.ENABLE_JOB_COMPLETION_EMAIL); - if (sendJobCompletion) { - Map replacementValues = new HashMap(); - replacementValues.put("HelpdeskEmail", from); - replacementValues.put("EvalTitle", eval.getTitle()); - Integer iEmailsSentCt = Integer.valueOf(emailsSentCt); - replacementValues.put("NumEmailsSent", iEmailsSentCt.toString()); - replacementValues.put("JobType", EvalConstants.JOB_TYPE_ACTIVE.substring(9)); - sendEmailJobCompleted(eval.getId(), replacementValues); + + if (sampleEmail == null && emailTemplate != null) { + sampleEmail = emailTemplate.getMessage(); } + String[] emailsSent = sentEmails.toArray(new String[sentEmails.size()]); + handleJobCompletion(eval, emailsSent, EvalConstants.JOB_TYPE_ACTIVE, from, sampleEmail); - return (String[]) sentEmails.toArray(new String[] {}); + return emailsSent; } @@ -277,12 +273,13 @@ */ public String[] sendEvalAvailableGroupNotification(Long evaluationId, String evalGroupId) { - List sentEmails = new ArrayList(); - int emailsSentCt=0; - if(! commonLogic.isEvalGroupPublished(evalGroupId)) { + if (! commonLogic.isEvalGroupPublished(evalGroupId)) { return new String[] {}; } + String sampleEmail = null; + List sentEmails = new ArrayList(); + // get group EvalGroup group = commonLogic.makeEvalGroupObject(evalGroupId); // only process valid groups @@ -302,31 +299,27 @@ String[] toUserIds = (String[]) userIdsSet.toArray(new String[] {}); EvalEmailMessage em = makeEmailMessage(emailTemplate.getMessage(), emailTemplate.getSubject(), eval, group); + if (sampleEmail == null && em.message != null) { + sampleEmail = em.message; + } // send the actual emails for this evalGroupId String[] emailAddresses = sendUsersEmails(from, toUserIds, em.subject, em.message); log.info("Sent evaluation available group message to " + emailAddresses.length + " users (attempted to send to "+toUserIds.length+")"); - emailsSentCt++; // store sent emails to return for (int j = 0; j < emailAddresses.length; j++) { sentEmails.add(emailAddresses[j]); } commonLogic.registerEntityEvent(EVENT_EMAIL_GROUP_AVAILABLE, eval); } - - // send email to admin that reminders are finished. - boolean sendJobCompletion = (Boolean) settings.get(EvalSettings.ENABLE_JOB_COMPLETION_EMAIL); - if (sendJobCompletion) { - Map replacementValues = new HashMap(); - replacementValues.put("HelpdeskEmail", from); - replacementValues.put("EvalTitle", eval.getTitle()); - Integer iEmailsSentCt = Integer.valueOf(emailsSentCt); - replacementValues.put("NumEmailsSent", iEmailsSentCt.toString()); - replacementValues.put("JobType", EvalConstants.JOB_TYPE_ACTIVE.substring(9)); - sendEmailJobCompleted(eval.getId(), replacementValues); + + if (sampleEmail == null && emailTemplate != null) { + sampleEmail = emailTemplate.getMessage(); } - - return (String[]) sentEmails.toArray(new String[] {}); + String[] emailsSent = sentEmails.toArray(new String[sentEmails.size()]); + handleJobCompletion(eval, emailsSent, EvalConstants.JOB_TYPE_ACTIVE, from, sampleEmail); + + return emailsSent; } @@ -334,10 +327,8 @@ * @see org.sakaiproject.evaluation.logic.EvalEmailsLogic#sendEvalReminderNotifications(java.lang.Long, java.lang.String) */ public String[] sendEvalReminderNotifications(Long evaluationId, String includeConstant) { - log.debug("evaluationId: " + evaluationId + ", includeConstant: " + includeConstant); - - boolean updateReminderStatus = (Boolean) settings.get(EvalSettings.ENABLE_REMINDER_STATUS); - + if (log.isDebugEnabled()) log.debug("sendEvalReminderNotifications(evaluationId: " + evaluationId + ", includeConstant: " + includeConstant+")"); + EvalUtils.validateEmailIncludeConstant(includeConstant); EvalEvaluation eval = getEvaluationOrFail(evaluationId); @@ -350,18 +341,18 @@ Map> evalGroupIds = evaluationService.getEvalGroupsForEval(new Long[] { evaluationId }, false, null); // handle recovery of interrupted email sending + boolean updateReminderStatus = (Boolean) settings.get(EvalSettings.ENABLE_REMINDER_STATUS); EvalReminderStatus reminderStatus = eval.getCurrentReminderStatus(); - boolean reminderGroupFound = false; - if (reminderStatus != null) { + if (updateReminderStatus && reminderStatus != null) { log.info("Reminder recovery processing for eval ("+evaluationId+") will attempt to continue from: "+reminderStatus); } // only one possible map key so we can assume evaluationId List groups = evalGroupIds.get(evaluationId); - log.debug("Found " + groups.size() + " groups for available evaluation: " + evaluationId); + if (log.isDebugEnabled()) log.debug("Found " + groups.size() + " groups for available evaluation: " + evaluationId); + String sampleEmail = null; List sentEmails = new ArrayList(); - int emailsSentCt=0; // loop through groups and send emails to correct users in each for (int i = 0; i < groups.size(); i++) { EvalGroup group = (EvalGroup) groups.get(i); @@ -375,15 +366,12 @@ // skip courses until we reach the one that we stopped on before when email was interrupted if (reminderStatus != null) { if (reminderStatus.currentEvalGroupId.equals(evalGroupId)) { - reminderGroupFound = true; - log.info("Reminder processing for eval ("+evaluationId+"), found last processed group ("+evalGroupId+") at position "+(i+1)+" of "+groups.size()); - } - if (reminderGroupFound) { reminderStatus = null; + log.info("Reminder recovery processing for eval ("+evaluationId+"), found last processed group ("+evalGroupId+") at position "+(i+1)+" of "+groups.size()); } // skip this group if (log.isDebugEnabled()) { - log.debug("Reminder status ("+reminderStatus+") for eval ("+evaluationId+"), skipping group "+evalGroupId); + log.debug("Reminder recovery processing for eval ("+evaluationId+"), reminder status ("+reminderStatus+"), skipping group "+evalGroupId); } continue; } @@ -405,17 +393,19 @@ // turn the set into an array String[] toUserIds = (String[]) userIdsSet.toArray(new String[] {}); if (log.isDebugEnabled()) { - log.debug("Found " + toUserIds.length + " users (" + ArrayUtils.arrayToString(toUserIds) + ") to send " - + EvalConstants.EMAIL_TEMPLATE_REMINDER + " notification to for available evaluation (" - + evaluationId + ") and group (" + group.evalGroupId + ")"); + log.debug("Found " + toUserIds.length + " users (" + ArrayUtils.arrayToString(toUserIds) + ") of type " + + includeConstant+" to send " + EvalConstants.EMAIL_TEMPLATE_REMINDER + + " notification to for available evaluation ("+ evaluationId + ") and group (" + group.evalGroupId + ")"); } EvalEmailMessage em = makeEmailMessage(emailTemplate.getMessage(), emailTemplate.getSubject(), eval, group, includeConstant); + if (sampleEmail == null && em.message != null) { + sampleEmail = em.message; + } // send the actual emails for this evalGroupId String[] emailAddresses = sendUsersEmails(from, toUserIds, em.subject, em.message); log.info("Sent evaluation reminder message for eval ("+evaluationId+") and group ("+group.evalGroupId+") to " + emailAddresses.length + " users (attempted to send to "+toUserIds.length+")"); - emailsSentCt++; // store sent emails to return for (int j = 0; j < emailAddresses.length; j++) { sentEmails.add(emailAddresses[j]); @@ -423,28 +413,26 @@ } // update the reminder status if (updateReminderStatus) { + if (log.isDebugEnabled()) log.debug("Reminder recovery processing for eval ("+evaluationId+"), update to group ("+evalGroupId+"), at "+(i+1)+" / "+groups.size()); evaluationService.updateEvaluationReminderStatus(evaluationId, new EvalReminderStatus(groups.size(), i+1, evalGroupId)); } } // set reminder status back to idle if (updateReminderStatus) { + if (log.isDebugEnabled()) log.debug("Reminder recovery processing for eval ("+evaluationId+"), cleared status"); evaluationService.updateEvaluationReminderStatus(evaluationId, null); } commonLogic.registerEntityEvent(EVENT_EMAIL_REMINDER, eval); + if (sampleEmail == null && emailTemplate != null) { + sampleEmail = emailTemplate.getMessage(); + } + String[] emailsSent = sentEmails.toArray(new String[sentEmails.size()]); // send email to helpdeskEmail that reminders are finished. - boolean sendJobCompletion = (Boolean) settings.get(EvalSettings.ENABLE_JOB_COMPLETION_EMAIL); - if (sendJobCompletion) { - Map replacementValues = new HashMap(); - replacementValues.put("HelpdeskEmail", from); - replacementValues.put("EvalTitle", eval.getTitle()); - Integer iEmailsSentCt = Integer.valueOf(emailsSentCt); - replacementValues.put("NumEmailsSent", iEmailsSentCt.toString()); - replacementValues.put("JobType", EvalConstants.JOB_TYPE_REMINDER.substring(9)); - sendEmailJobCompleted(eval.getId(), replacementValues); - } + handleJobCompletion(eval, emailsSent, EvalConstants.JOB_TYPE_REMINDER, from, sampleEmail); - return (String[]) sentEmails.toArray(new String[] {}); + if (log.isDebugEnabled()) log.debug("Reminder processing complete for eval ("+evaluationId+"), sent emails to: "+sentEmails); + return emailsSent; } @@ -486,8 +474,8 @@ List assignGroups = evalAssignGroups.get(evaluationId); if (log.isDebugEnabled()) log.debug("Found " + assignGroups.size() + " assign groups for available evaluation: " + evaluationId); + String sampleEmail = null; List sentEmails = new ArrayList(); - int emailsSentCt=0; // loop through groups and send emails to correct users in each evalGroupId for (int i = 0; i < assignGroups.size(); i++) { EvalAssignGroup evalAssignGroup = assignGroups.get(i); @@ -542,11 +530,13 @@ + evaluationId + ") and group (" + evalGroupId + ")"); EvalEmailMessage em = makeEmailMessage(emailTemplate.getMessage(), emailTemplate.getSubject(), eval, group); + if (sampleEmail == null && em.message != null) { + sampleEmail = em.message; + } // send the actual emails for this evalGroupId String[] emailAddresses = sendUsersEmails(from, toUserIds, em.subject, em.message); log.info("Sent evaluation results message to " + emailAddresses.length + " users (attempted to send to "+toUserIds.length+")"); - emailsSentCt++; // store sent emails to return for (int j = 0; j < emailAddresses.length; j++) { sentEmails.add(emailAddresses[j]); @@ -554,20 +544,101 @@ commonLogic.registerEntityEvent(EVENT_EMAIL_RESULTS, eval); } } - + + if (sampleEmail == null && emailTemplate != null) { + sampleEmail = emailTemplate.getMessage(); + } + String[] emailsSent = sentEmails.toArray(new String[sentEmails.size()]); // send email to admin that reminders are finished. + handleJobCompletion(eval, emailsSent, jobType, from, sampleEmail); + + return emailsSent; + } + + + /** + * Special method to handle the job completion notifications + * EVALSYS-916 Send email to the helpdesk user notifying that the job is completed + * + * @param eval the eval + * @param emailsSent email addresses sent to + * @param jobType type of job + * @param from [OPTIONAL] from address + * @param sampleEmail [OPTIONAL] a sample of the email that was sent + */ + protected void handleJobCompletion(EvalEvaluation eval, String[] emailsSent, String jobType, String from, String sampleEmail) { + // send email to admin that reminders are finished. boolean sendJobCompletion = (Boolean) settings.get(EvalSettings.ENABLE_JOB_COMPLETION_EMAIL); if (sendJobCompletion) { - Map replacementValues = new HashMap(); + if (eval == null) { + log.error("Cannot send job completion email"); + return; + } + if (jobType == null) { + jobType = EvalConstants.JOB_TYPE_ACTIVE; + } + if (jobType.length() > 9) { + jobType = jobType.substring(9); // trim off "scheduled" from beginning + } + if (from == null) { + from = getFromEmailOrFail(eval); + } + if (emailsSent == null) { + emailsSent = new String[0]; + } + if (sampleEmail == null) { + sampleEmail = "NO SAMPLE AVAILABLE"; + } + int emailsSentCt = emailsSent.length; + StringBuilder sb = new StringBuilder(); + for (String email : emailsSent) { + sb.append(" - "); + sb.append(email); + sb.append("\n"); + } + String emailsSentList = sb.toString(); + + log.info("Evals Job Completed: sent "+emailsSentCt+" "+jobType+" emails from "+from+" for eval: "+eval.getTitle()+" ("+eval.getId()+"): emails: "+emailsSentList); + + Map replacementValues = new HashMap(); replacementValues.put("HelpdeskEmail", from); - replacementValues.put("EvalTitle", eval.getTitle()); - Integer iEmailsSentCt = Integer.valueOf(emailsSentCt); - replacementValues.put("NumEmailsSent", iEmailsSentCt.toString()); - replacementValues.put("JobType", jobType.substring(9)); - sendEmailJobCompleted(eval.getId(), replacementValues); + replacementValues.put("EvalTitle", eval.getTitle()); + replacementValues.put("NumEmailsSent", String.valueOf(emailsSentCt)); + replacementValues.put("EmailsSentList", emailsSentList); + replacementValues.put("JobType", jobType); + replacementValues.put("SampleEmail", sampleEmail); + + /* @param replacementValues a map of values to be included in this email: + * HelpdeskEmail: the email to send this to + * EvalTitle: the title of the evaluation + * NumEmailsSent: the number of emails sent + * EmailsSent: the email addresses sent to + * JobType: the email job that just completed + * SampleEmail: a sample of the sent email + */ + try { + EvalEmailTemplate emailTemplate = getEmailTemplateOrFail(EvalConstants.EMAIL_TEMPLATE_JOB_COMPLETED, eval.getId()); + if (replacementValues.get("HelpdeskEmail") != null) { + String[] to = {replacementValues.get("HelpdeskEmail")}; + //String subject = "Email Job for evaluation " + evalTitle + " has completed"; + String subject = TextTemplateLogicUtils.processTextTemplate(emailTemplate.getSubject(), replacementValues); + //String message = "The " + jobType.substring(9) + " email job has completed. " + numEmailsSent + " emails were sent."; + String message = TextTemplateLogicUtils.processTextTemplate(emailTemplate.getMessage(), replacementValues); + String deliveryOption = (String) settings.get(EvalSettings.EMAIL_DELIVERY_OPTION); + String[] emails = commonLogic.sendEmailsToAddresses(replacementValues.get("HelpdeskEmail"), to, subject, message, true, deliveryOption); + if (log.isDebugEnabled()) { + log.debug("SENT TO: " + ArrayUtils.arrayToString(emails)); + log.debug("TO: " + ArrayUtils.arrayToString(to)); + log.debug("SUBJECT: " + subject); + log.debug("MESSAGE: " + message); + } + } else { + log.error("No HelpdeskEmail value set, job completed email NOT sent"); + } + } catch ( Exception e) { + log.error("Exception in sendEmailJobCompleted, email NOT sent: " + e); + } } - - return (String[]) sentEmails.toArray(new String[] {}); } /* (non-Javadoc) @@ -676,7 +747,7 @@ replacementValues.put("EvalDueDate", dueDate); String viewDate = null; if (eval.getViewDate() != null) { - viewDate = df.format(eval.getDueDate()); + viewDate = df.format(eval.getViewDate()); } else { viewDate = dueDate; } @@ -695,7 +766,7 @@ replacementValues.put("HelpdeskEmail", getFromEmailOrFail(eval)); // setup the opt-in, opt-out, and add questions variables - int addItems = ((Integer) settings.get(EvalSettings.ADMIN_ADD_ITEMS_NUMBER)).intValue(); + int addItems = ((Integer) settings.get(EvalSettings.INSTRUCTOR_ADD_ITEMS_NUMBER)).intValue(); if (! eval.getInstructorOpt().equals(EvalConstants.INSTRUCTOR_REQUIRED) || (addItems > 0)) { if (eval.getInstructorOpt().equals(EvalConstants.INSTRUCTOR_OPT_IN)) { // if eval is opt-in notify instructors that they may opt in @@ -984,9 +1055,9 @@ /** * INTERNAL METHOD
- * @param jobId TODO + * @param jobId * @param userMap - * @param jobStatusReporter TODO + * @param jobStatusReporter * @return */ protected List processConsolidatedEmails(String jobId, List> userMap, JobStatusReporter jobStatusReporter) { @@ -1066,40 +1137,7 @@ } return recipients; } - - /** - * EVALSYS-916 Send email to the helpdesk user notifying that the job is completed. - * - * @param evaluationId unique id of an eval from the email address this email appears to come from - * @param replacementValues a map of values to be included in this email: - * HelpdeskEmail: the email to send this to - * EvalTitle: the title of the evaluation - * NumEmailsSent: the number of emails sent - * JobType: the email job that just completed - */ - public void sendEmailJobCompleted(Long evaluationId, Map replacementValues) { - try { - EvalEmailTemplate emailTemplate = getEmailTemplateOrFail(EvalConstants.EMAIL_TEMPLATE_JOB_COMPLETED, evaluationId); - if (replacementValues.get("HelpdeskEmail") != null) { - String[] to = {replacementValues.get("HelpdeskEmail")}; - //String subject = "Email Job for evaluation " + evalTitle + " has completed"; - String subject = TextTemplateLogicUtils.processTextTemplate(emailTemplate.getSubject(), replacementValues); - //String message = "The " + jobType.substring(9) + " email job has completed. " + numEmailsSent + " emails were sent."; - String message = TextTemplateLogicUtils.processTextTemplate(emailTemplate.getMessage(), replacementValues); - String deliveryOption = (String) settings.get(EvalSettings.EMAIL_DELIVERY_OPTION); - String[] emails = commonLogic.sendEmailsToAddresses(replacementValues.get("HelpdeskEmail"), to, subject, message, true, deliveryOption); - log.debug("TO: " + to[0]); - log.debug("SUBJECT: " + subject); - log.debug("MESSAGE: " + message); - } else { - log.error("No HelpdeskEmail value set, job completed email NOT sent"); - } - } catch ( Exception e) { - log.error("Exception in sendEmailJobCompleted, email NOT sent: " + e); - } - - } /** * INTERNAL METHOD
@@ -1116,9 +1154,9 @@ * @return an array of email addresses that this message was sent to */ public String[] sendUsersEmails(String from, String[] toUserIds, String subject, String message) { - String[] emails; String deliveryOption = (String) settings.get(EvalSettings.EMAIL_DELIVERY_OPTION); - emails = commonLogic.sendEmailsToUsers(from, toUserIds, subject, message, true, deliveryOption); + if (log.isDebugEnabled()) log.debug("sendUsersEmails(from:"+from+", to:"+ArrayUtils.arrayToString(toUserIds)+", subj:"+subject); + String[] emails = commonLogic.sendEmailsToUsers(from, toUserIds, subject, message, true, deliveryOption); return emails; } /** @@ -1215,32 +1253,27 @@ * (non-Javadoc) * @see org.sakaiproject.evaluation.logic.EvalEmailsLogic#sendEvalSubmissionConfirmationEmail(java.lang.Long) */ - public String sendEvalSubmissionConfirmationEmail(String userId, Long evaluationId) { - String to = null; - Boolean sendConfirmation = (Boolean) settings.get(EvalSettings.ENABLE_SUBMISSION_CONFIRMATION_EMAIL); - - if(sendConfirmation.booleanValue()) { - EvalEmailTemplate template = null; - Map replacementValues = new HashMap(); - - EvalEvaluation eval = getEvaluationOrFail(evaluationId); - String evalTitle = eval.getTitle(); - String from = getFromEmailOrFail(eval); - //get the template - template = getEmailTemplateOrFail(EvalConstants.EMAIL_TEMPLATE_SUBMITTED, evaluationId); - if(template != null) { - //make email and do the variable substitutions - EvalEmailMessage em = makeEmailMessage(template.getMessage(), template.getSubject(), eval, null); + public String sendEvalSubmissionConfirmationEmail(String userId, Long evaluationId) { + String to = null; + Boolean sendConfirmation = (Boolean) settings.get(EvalSettings.ENABLE_SUBMISSION_CONFIRMATION_EMAIL); - // send the actual email for this user - String[] emailAddresses = sendUsersEmails(from, new String[]{userId}, em.subject, em.message); - if(emailAddresses.length > 0){ + if (sendConfirmation.booleanValue()) { + EvalEvaluation eval = getEvaluationOrFail(evaluationId); + String from = getFromEmailOrFail(eval); + //get the template + EvalEmailTemplate emailTemplate = getEmailTemplateOrFail(EvalConstants.EMAIL_TEMPLATE_SUBMITTED, evaluationId); + if (emailTemplate != null) { + //make email and do the variable substitutions + EvalEmailMessage em = makeEmailMessage(emailTemplate.getMessage(), emailTemplate.getSubject(), eval, null); + // send the actual email for this user + String[] emailAddresses = sendUsersEmails(from, new String[]{userId}, em.subject, em.message); + if (emailAddresses.length > 0){ log.info("Sent Submission Confirmation email to " + userId + ". (attempted to send to "+emailAddresses.length+")"); commonLogic.registerEntityEvent(EVENT_EMAIL_SUBMISSION, EvalEvaluation.class, eval.getId().toString()); - } - } - } - return to; - } + } + } + } + return to; + } } Index: impl/src/java/org/sakaiproject/evaluation/logic/EvalEvaluationServiceImpl.java =================================================================== --- impl/src/java/org/sakaiproject/evaluation/logic/EvalEvaluationServiceImpl.java (revision 81089) +++ impl/src/java/org/sakaiproject/evaluation/logic/EvalEvaluationServiceImpl.java (working copy) @@ -506,6 +506,7 @@ } else if ( EvalConstants.EVALUATION_AUTHCONTROL_KEY.equals(eval.getAuthControl()) ) { // if this uses a key then only the key matters // TODO add key check + log.info("Evaluation key (" + eval.getAuthControl() + ") is not a valid evaluation authcontrol key"); allowed = false; } else if ( EvalConstants.EVALUATION_AUTHCONTROL_AUTH_REQ.equals(eval.getAuthControl()) ) { if (commonLogic.isUserAdmin(userId) ) { @@ -529,6 +530,7 @@ // ok if at least one group is approved and in the set of groups this user can take evals in for this eval id allowed = true; } else { + log.info("User (" + userId + ") is not in a valid group for evaluation (" + evaluationId + ")"); allowed = false; } } @@ -550,7 +552,7 @@ // cannot modify responses // check if the user already took this evaluation for this group EvalResponse response = getResponseForUserAndGroup(evaluationId, userId, evalGroupId); - if (response != null) { + if (response != null && response.complete && response.isSubmitted()) { // user already has a response saved for this evaluation and evalGroupId log.info("User (" + userId + ") cannot take evaluation (" + evaluationId + ") again in this group (" + evalGroupId @@ -1096,6 +1098,7 @@ private void fixupEvaluation(EvalEvaluation evaluation) { if (evaluation != null) { // add in any needed checks or change storage that is needed here + evaluation.useDateTimes = (Boolean) settings.get(EvalSettings.EVAL_USE_DATE_TIME); } } Index: impl/src/java/org/sakaiproject/evaluation/logic/EvalEvaluationSetupServiceImpl.java =================================================================== --- impl/src/java/org/sakaiproject/evaluation/logic/EvalEvaluationSetupServiceImpl.java (revision 81089) +++ impl/src/java/org/sakaiproject/evaluation/logic/EvalEvaluationSetupServiceImpl.java (working copy) @@ -265,6 +265,7 @@ EvalBeanUtils.validateEvalDates(evaluation); boolean isNew = false; + boolean isClosed = false; if (evaluation.getId() == null) { isNew = true; // assure that all the defaults are set correctly for new evals @@ -275,10 +276,14 @@ // if (evalCheck == null) { // isNew = true; // } + if (EvalUtils.checkStateAfter(evaluation.getState(), EvalConstants.EVALUATION_STATE_CLOSED, true)) { + // check if we are or have closed the evaluation (or some state after that) + isClosed = true; + } } // assure valid date handling but only after the dates are checked during saving - evalBeanUtils.fixupEvaluationDates(evaluation); + evalBeanUtils.fixupEvaluationDates(evaluation, isClosed); // now perform checks depending on whether this is new or existing Calendar calendar = GregorianCalendar.getInstance(); @@ -433,7 +438,7 @@ // save the eval dao.save(evaluation); - log.info("User ("+userId+") saved evaluation ("+evaluation.getId()+"), title: " + evaluation.getTitle()); + log.info("User ("+userId+") saved evaluation ("+evaluation.getId()+"), state="+evaluation.getState()+", title: " + evaluation.getTitle()); // initialize the scheduling for the eval jobs (only if state is not partial) if ( EvalUtils.checkStateAfter(evalState, EvalConstants.EVALUATION_STATE_PARTIAL, false) ) { @@ -608,7 +613,7 @@ cal.setTime( new Date() ); cal.add(Calendar.SECOND, -1); Date now = cal.getTime(); - evaluation.setDueDate(now); + evaluation.forceDueDate(now); // fix stop and view dates if needed evaluation.setStopDate(null); @@ -721,25 +726,108 @@ return evals; } - /* (non-Javadoc) - * @see org.sakaiproject.evaluation.logic.EvalEvaluationSetupService#getEvaluationsForEvaluatee(java.lang.String) - */ - public List getEvaluationsForEvaluatee(String userId) { + /* (non-Javadoc) + * @see org.sakaiproject.evaluation.logic.EvalEvaluationSetupService#getEvaluationsForEvaluatee(java.lang.String, java.lang.Boolean) + */ + public List getEvaluationsForEvaluatee(String userId, Boolean includeRecentlyClosed) { if (userId == null) { throw new IllegalArgumentException("userId must be set"); } + // TODO Shouldn't this actually get the list of groups based on the set of assigned eval groups? List evalGroups = commonLogic.getEvalGroupsForUser(userId, EvalConstants.PERM_BE_EVALUATED); String[] evalGroupIds = new String[evalGroups.size()]; int i = 0; - for(EvalGroup evalGroup : evalGroups) { - evalGroupIds[i++] = evalGroup.evalGroupId; + for (EvalGroup evalGroup : evalGroups) { + evalGroupIds[i++] = evalGroup.evalGroupId; } List evals = dao.getEvaluationsByEvalGroups(evalGroupIds, null, null, null, 0, 0); + // date calculations for recently closed + Date today = new Date(); + Integer recentlyClosedDays = (Integer) settings.get(EvalSettings.EVAL_EVALUATEE_RECENTLY_CLOSED_DAYS); + int recentlyClosedHours = recentlyClosedDays.intValue() * 24; + + for (Iterator iterator = evals.iterator(); iterator.hasNext();) { + EvalEvaluation evaluation = iterator.next(); + // fix up the states to ensure they are good + evaluationService.returnAndFixEvalState(evaluation, true); + // handle filtering + if (includeRecentlyClosed != null) { + // not null so filter (NOTE: if null then just include them all) + if (includeRecentlyClosed) { + // filter out evals older than recently closed + int hoursDiff = EvalUtils.getHoursDifference(evaluation.getDueDate(), today); + if (hoursDiff > recentlyClosedHours) { + if (log.isDebugEnabled()) log.debug("Dropping Evaluatee eval which is not recently closed: "+evaluation.getId()+", due="+evaluation.getDueDate()); + iterator.remove(); + } + } else { + // filter out all closed evals + if (EvalUtils.checkStateAfter(evaluation.getState(), EvalConstants.EVALUATION_STATE_CLOSED, true)) { + if (log.isDebugEnabled()) log.debug("Dropping Evaluatee eval which is closed: "+evaluation.getId()); + iterator.remove(); + } + } + } + } + // populate the assign groups and eval groups in the evals + populateEvaluationsGroups(evals, evalGroups); return evals; - } + } + /** + * Special method to populate the assign groups and eval groups non-persistent fields in the evaluation objects + * + * @param evaluations the list of evaluations to populate the groups in (does nothing if this is empty) + * @param limitEvalGroups if null, populate all assigned groups, + * if empty, populate no assigned groups, + * otherwise, populate only the groups which are assigned and also in this list + */ + protected void populateEvaluationsGroups(List evaluations, List limitEvalGroups) { + if (!evaluations.isEmpty()) { + Long[] evaluationIds = new Long[evaluations.size()]; + int j = 0; + for (EvalEvaluation eval : evaluations) { + evaluationIds[j++] = eval.getId(); + } + Map> agsMap = evaluationService.getAssignGroupsForEvals(evaluationIds, true, null); + // now populate the evaluations with the AGs and EGs (or set them to empty lists) + for (EvalEvaluation eval : evaluations) { + List assignGroups = agsMap.get(eval.getId()); + if (assignGroups != null && !assignGroups.isEmpty()) { + if (limitEvalGroups == null) { + // include all + eval.setEvalAssignGroups(assignGroups); + // does not populate the eval groups + } else if (limitEvalGroups.isEmpty()) { + // include none + eval.setEvalAssignGroups(new ArrayList(0)); + eval.setEvalGroups(new ArrayList(0)); + } else { + // include the groups passed in only + List evaluationAssignGroups = new ArrayList(); + List evaluationGroups = new ArrayList(); + for (EvalGroup eg : limitEvalGroups) { + for (EvalAssignGroup eag : assignGroups) { + if (eag.getEvalGroupId().equals(eg.evalGroupId)) { + evaluationAssignGroups.add(eag); + evaluationGroups.add(eg); + break; + } + } + } + eval.setEvalAssignGroups(evaluationAssignGroups); + eval.setEvalGroups(evaluationGroups); + } + } else { + eval.setEvalAssignGroups(new ArrayList(0)); + eval.setEvalGroups(new ArrayList(0)); + } + } + } + } + /** * Method which retrieves the groupIds for all groups in which this user has * an assignment of type evaluator @@ -1014,23 +1102,27 @@ if (assignUserToRemove.isEmpty() && assignUserToSave.isEmpty()) { message += ": no changes to the user assignments ("+assignedUsers.size()+")"; } else { + if (removeAllowed + && ! assignUserToRemove.isEmpty()) { + Long[] assignUserToRemoveArray = assignUserToRemove.toArray(new Long[assignUserToRemove.size()]); + if (log.isDebugEnabled()) log.debug("Deleting user eval assignment Ids: "+assignUserToRemove); + dao.deleteSet(EvalAssignUser.class, assignUserToRemoveArray); + message += ": removed the following assignments: " + assignUserToRemove; + changedUserAssignments.addAll( assignUserToRemove ); + } if (! assignUserToSave.isEmpty()) { for (EvalAssignUser evalAssignUser : assignUserToSave) { setAssignUserDefaults(evalAssignUser, evaluation, currentUserId); } + // this is meant to force the assigned users set to be re-calculated + assignUserToSave = new HashSet(assignUserToSave); + if (log.isDebugEnabled()) log.debug("Saving user eval assignments: "+assignUserToSave); dao.saveSet(assignUserToSave); message += ": created the following assignments: " + assignUserToSave; for (EvalAssignUser evalAssignUser : assignUserToSave) { changedUserAssignments.add( evalAssignUser.getId() ); } } - if (removeAllowed - && ! assignUserToRemove.isEmpty()) { - Long[] assignUserToRemoveArray = assignUserToRemove.toArray(new Long[assignUserToRemove.size()]); - dao.deleteSet(EvalAssignUser.class, assignUserToRemoveArray); - message += ": removed the following assignments: " + assignUserToRemove; - changedUserAssignments.addAll( assignUserToRemove ); - } } // one more specialty check to cleanup orphaned user assignments - EVALSYS-703 Index: impl/src/java/org/sakaiproject/evaluation/logic/externals/EvalExternalLogicImpl.java =================================================================== --- impl/src/java/org/sakaiproject/evaluation/logic/externals/EvalExternalLogicImpl.java (revision 81089) +++ impl/src/java/org/sakaiproject/evaluation/logic/externals/EvalExternalLogicImpl.java (working copy) @@ -114,6 +114,7 @@ private static final String SAKAI_SITE_TYPE = SiteService.SITE_SUBTYPE; private static final String SAKAI_GROUP_TYPE = SiteService.GROUP_SUBTYPE; + private static final String SAKAI_SITE_TYPE_FULL = SiteService.APPLICATION_ID; private static final String ANON_USER_ATTRIBUTE = "AnonUserAttribute"; private static final String ANON_USER_PREFIX = "Anon_User_"; @@ -968,9 +969,9 @@ * @return a CONTEXT_TYPE constant from {@link EvalConstants} */ protected String getContextType(String sakaiType) { - if (sakaiType.equals(SAKAI_SITE_TYPE)) { + if (SAKAI_SITE_TYPE.equals(sakaiType) || SAKAI_SITE_TYPE_FULL.equals(sakaiType)) { return EvalConstants.GROUP_TYPE_SITE; - } else if (sakaiType.equals(SAKAI_GROUP_TYPE)) { + } else if (SAKAI_GROUP_TYPE.equals(sakaiType)) { return EvalConstants.GROUP_TYPE_GROUP; } return EvalConstants.GROUP_TYPE_UNKNOWN; Index: impl/src/java/org/sakaiproject/evaluation/logic/scheduling/EvalJobLogicImpl.java =================================================================== --- impl/src/java/org/sakaiproject/evaluation/logic/scheduling/EvalJobLogicImpl.java (revision 81089) +++ impl/src/java/org/sakaiproject/evaluation/logic/scheduling/EvalJobLogicImpl.java (working copy) @@ -139,6 +139,7 @@ log.info("Could not find evaluation ("+evaluationId+") for jobAction ("+jobType+"), " + "purging out all jobs related to this evaluation..."); removeScheduledInvocations(evaluationId); + return; } // fix up EvalEvaluation state (also persists it) @@ -147,6 +148,9 @@ Boolean useConsolidatedNotifications = (Boolean) this.settings.get(EvalSettings.ENABLE_SINGLE_EMAIL_PER_STUDENT); + // EVALSYS-1236 + // send out the evaluation available e-mail, even if useConsolidatedNotification is true + boolean forceSendAvailableNotification = (Boolean) this.settings.get(EvalSettings.CONSOLIDATED_FORCE_SEND_AVAILABLE_NOTIFICATION); // dispatch to send email and/or schedule jobs based on jobType but if // consolidated emails are enabled, no scheduled emails are not enabled if (EvalConstants.JOB_TYPE_CREATED.equals(jobType)) { @@ -156,7 +160,7 @@ } else if (EvalConstants.JOB_TYPE_ACTIVE.equals(jobType)) { // Consider flag wrt sending a mass email notifying users of opening. Send mail if flag is not set. boolean sendMail = ( eval.getSendAvailableNotifications() == null ? true : eval.getSendAvailableNotifications() ) - && ! useConsolidatedNotifications; + && (! useConsolidatedNotifications || forceSendAvailableNotification); if (sendMail){ sendAvailableEmail(evaluationId); } @@ -267,11 +271,16 @@ throw new IllegalStateException("Cannot process new evaluation that is in partial state, state must be after partial"); } + // EVALSYS-1236 + // send the instructors a created e-mail, even if they are not allowed to edit it, because instAddItemNum is 0 + // and instructorOpt is "Required" (which it is hard-coded at this point to be "Required") + boolean forceSendCreatedNotification = (Boolean) this.settings.get(EvalSettings.CONSOLIDATED_FORCE_SEND_CREATED_EMAIL); // send created email if instructor can add questions or opt-in or opt-out Integer instAddItemsNum = (Integer) settings.get(EvalSettings.INSTRUCTOR_ADD_ITEMS_NUMBER); if (instAddItemsNum == null) instAddItemsNum = 0; if ( instAddItemsNum > 0 || - !eval.getInstructorOpt().equals(EvalConstants.INSTRUCTOR_REQUIRED)) { + !eval.getInstructorOpt().equals(EvalConstants.INSTRUCTOR_REQUIRED) || + forceSendCreatedNotification) { // http://bugs.sakaiproject.org/jira/browse/EVALSYS-507 int timeToWaitSecs = 300; Integer ttws = (Integer) settings.get(EvalSettings.EVALUATION_TIME_TO_WAIT_SECS); @@ -327,7 +336,7 @@ } Boolean syncGroupAssignments = (Boolean) this.settings.get(EvalSettings.SYNC_USER_ASSIGNMENTS_ON_STATE_CHANGE); - if(syncGroupAssignments == null) { + if (syncGroupAssignments == null) { // use default value, false syncGroupAssignments = new Boolean(false); } @@ -338,6 +347,8 @@ } else if (EvalConstants.EVALUATION_STATE_DELETED.equals(eval.getState())) { // remove all remaining events for this eval removeScheduledInvocations(eval.getId()); + // do not sync assignments if new state is deleted + syncGroupAssignments = false; } else if (EvalConstants.EVALUATION_STATE_INQUEUE.equals(eval.getState())) { // make sure scheduleActive job invocation date matches EvalEvaluation start date @@ -387,9 +398,13 @@ } // do not sync assignments if new state is closed syncGroupAssignments = false; + + } else if (EvalConstants.EVALUATION_STATE_VIEWABLE.equals(eval.getState())) { + // do not sync assignments if new state is viewable + syncGroupAssignments = false; } - if(syncGroupAssignments) { + if (syncGroupAssignments) { this.evaluationSetupService.synchronizeUserAssignments(eval.getId(), null); } } @@ -668,6 +683,10 @@ log.info("Scheduling a reminder ("+new Date(reminderTime)+") for 24h before the end ("+new Date(dueTime)+") of the evaluation ("+eval.getTitle()+") ["+eval.getId()+"]"); } } + } else if (reminderDays == -2) { + // NOTE: special case for testing + reminderTime = System.currentTimeMillis() + (1000l * 60l * 5l); // reminders every 5 minutes + log.warn("REMINDERS TESTING ONLY (-2): Scheduling a reminder in the near future ("+new Date(reminderTime)+") for testing: due date ("+new Date(dueTime)+") of the evaluation ("+eval.getTitle()+") ["+eval.getId()+"]"); } return reminderTime; } @@ -693,8 +712,7 @@ /** * Send email that an evaluation has been created
* - * @param evalId - * the EvalEvaluation id + * @param evalId the EvalEvaluation id */ protected void sendCreatedEmail(Long evalId) { boolean includeOwner = true; @@ -706,23 +724,29 @@ /** * Send a reminder that an evaluation is available to those who have not responded * - * @param evalId - * the EvalEvaluation id + * @param evalId the EvalEvaluation id */ protected void sendReminderEmail(Long evaluationId) { EvalEvaluation eval = getEvaluationOrFail(evaluationId); if (eval.getState().equals(EvalConstants.EVALUATION_STATE_ACTIVE) && eval.getReminderDaysInt() != 0) { - String includeConstant = EvalConstants.EVAL_INCLUDE_NONTAKERS; - String[] sentMessages = emails.sendEvalReminderNotifications(evaluationId, includeConstant); - if (log.isDebugEnabled()) - log.debug("EvalJobLogicImpl.sendReminderEmail(" + evaluationId + ")" + " sentMessages: " + ArrayUtils.arrayToString(sentMessages)); - String[] sentMessagesInProgress = emails.sendEvalReminderNotifications(evaluationId, EvalConstants.EVAL_INCLUDE_IN_PROGRESS); + String[] sentMessages = emails.sendEvalReminderNotifications(evaluationId, EvalConstants.EVAL_INCLUDE_NONTAKERS); if (log.isDebugEnabled()) { - log.debug("EvalJobLogicImpl.sendReminderEmail(" + evaluationId + ")" + " sentMessagesInProgress: " + ArrayUtils.arrayToString(sentMessagesInProgress)); + log.debug("sendReminderEmail(" + evaluationId + ")" + " sentMessages: " + ArrayUtils.arrayToString(sentMessages)); + } + boolean saveWithoutSubmit = (Boolean) settings.get(EvalSettings.STUDENT_SAVE_WITHOUT_SUBMIT); + if (saveWithoutSubmit) { + String[] sentMessagesInProgress = emails.sendEvalReminderNotifications(evaluationId, EvalConstants.EVAL_INCLUDE_IN_PROGRESS); + if (log.isDebugEnabled()) { + log.debug("sendReminderEmail(" + evaluationId + ")" + " sentMessagesInProgress: " + ArrayUtils.arrayToString(sentMessagesInProgress)); + } + } else { + log.debug("sendReminderEmail(" + evaluationId + "), No in progress reminders sent (saveWithoutSubmit is disabled)"); + } + } else { + log.debug("sendReminderEmail(" + evaluationId + "), no reminder sent (state="+eval.getState()+", reminderDays="+eval.getReminderDaysInt()+")"); } } - } /** * Send email that the results of an evaluation may be viewed now.
Notification may be sent Index: impl/src/java/org/sakaiproject/evaluation/logic/scheduling/GroupMembershipSyncImpl.java =================================================================== --- impl/src/java/org/sakaiproject/evaluation/logic/scheduling/GroupMembershipSyncImpl.java (revision 81089) +++ impl/src/java/org/sakaiproject/evaluation/logic/scheduling/GroupMembershipSyncImpl.java (working copy) @@ -82,10 +82,7 @@ for(String state : stateList) { List evals = evaluationService.getEvaluationsByState(state); - int count = 0; - if(evals != null) { - count = evals.size(); - } + int count = evals.size(); if(logger.isInfoEnabled()) { StringBuilder buf1 = new StringBuilder(); buf1.append("GroupMembershipSync.execute() syncing "); Index: impl/src/java/org/sakaiproject/evaluation/logic/EvalAuthoringServiceImpl.java =================================================================== --- impl/src/java/org/sakaiproject/evaluation/logic/EvalAuthoringServiceImpl.java (revision 81089) +++ impl/src/java/org/sakaiproject/evaluation/logic/EvalAuthoringServiceImpl.java (working copy) @@ -2150,8 +2150,13 @@ } - + /* (non-Javadoc) + * @see org.sakaiproject.evaluation.logic.EvalAuthoringService#saveTemplateItemOrder(java.util.Map, java.lang.String) + */ public void saveTemplateItemOrder(Map orderingMap, String currentUserId) { + /* TODO - warning! this method does not even check to see if these template items are in the same template + * This is very dangerous and was written poorly by the original author, this should be rewritten + */ Iterator> selector = orderingMap.entrySet().iterator(); while ( selector.hasNext() ) { Map.Entry pairs = selector.next(); @@ -2165,4 +2170,5 @@ } } + } Index: impl/src/java/org/sakaiproject/evaluation/logic/entity/TemplateItemEntityProviderImpl.java =================================================================== --- impl/src/java/org/sakaiproject/evaluation/logic/entity/TemplateItemEntityProviderImpl.java (revision 81089) +++ impl/src/java/org/sakaiproject/evaluation/logic/entity/TemplateItemEntityProviderImpl.java (working copy) @@ -133,27 +133,30 @@ } return id; } - - //Custom action to handle /eval-templateitem/template-items-reorder - @EntityCustomAction(action=CUSTOM_TEMPLATE_ITEMS_REORDER,viewKey=EntityView.VIEW_NEW) - public void saveTemplateItemsOrdering(EntityView view, Map params) { - Object ids = params.get(key_ordered_Ids); - String currentUserId = commonLogic.getCurrentUserId(); - Map orderedMap = new HashMap(); - - if ( ids != null ){ - String orderedChildIds = ids.toString(); - List orderedChildIdList = Arrays.asList(orderedChildIds.split(",")); - for( String itemId : orderedChildIdList ){ - int itemPosition = orderedChildIdList.indexOf( itemId ) + 1; - orderedMap.put( Long.parseLong(itemId), itemPosition); - } - authoringService.saveTemplateItemOrder(orderedMap, currentUserId); - }else{ - throw new IllegalArgumentException("No ordered Ids to process."); - } - } + //Custom action to handle /eval-templateitem/template-items-reorder + @EntityCustomAction(action = CUSTOM_TEMPLATE_ITEMS_REORDER, viewKey = EntityView.VIEW_NEW) + public void saveTemplateItemsOrdering(EntityView view, Map params) { + Object ids = params.get(key_ordered_Ids); + if (ids != null && !"".equals(ids)) { + String orderedChildIds = ids.toString().trim(); + if (!"".equals(orderedChildIds)) { + String currentUserId = commonLogic.getCurrentUserId(); + Map orderedMap = new HashMap(); + List orderedChildIdList = Arrays.asList(orderedChildIds.split(",")); + for (String itemId : orderedChildIdList) { + int itemPosition = orderedChildIdList.indexOf(itemId) + 1; + orderedMap.put(Long.parseLong(itemId), itemPosition); + } + authoringService.saveTemplateItemOrder(orderedMap, currentUserId); + } else { + throw new IllegalArgumentException("No ordered Ids to process (string had only whitespace)."); + } + } else { + throw new IllegalArgumentException("No ordered Ids to process (blank or null)."); + } + } + //Custom method to handle /eval-templateitem/modify-block-items @EntityCustomAction(action=CUSTOM_TEMPLATE_ITEMS_BLOCK,viewKey=EntityView.VIEW_NEW) public void modifyBlockItems(EntityView view, Map params) { Index: api/src/java/org/sakaiproject/evaluation/model/EvalResponse.java =================================================================== --- api/src/java/org/sakaiproject/evaluation/model/EvalResponse.java (revision 81089) +++ api/src/java/org/sakaiproject/evaluation/model/EvalResponse.java (working copy) @@ -73,6 +73,16 @@ */ public boolean complete = false; + /** + * This variable is used to keep track of whether the response has been submitted or only saved. + * There are two configurations at work here. + * EvalSettings.STUDENT_MODIFY_RESPONSES - determines if the user can submit multiple times + * EvalSettings.STUDENT_SAVE_WITHOUT_SUBMIT - determines if the user can save without submitting + *
Once an evaluation is submitted, it will be included in the metrics reporting. In the + * scenario where the user cannot modify responses but can save without submitting, this variable + * will keep track of whether the evaluation has been submitted yet. + */ + private transient boolean submitted = true; // Constructors /** default constructor */ @@ -205,6 +215,34 @@ public Date getEndTime() { return endTime; } + + /** + * isSubmitted() returns whether the response has been submitted or only saved. + * There are two configurations at work here. + * EvalSettings.STUDENT_MODIFY_RESPONSES - determines if the user can submit multiple times + * EvalSettings.STUDENT_SAVE_WITHOUT_SUBMIT - determines if the user can save without submitting + *
Once an evaluation is submitted, it will be included in the metrics reporting. In the + * scenario where the user cannot modify responses but can save without submitting, this variable + * will keep track of whether the evaluation has been submitted yet. + * @returns true if this response has been submitted before or false if only saved. + */ + public boolean isSubmitted() { + return this.submitted; + } + + /** + * isSubmitted() returns whether the response has been submitted or only saved. + * There are two configurations at work here. + * EvalSettings.STUDENT_MODIFY_RESPONSES - determines if the user can submit multiple times + * EvalSettings.STUDENT_SAVE_WITHOUT_SUBMIT - determines if the user can save without submitting + *
Once an evaluation is submitted, it will be included in the metrics reporting. In the + * scenario where the user cannot modify responses but can save without submitting, this variable + * will keep track of whether the evaluation has been submitted yet. + * @param submitted whether this response has been submitted before or only saved + */ + public void isSubmitted(boolean submitted) { + this.submitted = submitted; + } public void setEndTime(Date endTime) { if (endTime == null) { Index: api/src/java/org/sakaiproject/evaluation/model/EvalEvaluation.java =================================================================== --- api/src/java/org/sakaiproject/evaluation/model/EvalEvaluation.java (revision 81089) +++ api/src/java/org/sakaiproject/evaluation/model/EvalEvaluation.java (working copy) @@ -22,6 +22,7 @@ import org.sakaiproject.evaluation.constant.EvalConstants; import org.sakaiproject.evaluation.logic.EvalEvaluationService; +import org.sakaiproject.evaluation.logic.model.EvalGroup; import org.sakaiproject.evaluation.logic.model.EvalReminderStatus; import org.sakaiproject.evaluation.utils.EvalUtils; @@ -94,7 +95,7 @@ * {@link #instructorsDate} to be nulled out out when the evaluation is saved if set to false */ private boolean instructorViewResults; - + private Boolean instructorViewAllResults; /** @@ -195,7 +196,7 @@ * if true then responses may be changed during active eval period */ private Boolean modifyResponsesAllowed; - + /** * if true then all roles will be included in the list of evaluators */ @@ -204,19 +205,19 @@ private Boolean unregisteredAllowed; private Boolean availableEmailSent = new Boolean(false); - + private Boolean locked; private String authControl; private String evalCategory; - + /** * A flag to toggle sending mass email on evaluation active state */ private Boolean sendAvailableNotifications; - /** + /** * If this is not null then we will load in all templates/templateItems/items with the related * linking autoUseTag when the evaluation is created */ @@ -264,28 +265,95 @@ * This is ignored if it is null
*/ public Boolean useViewDate; - - /** - * Optional field never used by EVALSYS code. May be used to mark records for bulk actions. - * For example, an import operation might set a value that will be persisted and can be used - * later to select records for export, deletion, etc. Maximum length is 80 characters. - */ - public String localSelector; + /** + * Non-persistent field:
+ * If this is set to false then the evaluation only uses the DATE portion of Date objects, + * if true then the DATE and TIME portions are used
+ * NOTE: This is ignored if it is null
+ */ + public Boolean useDateTimes; /** - * This is an optional listing of eval groups for this evaluation, + * Optional field never used by EVALSYS code. May be used to mark records for bulk actions. + * For example, an import operation might set a value that will be persisted and can be used + * later to select records for export, deletion, etc. Maximum length is 80 characters. + */ + public String localSelector; + + /** + * This is an optional listing of assigned eval groups for this evaluation, * if this is non-null and has been set then the groups contained are relevant to service method used * to retrieve the evaluations, typically this would include the groups assigned to this eval which * are accessible to the current user */ protected List evalAssignGroups; + /** + * This is an optional listing of eval groups for this evaluation, + * if this is non-null and has been set then the groups contained are relevant to service method used + * to retrieve the evaluations, typically this would include the groups assigned to this eval which + * are accessible to the current user + */ + protected List evalGroups; + // Constructors /** default constructor */ public EvalEvaluation() { } + /** COPY constructor - this MUST be updated if fields are added to this object **/ + public EvalEvaluation(EvalEvaluation eval) { + // construct evaluation from another one + this.id = eval.id; + this.eid = eval.eid; + this.lastModified = copy(eval.lastModified); + this.type = eval.type; + this.owner = eval.owner; + this.title = eval.title; + this.instructions = eval.instructions; + this.startDate = copy(eval.startDate); + this.dueDate = copy(eval.dueDate); + this.stopDate = copy(eval.stopDate); + this.viewDate = copy(eval.viewDate); + this.studentViewResults = eval.studentViewResults; + this.instructorViewResults = eval.instructorViewResults; + this.instructorViewAllResults = eval.instructorViewAllResults; + this.selectionSettings = eval.selectionSettings; + this.studentsDate = copy(eval.studentsDate); + this.instructorsDate = copy(eval.instructorsDate); + this.state = eval.state; + this.instructorOpt = eval.instructorOpt; + this.reminderDays = eval.reminderDays; + this.reminderFromEmail = eval.reminderFromEmail; + this.reminderStatus = eval.reminderStatus; + this.termId = eval.termId; + this.availableEmailTemplate = eval.availableEmailTemplate; + this.reminderEmailTemplate = eval.reminderEmailTemplate; + this.template = eval.template; + this.responses = eval.responses; + this.resultsSharing = eval.resultsSharing; + this.blankResponsesAllowed = eval.blankResponsesAllowed; + this.modifyResponsesAllowed = eval.modifyResponsesAllowed; + this.allRolesParticipate = eval.allRolesParticipate; + this.unregisteredAllowed = eval.unregisteredAllowed; + this.availableEmailSent = eval.availableEmailSent; + this.locked = eval.locked; + this.authControl = eval.authControl; + this.evalCategory = eval.evalCategory; + this.sendAvailableNotifications = eval.sendAvailableNotifications; + this.autoUseTag = eval.autoUseTag; + this.autoUseInsertion = eval.autoUseInsertion; + // NON_PERSISTENT + this.customStartDate = eval.customStartDate; + this.useDueDate = eval.useDueDate; + this.useStopDate = eval.useStopDate; + this.useViewDate = eval.useViewDate; + this.localSelector = eval.localSelector; + this.evalAssignGroups = eval.evalAssignGroups; + this.evalGroups = eval.evalGroups; + } + /** * minimal constructor */ @@ -302,7 +370,7 @@ Integer reminderDays, EvalTemplate template) { this(type, owner, title, null, startDate, dueDate, stopDate, viewDate, false, null, true, null, state, resultsSharing, null, reminderDays, null, null, null, null, template, null, null, null, null, Boolean.FALSE, null, null, null); } - + public EvalEvaluation(String type, String owner, String title, String instructions, Date startDate, Date dueDate, Date stopDate, Date viewDate, boolean studentViewResults, Date studentsDate, boolean instructorViewResults, Date instructorsDate, String state, @@ -312,13 +380,13 @@ Set responses, Boolean blankResponsesAllowed, Boolean modifyResponsesAllowed, Boolean unregisteredAllowed, Boolean locked, String authControl, String evalCategory, String selectionSettings) { - - this(type, owner, title, instructions, startDate, dueDate, stopDate, viewDate, studentViewResults, studentsDate, instructorViewResults, Boolean.TRUE, instructorsDate, state, + + this(type, owner, title, instructions, startDate, dueDate, stopDate, viewDate, studentViewResults, studentsDate, instructorViewResults, Boolean.TRUE, instructorsDate, state, resultsSharing, instructorOpt, reminderDays, reminderFromEmail, termId, availableEmailTemplate, reminderEmailTemplate, template, responses, blankResponsesAllowed, modifyResponsesAllowed, unregisteredAllowed, locked, authControl, evalCategory, selectionSettings, Boolean.TRUE); } - + /** * full constructor without email flag */ @@ -331,13 +399,13 @@ Set responses, Boolean blankResponsesAllowed, Boolean modifyResponsesAllowed, Boolean unregisteredAllowed, Boolean locked, String authControl, String evalCategory, String selectionSettings) { - - this(type, owner, title, instructions, startDate, dueDate, stopDate, viewDate, studentViewResults, studentsDate, instructorViewResults, instructorViewAllResults, instructorsDate, state, + + this(type, owner, title, instructions, startDate, dueDate, stopDate, viewDate, studentViewResults, studentsDate, instructorViewResults, instructorViewAllResults, instructorsDate, state, resultsSharing, instructorOpt, reminderDays, reminderFromEmail, termId, availableEmailTemplate, reminderEmailTemplate, template, responses, blankResponsesAllowed, modifyResponsesAllowed, unregisteredAllowed, locked, authControl, evalCategory, selectionSettings, Boolean.TRUE); } - + /** * full constructor without all rolls can participate */ @@ -350,13 +418,13 @@ Set responses, Boolean blankResponsesAllowed, Boolean modifyResponsesAllowed, Boolean unregisteredAllowed, Boolean locked, String authControl, String evalCategory, String selectionSettings, Boolean emailOpenNotification){ - - this(type, owner, title, instructions, startDate, dueDate, stopDate, viewDate, studentViewResults, studentsDate, instructorViewResults, instructorViewAllResults, instructorsDate, state, + + this(type, owner, title, instructions, startDate, dueDate, stopDate, viewDate, studentViewResults, studentsDate, instructorViewResults, instructorViewAllResults, instructorsDate, state, resultsSharing, instructorOpt, reminderDays, reminderFromEmail, termId, availableEmailTemplate, reminderEmailTemplate, template, responses, blankResponsesAllowed, modifyResponsesAllowed, unregisteredAllowed, Boolean.FALSE ,locked, authControl, evalCategory, selectionSettings, Boolean.TRUE); } - + /** * full constructor */ @@ -369,7 +437,7 @@ Set responses, Boolean blankResponsesAllowed, Boolean modifyResponsesAllowed, Boolean unregisteredAllowed, Boolean allRolesParticipate, Boolean locked, String authControl, String evalCategory, String selectionSettings, Boolean emailOpenNotification) { - + this.lastModified = new Date(); this.type = type; this.owner = owner; @@ -402,13 +470,28 @@ this.authControl = authControl; this.evalCategory = evalCategory; this.selectionSettings = selectionSettings; - this.sendAvailableNotifications = emailOpenNotification; + this.sendAvailableNotifications = emailOpenNotification; } + /** + * @return a copy of this object + */ + public EvalEvaluation copy() { + return new EvalEvaluation(this); + } + + private Date copy(Date d) { + Date copy = null; + if (d != null) { + copy = new Date(d.getTime()); + } + return copy; + } + @Override public String toString() { return "eval: [" + this.type + "] " + this.title + " (" + this.id + ") state=" + this.state - + " ,start=" + this.startDate + ", due=" + this.dueDate; + + " ,start=" + this.startDate + ", due=" + this.dueDate; }; @@ -561,17 +644,17 @@ this.authControl = authControl; } - public Boolean getAvailableEmailSent() { - return availableEmailSent; - } - + public Boolean getAvailableEmailSent() { + return availableEmailSent; + } + public EvalEmailTemplate getAvailableEmailTemplate() { return availableEmailTemplate; } - public void setAvailableEmailSent(Boolean availableEmailSent) { - this.availableEmailSent = availableEmailSent; - } + public void setAvailableEmailSent(Boolean availableEmailSent) { + this.availableEmailSent = availableEmailSent; + } public void setAvailableEmailTemplate(EvalEmailTemplate availableEmailTemplate) { this.availableEmailTemplate = availableEmailTemplate; @@ -585,14 +668,6 @@ this.blankResponsesAllowed = blankResponsesAllowed; } - public Date getDueDate() { - return dueDate; - } - - public void setDueDate(Date dueDate) { - this.dueDate = dueDate; - } - public String getEvalCategory() { return evalCategory; } @@ -664,14 +739,14 @@ public void setModifyResponsesAllowed(Boolean modifyResponsesAllowed) { this.modifyResponsesAllowed = modifyResponsesAllowed; } - + public Boolean getAllRolesParticipate() { - return allRolesParticipate; - } - + return allRolesParticipate; + } + public void setAllRolesParticipate(Boolean allRolesParticipate) { - this.allRolesParticipate = allRolesParticipate; - } + this.allRolesParticipate = allRolesParticipate; + } public String getOwner() { return owner; @@ -730,6 +805,14 @@ this.responses = responses; } + public String getState() { + return state; + } + + public void setState(String state) { + this.state = state; + } + public Date getStartDate() { return startDate; } @@ -738,22 +821,46 @@ this.startDate = startDate; } - public String getState() { - return state; + public Date getDueDate() { + return dueDate; } - public void setState(String state) { - this.state = state; + public void forceDueDate(Date dueDate) { + this.dueDate = dueDate; } + public void setDueDate(Date dueDate) { + if (dueDate != null && !EvalUtils.safeBool(this.useDateTimes, true)) { + // force the date to the end of the day when times use is disabled + dueDate = EvalUtils.getEndOfDayDate(dueDate); + } + this.dueDate = dueDate; + } + public Date getStopDate() { return stopDate; } + public void forceStopDate(Date stopDate) { + this.stopDate = stopDate; + } + public void setStopDate(Date stopDate) { + if (stopDate != null && !EvalUtils.safeBool(this.useDateTimes, true)) { + // force the date to the end of the day when times use is disabled + stopDate = EvalUtils.getEndOfDayDate(stopDate); + } this.stopDate = stopDate; } + public Date getViewDate() { + return viewDate; + } + + public void setViewDate(Date viewDate) { + this.viewDate = viewDate; + } + public Date getStudentsDate() { return studentsDate; } @@ -794,14 +901,6 @@ this.unregisteredAllowed = unregisteredAllowed; } - public Date getViewDate() { - return viewDate; - } - - public void setViewDate(Date viewDate) { - this.viewDate = viewDate; - } - public String getType() { return type; } @@ -849,7 +948,7 @@ public void setInstructorViewResults(boolean instructorViewResults) { this.instructorViewResults = instructorViewResults; } - + public Boolean getInstructorViewAllResults() { return instructorViewAllResults; } @@ -857,7 +956,7 @@ public void setInstructorViewAllResults(Boolean instructorViewAllResults) { this.instructorViewAllResults = instructorViewAllResults; } - + public String getSelectionSettings() { return selectionSettings; } @@ -878,11 +977,23 @@ public void setEvalAssignGroups(List evalAssignGroups) { this.evalAssignGroups = evalAssignGroups; } - + + /** + * NON_PERSISTENT list of assign groups for this eval, may be limited by user + * @return the evalAssignGroups, will be NULL if the groups were not populated, will be empty if populated but none are set + */ + public List getEvalGroups() { + return evalGroups; + } + + public void setEvalGroups(List evalGroups) { + this.evalGroups = evalGroups; + } + public Boolean getSendAvailableNotifications() { return sendAvailableNotifications; } - + public void setSendAvailableNotifications(Boolean sendAvailableNotifications) { this.sendAvailableNotifications = sendAvailableNotifications; } @@ -901,13 +1012,13 @@ public String getLocalSelector() { return localSelector; } - + /** * @param localSelector the localSelector to set */ public void setLocalSelector(String localSelector) { this.localSelector = localSelector; - } - + } + } Index: api/src/java/org/sakaiproject/evaluation/model/EvalAssignUser.java =================================================================== --- api/src/java/org/sakaiproject/evaluation/model/EvalAssignUser.java (revision 81089) +++ api/src/java/org/sakaiproject/evaluation/model/EvalAssignUser.java (working copy) @@ -152,18 +152,28 @@ public EvalAssignUser() { } + public EvalAssignUser(String userId, String evalGroupId) { + this(userId, evalGroupId, null, null, null); + } + /** * Minimal constructor, sets the type automatically to eval taker (student), * all records are created with a default status of active, * makes the current user the owner * * @param userId the user which is being assigned, should be the internal id (not the username) + * @param eval the evaluation this assignment is linked to * @param evalGroupId (OPTIONAL) the eval group this assignment is related to + * @param owner (OPTIONAL) will be assigned to the current user if not set */ - public EvalAssignUser(String userId, String evalGroupId) { - this(userId, evalGroupId, null, null, null); + public EvalAssignUser(String userId, EvalEvaluation eval, String evalGroupId, String owner) { + this(userId, evalGroupId, owner, null, null, eval, null); } + public EvalAssignUser(String userId, String evalGroupId, String owner, String type, String status) { + this(userId, evalGroupId, owner, type, status, null, null); + } + /** * Full constructor * @@ -172,8 +182,10 @@ * @param owner (OPTIONAL) will be assigned to the current user if not set * @param type (OPTIONAL) use a constant like {@link #TYPE_EVALUATEE} or {@value #TYPE_EVALUATOR} * @param status (OPTIONAL) use a constant {@link #STATUS_LINKED} or {@link #STATUS_REMOVED} + * @param eval the evaluation this assignment is linked to + * @param assignGroupId (OPTIONAL) the assigned group id */ - public EvalAssignUser(String userId, String evalGroupId, String owner, String type, String status) { + public EvalAssignUser(String userId, String evalGroupId, String owner, String type, String status, EvalEvaluation eval, Long assignGroupId) { super(); this.lastModified = new Date(); if (userId == null || "".equals(userId) ) { @@ -194,6 +206,8 @@ type = TYPE_EVALUATOR; } this.type = type; + this.evaluation = eval; + this.assignGroupId = assignGroupId; } public Long getId() { @@ -383,13 +397,9 @@ public int hashCode() { final int prime = 31; int result = 1; - if (id == null) { - result = prime * result + ((userId == null) ? 0 : userId.hashCode()); - result = prime * result + ((evalGroupId == null) ? 0 : evalGroupId.hashCode()); - result = prime * result + ((type == null) ? 0 : type.hashCode()); - } else { - result = prime * result + id.hashCode(); - } + result = prime * result + ((evalGroupId == null) ? 0 : evalGroupId.hashCode()); + result = prime * result + ((type == null) ? 0 : type.hashCode()); + result = prime * result + ((userId == null) ? 0 : userId.hashCode()); return result; } @@ -402,17 +412,21 @@ if (getClass() != obj.getClass()) return false; EvalAssignUser other = (EvalAssignUser) obj; - if (id == null) { - if ( userId.equals(other.userId) - && type.equals(other.type) - && (evalGroupId == null ? other.evalGroupId == null : evalGroupId.equals(other.evalGroupId)) ) { + if (evalGroupId == null) { + if (other.evalGroupId != null) return false; - } - } else { - if (!id.equals(other.id)) { + } else if (!evalGroupId.equals(other.evalGroupId)) + return false; + if (type == null) { + if (other.type != null) return false; - } - } + } else if (!type.equals(other.type)) + return false; + if (userId == null) { + if (other.userId != null) + return false; + } else if (!userId.equals(other.userId)) + return false; return true; } Index: api/src/java/org/sakaiproject/evaluation/utils/TemplateItemDataList.java =================================================================== --- api/src/java/org/sakaiproject/evaluation/utils/TemplateItemDataList.java (revision 81089) +++ api/src/java/org/sakaiproject/evaluation/utils/TemplateItemDataList.java (working copy) @@ -854,6 +854,14 @@ } return answer; } + + @Override + public String toString() { + return "DTI[key=" + key + ", ti=" + templateItem.getId() + + ", aType=" + associateType + ", aId=" + associateId + ", node=" + (node != null ? node.id : null) + + ", blParId=" + blockParentId + "]"; + } + } /** Index: api/src/java/org/sakaiproject/evaluation/utils/EvalUtils.java =================================================================== --- api/src/java/org/sakaiproject/evaluation/utils/EvalUtils.java (revision 81089) +++ api/src/java/org/sakaiproject/evaluation/utils/EvalUtils.java (working copy) @@ -300,7 +300,7 @@ /** * Set the time portion to the end of the day instead (23:59), this is to avoid confusion for users - * when setting the evaluationSetupService to end on a certain date and having them end in the first minute of the day instead of + * when setting the evaluation to end on a certain date and having them end in the first minute of the day instead of * at the end of the day * Note: This may lead to a nasty bug if anyone ever attempts to explicitly set the time for the stop and due dates * @@ -313,7 +313,9 @@ cal.set(Calendar.HOUR_OF_DAY, 23); cal.set(Calendar.MINUTE, 59); cal.set(Calendar.SECOND, 59); - log.info("Setting a date to the end of the day from " + d + " to " + cal.getTime()); + if (!cal.getTime().equals(d)) { + log.info("Setting a date to the end of the day from " + d + " to " + cal.getTime()); + } return cal.getTime(); } @@ -615,6 +617,30 @@ /** + * Shuffle the evals which are closed (or later) to the end of the list and otherwise maintain the current order of evaluations + * @param evaluations collection of evals + * @return list of evals in original order except closed evals at the end + */ + public static List sortClosedEvalsToEnd(Collection evaluations) { + List l; + if (evaluations == null || evaluations.isEmpty()) { + l = new ArrayList(0); + } else { + l = new ArrayList(evaluations.size()); + ArrayList closedEvals = new ArrayList(evaluations.size()); + for (EvalEvaluation eval : evaluations) { + if (EvalUtils.checkStateBefore(eval.getState(), EvalConstants.EVALUATION_STATE_CLOSED, false)) { + l.add(eval); + } else { + closedEvals.add(eval); + } + } + l.addAll(closedEvals); + } + return l; + } + + /** * Takes 2 lists of group types, {@link EvalGroup} and {@link EvalAssignGroup}, and * merges the groups in common and then returns an array of the common groups, * comparison is on the evalGroupId @@ -683,6 +709,42 @@ } /** + * Converts a collection of evals into a set of ids, + * simple convenience method to avoid writing the same code over and over + * + * @param evaluations a collection of evals + * @return the list of eval ids + */ + public static List getEvalIdsFromEvaluations(Collection evaluations) { + List l = new ArrayList(); + if (evaluations != null) { + for (EvalEvaluation eval : evaluations) { + if (eval.getId() != null) { + l.add(eval.getId()); + } + } + } + return l; + } + + /** + * Converts a collection of evalGroups into a set of ids, + * simple convenience method to avoid writing the same code over and over + * + * @param groups a collection of evalGroupss + * @return the list of evalGroup Ids + */ + public static List getGroupIdsFromGroups(Collection groups) { + List l = new ArrayList(); + if (groups != null) { + for (EvalGroup evalGroup : groups) { + l.add(evalGroup.evalGroupId); + } + } + return l; + } + + /** * Creates eval groups from groupIds * * @param evalGroupIds a collection of evalGroupId (unique ids for eval groups) Index: api/src/java/org/sakaiproject/evaluation/utils/ComparatorsUtils.java =================================================================== --- api/src/java/org/sakaiproject/evaluation/utils/ComparatorsUtils.java (revision 81089) +++ api/src/java/org/sakaiproject/evaluation/utils/ComparatorsUtils.java (working copy) @@ -30,8 +30,27 @@ public class ComparatorsUtils { /** - * static class to sort {@link EvalEvaluation} by due date, then by title, then by id + * static class to sort {@link EvalEvaluation} by due date (most recent first), then by id */ + public static class EvaluationDueDateComparator implements Comparator, Serializable { + static private final long serialVersionUID = 31L; + public int compare(EvalEvaluation eval0, EvalEvaluation eval1) { + int comparison = 0; + if (eval0.getDueDate() != null && eval1.getDueDate() != null) { + comparison = eval0.getDueDate().compareTo(eval1.getDueDate()); + } else { + comparison = eval0.getStartDate().compareTo(eval1.getStartDate()); + } + if (comparison == 0) { + comparison = eval0.getId().compareTo(eval1.getId()); + } + return comparison; + } + } + + /** + * static class to sort {@link EvalEvaluation} by due date (most recent first), then by title, then by id + */ public static class EvaluationDateTitleIdComparator implements Comparator, Serializable { static private final long serialVersionUID = 31L; public int compare(EvalEvaluation eval0, EvalEvaluation eval1) { Index: api/src/java/org/sakaiproject/evaluation/beans/EvalBeanUtils.java =================================================================== --- api/src/java/org/sakaiproject/evaluation/beans/EvalBeanUtils.java (revision 81089) +++ api/src/java/org/sakaiproject/evaluation/beans/EvalBeanUtils.java (working copy) @@ -100,6 +100,108 @@ } /** + * Check if an instructor can view the results of a given evaluation + * (NOTE: this only checks is an evaluatee/instructor can view the results based on this evals settings, + * user permissions and response rates still need to be checked), + * probably should be using a method like this one: ReportingPermissions.canViewEvaluationResponses(), + * similar logic to {@link #getInstructorViewDateForEval(EvalEvaluation)} + * + * @param eval the evaluation + * @return true if results can be viewed, false otherwise + */ + public boolean checkInstructorViewResultsForEval(EvalEvaluation eval, String evalState) { + // now handle the results viewing flags (i.e. filter out evals the instructor should not see) + boolean instViewResultsEval = false; + if (eval != null) { + if (evalState == null || "".equals(evalState)) { + evalState = commonLogic.calculateViewability(eval.getState()); + } + if (EvalConstants.EVALUATION_STATE_DELETED.equals(eval.getState())) { + // skip this one + } else if (EvalUtils.checkStateAfter(evalState, EvalConstants.EVALUATION_STATE_INQUEUE, false)) { + // this eval is active or later and nothing before active is viewable + boolean evalViewable = false; + // check if this eval is forced to a viewable state + String forcedViewableState = commonLogic.calculateViewability(evalState); + if (EvalUtils.checkStateAfter(forcedViewableState, EvalConstants.EVALUATION_STATE_VIEWABLE, true)) { + // forced viewable + evalViewable = true; + } else { + // not forced so check if it is actually viewable + if (EvalUtils.checkStateAfter(evalState, EvalConstants.EVALUATION_STATE_VIEWABLE, true)) { + // check for viewable state evals + evalViewable = true; + } + } + if (evalViewable) { + // finally check if the instructor can actually view it + Boolean instViewResultsSetting = (Boolean) settings.get(EvalSettings.INSTRUCTOR_ALLOWED_VIEW_RESULTS); + // probably should be using a method like this one: ReportingPermissions.canViewEvaluationResponses() + if (instViewResultsSetting == null) { + instViewResultsEval = eval.getInstructorViewResults(); + } else { + instViewResultsEval = instViewResultsSetting.booleanValue(); + } + } + } + } + return instViewResultsEval; + } + + /** + * Find the date at which an instructor can view the report/results of an evaluation, + * similar logic to {@link #checkInstructorViewResultsForEval(EvalEvaluation, String)} + * + * @param eval an evaluation + * @return the date OR null if instructors cannot view the report + */ + public Date getInstructorViewDateForEval(EvalEvaluation eval) { + Date instViewDate = null; + if (eval != null) { + if (EvalConstants.EVALUATION_STATE_DELETED.equals(eval)) { + // skip this one + } else if (EvalUtils.checkStateAfter(eval.getState(), EvalConstants.EVALUATION_STATE_INQUEUE, false)) { + // this eval is active or later and nothing before active is viewable + boolean evalViewable = false; + // check if this eval is forced to a viewable state + String forcedViewableState = commonLogic.calculateViewability(eval.getState()); + if (EvalUtils.checkStateAfter(forcedViewableState, EvalConstants.EVALUATION_STATE_VIEWABLE, true)) { + // forced viewable + evalViewable = true; + instViewDate = eval.getStartDate(); + } else { + // not forced so check if it is actually viewable + if (EvalUtils.checkStateAfter(eval.getState(), EvalConstants.EVALUATION_STATE_VIEWABLE, true)) { + // check for viewable state evals + evalViewable = true; + instViewDate = eval.getSafeViewDate(); + } + } + if (evalViewable) { + // finally check if the instructor can actually view it + Boolean instViewResultsSetting = (Boolean) settings.get(EvalSettings.INSTRUCTOR_ALLOWED_VIEW_RESULTS); + if (instViewResultsSetting == null) { + evalViewable = eval.getInstructorViewResults(); + } else { + evalViewable = instViewResultsSetting.booleanValue(); + } + } + if (evalViewable) { + // see if there is a local override for the instructor view date + if (eval.getInstructorsDate() != null) { + instViewDate = eval.getInstructorsDate(); + } + } else { + // not viewable after all + instViewDate = null; + } + } + + } + return instViewDate; + } + + /** * Sets all the system defaults for this evaluation object * and ensures all required fields are correctly set, * use this whenever you create a new evaluation
@@ -312,8 +414,9 @@ * handles setting date fields based on the useDueDate, etc. fields in the evaluation as well
* * @param eval an {@link EvalEvaluation} object (can be persisted or new) + * @param ignoreMinTimeDiff if true, the minimum time difference is ignored, if false, it is enforced */ - public void fixupEvaluationDates(EvalEvaluation eval) { + public void fixupEvaluationDates(EvalEvaluation eval, boolean ignoreMinTimeDiff) { if (eval == null) { throw new IllegalArgumentException("eval must be set to fix dates"); } @@ -331,8 +434,6 @@ useViewDate = (Boolean) settings.get(EvalSettings.EVAL_USE_VIEW_DATE); } boolean useDateTime = ((Boolean) settings.get(EvalSettings.EVAL_USE_DATE_TIME)); - // Getting the system setting that tells what should be the minimum time difference between start date and due date. - int minHoursDifference = ((Integer) settings.get(EvalSettings.EVAL_MIN_TIME_DIFF_BETWEEN_START_DUE)).intValue(); Date now = new Date(); if (eval.getStartDate() == null) { @@ -390,6 +491,11 @@ } } + // Getting the system setting that tells what should be the minimum time difference between start date and due date. + int minHoursDifference = 0; + if (!ignoreMinTimeDiff) { + minHoursDifference = ((Integer) settings.get(EvalSettings.EVAL_MIN_TIME_DIFF_BETWEEN_START_DUE)).intValue(); + } // Ensure minimum time difference between start and due/stop dates in eval - check this after the dates are set if (eval.getDueDate() != null) { EvalUtils.updateDueStopDates(eval, minHoursDifference); @@ -498,19 +604,15 @@ * invalid for use in a URL). * * @param evalCategory the eval category entered by the user - * @return boolean indicating its validity */ public void validateEvalCategory(String evalCategory) { - try { - - if ((evalCategory != null) && (evalCategory.length() != 0)) + if ((evalCategory != null) && (evalCategory.length() != 0)) { commonLogic.getEntityURL(EvalCategoryEntityProvider.ENTITY_PREFIX, evalCategory); - + } } catch (IllegalArgumentException ex) { throw new InvalidEvalCategoryException(ex); } - } } Index: api/src/java/org/sakaiproject/evaluation/constant/EvalEmailConstants.java =================================================================== --- api/src/java/org/sakaiproject/evaluation/constant/EvalEmailConstants.java (revision 81089) +++ api/src/java/org/sakaiproject/evaluation/constant/EvalEmailConstants.java (working copy) @@ -311,18 +311,25 @@ /** * EmailTemplate subject: Default subject for email job completion notification */ - public static final String EMAIL_JOB_COMPLETED_DEFAULT_SUBJECT = "Email Job for Evaluation: ${EvalTitle} has completed\n"; + public static final String EMAIL_JOB_COMPLETED_DEFAULT_SUBJECT = "${JobType} Email Job for Evaluation: ${EvalTitle} has completed\n"; /** * EmailTemplate message setting: * This is the default template for when the single email per student option is in effect and an evaluation response is outstanding. * Replaceable strings:
+ * ${EvalTitle} - the related evaluation * ${JobType} - the ScheduledInvocationCommand jobType name for the eval email job. * ${NumEmailsSent} - the number of emails sent. + * ${EmailsSentList} - list of email addresses (separated by newlines) + * ${SampleEmail} - a sample of the email that was sent for this job */ public static final String EMAIL_JOB_COMPLETED_DEFAULT_TEXT = - "The ${JobType} email job has completed. \n\n" + - "${NumEmailsSent} emails were sent.\n"; + "The ${JobType} email job has completed for Evaluation: ${EvalTitle}. \n\n" + + "${NumEmailsSent} emails were sent. \n" + + "They were sent to the following users: \n" + + "${EmailsSentList}\n\n" + + "Sample email: \n" + + "${SampleEmail}"; /** * EmailTemplate subject: Default subject for submission confirmation @@ -345,7 +352,7 @@ "Note that all student responses are kept confidential." + "<#if ShowAllowEditResponsesText == \"true\">\n" + "You may edit your evaluation responses up until the close date for this evaluation.\n" + - "\n"; + "\n"; /** * Email text describing where a user should look for the evaluation tool. Index: api/src/java/org/sakaiproject/evaluation/logic/EvalEvaluationService.java =================================================================== --- api/src/java/org/sakaiproject/evaluation/logic/EvalEvaluationService.java (revision 81089) +++ api/src/java/org/sakaiproject/evaluation/logic/EvalEvaluationService.java (working copy) @@ -482,7 +482,7 @@ public List getResponses(String userId, Long[] evaluationIds, String[] evalGroupIds, Boolean completed); /** - * Count the number of responses for evaluationSetupService, + * Count the number of responses for evaluations, * can count responses for an entire evaluation regardless of eval group * or just responses for a specific group and/or user
* This is a good method for checking to see if a user has responded
@@ -613,8 +613,9 @@ */ public boolean canControlEmailTemplate(String userId, Long evaluationId, Long emailTemplateId); - // COUNT METHODS FROM UM + // COUNT METHODS FROM UM below here + /** * UM method * Access a count of the number of evaluations in which the search string appears in the title. @@ -671,14 +672,14 @@ * @param useReminderEmailSent Should be true if the reminderEmailSent date should be used in selecting records. * @param reminderEmailSent The date to use if querying by reminderEmailSent. * @param emailTemplateType The type of template (ConsolidatedAvailable or ConsolidateReminder) to find. - * @return + * @return count */ public int selectConsoliatedEmailRecipients(boolean useAvailableEmailSent, Date availableEmailSent, boolean useReminderEmailSent, Date reminderEmailSent, String emailTemplateType); /** * Reports the number of distinct eval groups for which mappings are currently in the email processing queue. - * @return + * @return count */ public int countDistinctGroupsInConsolidatedEmailMapping(); Index: api/src/java/org/sakaiproject/evaluation/logic/EvalSettings.java =================================================================== --- api/src/java/org/sakaiproject/evaluation/logic/EvalSettings.java (revision 81089) +++ api/src/java/org/sakaiproject/evaluation/logic/EvalSettings.java (working copy) @@ -49,7 +49,10 @@ * Note: If this is NULL then the evaluation settings override, otherwise this overrides the evaluation setting */ public static final String INSTRUCTOR_ALLOWED_VIEW_RESULTS = "INSTRUCTOR_ALLOWED_VIEW_RESULTS:java.lang.Boolean"; - + /** + * CONSTANT: Is the instructor allowed to view the results of all evaluations - {@link Boolean}, default True + * Note: If this is NULL then the evaluation settings override, otherwise this overrides the evaluation setting + */ public static final String INSTRUCTOR_ALLOWED_VIEW_ALL_RESULTS = "INSTRUCTOR_ALLOWED_VIEW_ALL_RESULTS:java.lang.Boolean"; /** @@ -65,6 +68,10 @@ * CONSTANT: How many items is the instructor allowed to add to an evaluation from above in the hierarchy - {@link Integer}, default 5 */ public static final String INSTRUCTOR_ADD_ITEMS_NUMBER = "INSTRUCTOR_ADD_ITEMS_NUMBER:java.lang.Integer"; + /** + * CONSTANT: Control whether instructor users have access to the list of responders for an evaluation - {@link Boolean}, default False + */ + public static final String INSTRUCTOR_ALLOWED_VIEW_RESPONDERS = "INSTRUCTOR_ALLOWED_VIEW_RESPONDERS:java.lang.Boolean"; /** * CONSTANT: Student is allowed to leave questions unanswered (this only affects multiple choice items) - {@link Boolean}, default True @@ -83,6 +90,11 @@ */ public static final String STUDENT_SAVE_WITHOUT_SUBMIT = "STUDENT_SAVE_WITHOUT_SUBMIT:java.lang.Boolean"; /** + * CONSTANT: Student is presented with a Cancel button when taking an assessment. If a Cancel button is pressed, + * no assessment data is saved, and the user is returned to the dashboard. + */ + public static final String STUDENT_CANCEL_ALLOWED = "STUDENT_CANCEL_ALLOWED:java.lang.Boolean"; + /** * CONSTANT: Student is allowed to view the results of the evaluation - {@link Boolean}, default False * Note: If this is NULL then the evaluation settings override, otherwise this overrides the evaluation setting */ @@ -123,7 +135,7 @@ */ public static final String ENABLE_ADMINISTRATING_BOX = "ENABLE_ADMINISTRATING_BOX:java.lang.Boolean"; /** - * CONSTANT: Is the box showing the Courses in Which I May Be Evaluated visible? - {@link Boolean}, default False + * CONSTANT: Is the box showing the Evals/Courses in Which I May Be Evaluated visible? - {@link Boolean}, default False */ public static final String ENABLE_EVALUATEE_BOX = "ENABLE_EVALUATEE_BOX:java.lang.Boolean"; /** @@ -173,6 +185,12 @@ */ public static final String EVAL_RECENTLY_CLOSED_DAYS = "EVAL_RECENTLY_CLOSED_DAYS:java.lang.Integer"; /** + * CONSTANT: How many days old can an eval be and still be recently closed (for the be evaluated box) - {@link Integer}, default 10
+ * It must be less than or equal to this many days old to count as recent + */ + public static final String EVAL_EVALUATEE_RECENTLY_CLOSED_DAYS = "EVAL_EVALUATEE_RECENTLY_CLOSED_DAYS:java.lang.Integer"; + + /** * CONSTANT: Allow users to set the stop date when creating evaluations - {@link Boolean}, default False
* Note: Stop date should default to null when it cannot be set */ @@ -374,6 +392,11 @@ public static final String ENABLE_INSTRUCTOR_ASSISTANT_SELECTION = "ENABLE_INSTRUCTOR_ASSISTANT_SELECTION:java.lang.Boolean"; /** + * Enable the check to filter out sites (groups) which are not published when selecting groups to assign. - {@link Boolean}, default False + */ + public static final String ENABLE_SITE_GROUP_PUBLISH_CHECK = "ENABLE_SITE_GROUP_PUBLISH_CHECK:java.lang.Boolean"; + + /** * If this is enabled/true then we only show evalgroups/sites like the current one in the Assign Eval to groups view */ public static final String ENABLE_FILTER_ASSIGNABLE_GROUPS = "ENABLE_FILTER_ASSIGNABLE_GROUPS:java.lang.Boolean"; @@ -415,6 +438,21 @@ */ public static final String CONSOLIDATED_EMAIL_NOTIFY_AVAILABLE = "CONSOLIDATED_EMAIL_NOTIFY_AVAILABLE:java.lang.Boolean"; + /** + * EVALSYS-1236 + * If this is true, send a created e-mail, even if the instructor cannot + * modify the evaluation. Only applies if the email settings are set to + * Consolidated emails + */ + public static final String CONSOLIDATED_FORCE_SEND_CREATED_EMAIL = "CONSOLIDATED_FORCE_SEND_CREATED_EMAIL:java.lang.Boolean"; + + /** + * EVALSYS-1236 + * If this is true, send an evaluation available e-mail. Only applies if + * the email settings are set to Consolidated emails. + */ + public static final String CONSOLIDATED_FORCE_SEND_AVAILABLE_NOTIFICATION = "CONSOLIDATED_FORCE_SEND_AVAILABLE_NOTIFICATION:java.lang.Boolean"; + /** * If true, memberships in EvalAssignGroup will be synchronized with the group provider when a new EvalAssignGroup is saved. Default is true. */ @@ -457,58 +495,64 @@ ADMIN_VIEW_INSTRUCTOR_ADDED_RESULTS, ALLOW_EVALSPECIFIC_TOGGLE_EMAIL_NOTIFICATION, CONSOLIDATED_EMAIL_NOTIFY_AVAILABLE, + CONSOLIDATED_FORCE_SEND_CREATED_EMAIL, + CONSOLIDATED_FORCE_SEND_AVAILABLE_NOTIFICATION, DISABLE_ITEM_BANK, DISABLE_QUESTION_BLOCKS, DISPLAY_HIERARCHY_HEADERS, DISPLAY_HIERARCHY_OPTIONS, + ENABLE_ADMINISTRATING_BOX, ENABLE_ADHOC_GROUPS, ENABLE_ADHOC_USERS, + ENABLE_ASSISTANT_CATEGORY, ENABLE_CSV_REPORT_EXPORT, ENABLE_EVAL_CATEGORIES, ENABLE_EVAL_TERM_IDS, ENABLE_EVAL_EARLY_CLOSE, ENABLE_EVAL_REOPEN, ENABLE_EVAL_RESPONSE_REMOVAL, + ENABLE_EVALUATEE_BOX, ENABLE_FILTER_ASSIGNABLE_GROUPS, + ENABLE_GROUP_SPECIFIC_PREVIEW, ENABLE_IMPORTING, - ENABLE_PROVIDER_SYNC, ENABLE_INSTRUCTOR_ASSISTANT_SELECTION, ENABLE_ITEM_COMMENTS, + ENABLE_JOB_COMPLETION_EMAIL, ENABLE_LIST_OF_TAKERS_EXPORT, + ENABLE_SAKAI_ADMIN_ACCESS, + ENABLE_MY_TOPLINKS, ENABLE_NOT_AVAILABLE, ENABLE_PDF_REPORT_BANNER, ENABLE_PDF_REPORT_EXPORT, + ENABLE_PROVIDER_SYNC, + ENABLE_REMINDER_STATUS, ENABLE_SINGLE_EMAIL_PER_STUDENT, + ENABLE_SITE_GROUP_PUBLISH_CHECK, ENABLE_SUBMISSION_CONFIRMATION_EMAIL, ENABLE_SUMMARY_SITES_BOX, - ENABLE_ASSISTANT_CATEGORY, - ENABLE_ADMINISTRATING_BOX, - ENABLE_EVALUATEE_BOX, - ENABLE_MY_TOPLINKS, + ENABLE_TEMPLATE_COPYING, ENABLE_XLS_REPORT_EXPORT, - ENABLE_TEMPLATE_COPYING, - ENABLE_GROUP_SPECIFIC_PREVIEW, EVAL_USE_DATE_TIME, EVAL_USE_SAME_VIEW_DATES, EVAL_USE_STOP_DATE, EVAL_USE_VIEW_DATE, INSTRUCTOR_ALLOWED_EMAIL_STUDENTS, + INSTRUCTOR_ALLOWED_VIEW_RESPONDERS, INSTRUCTOR_ALLOWED_CREATE_EVALUATIONS, ITEM_USE_RESULTS_SHARING, ITEM_USE_COURSE_CATEGORY_ONLY, LOG_EMAIL_RECIPIENTS, REQUIRE_COMMENTS_BLOCK, - USE_ADMIN_AS_FROM_EMAIL, - USE_EXPERT_ITEMS, - USE_EXPERT_TEMPLATES, - VIEW_SURVEY_RESULTS_IGNORE_DATES, - ENABLE_JOB_COMPLETION_EMAIL, - ENABLE_REMINDER_STATUS, + STUDENT_SAVE_WITHOUT_SUBMIT, + STUDENT_CANCEL_ALLOWED, SYNC_USER_ASSIGNMENTS_ON_GROUP_SAVE, SYNC_USER_ASSIGNMENTS_ON_GROUP_UPDATE, SYNC_USER_ASSIGNMENTS_ON_STATE_CHANGE, SYNC_UNASSIGNED_GROUPS_ON_STARTUP, - ENABLE_SAKAI_ADMIN_ACCESS + USE_ADMIN_AS_FROM_EMAIL, + USE_EXPERT_ITEMS, + USE_EXPERT_TEMPLATES, + VIEW_SURVEY_RESULTS_IGNORE_DATES }; /** @@ -517,13 +561,12 @@ * all booleans should be indicated in either this or {@link #BOOLEAN_SETTINGS} */ public static String[] TERNARY_BOOLEAN_SETTINGS = { + ALLOW_ALL_SITE_ROLES_TO_RESPOND, INSTRUCTOR_ALLOWED_VIEW_RESULTS, INSTRUCTOR_ALLOWED_VIEW_ALL_RESULTS, STUDENT_ALLOWED_LEAVE_UNANSWERED, STUDENT_MODIFY_RESPONSES, - STUDENT_SAVE_WITHOUT_SUBMIT, - STUDENT_ALLOWED_VIEW_RESULTS, - ALLOW_ALL_SITE_ROLES_TO_RESPOND + STUDENT_ALLOWED_VIEW_RESULTS }; /** Index: api/src/java/org/sakaiproject/evaluation/logic/EvalCommonLogic.java =================================================================== --- api/src/java/org/sakaiproject/evaluation/logic/EvalCommonLogic.java (revision 81089) +++ api/src/java/org/sakaiproject/evaluation/logic/EvalCommonLogic.java (working copy) @@ -28,6 +28,7 @@ import org.sakaiproject.evaluation.model.EvalAdhocGroup; import org.sakaiproject.evaluation.model.EvalAdhocUser; import org.sakaiproject.evaluation.model.EvalAdmin; +import org.sakaiproject.evaluation.providers.EvalGroupsProvider; /** @@ -211,6 +212,16 @@ public EvalAdmin getEvalAdmin(String userId); /** + * calculateViewability() takes a state and determines if the state + * should be viewable, based on system settings + *

EvalSettings.VIEW_SURVEY_RESULTS_IGNORE, if set, will promote some + * states to EvalConstants.EVALUATION_STATE_VIEWABLE + * @param state one of the states listed in EvalConstants, such as EVALUATION_STATE_ACTIVE + * @return the original state or EVALUATION_STATE_VIEWABLE if the view can be promoted + */ + public String calculateViewability(String state); + + /** * Assigns a user as an eval admin. * * @param userId internal user id (not username) @@ -232,5 +243,18 @@ * @return true if the user is an eval admin, false otherwise */ public boolean isUserEvalAdmin(String userId); - + + + // PROVIDERS + + /** + * The provider will auto-register if it can, but this will allow it to also be registered + * or unregistered manually, calling this will override any previously registered eval groups provider + * and calling it with a null will clear the currently registered provider + * + * @param provider the EGP to register for the system to use, + * if NULL then unregister the provider + */ + public void registerEvalGroupsProvider(EvalGroupsProvider provider); + } Index: api/src/java/org/sakaiproject/evaluation/logic/EvalEvaluationSetupService.java =================================================================== --- api/src/java/org/sakaiproject/evaluation/logic/EvalEvaluationSetupService.java (revision 81089) +++ api/src/java/org/sakaiproject/evaluation/logic/EvalEvaluationSetupService.java (working copy) @@ -142,10 +142,14 @@ * Get all evaluations in which this user can be evaluated. * * @param userId the acting user, normally the current user, internal user id (not username) + * @param includeRecentlyClosed filter returned evals by the closed date, + * if true, recently closed evals are returned, + * if false, no closed evals are returned, + * if null, all evals are returned * @return a List of {@link EvalEvaluation} objects (sorted by DueDate) * @throws IllegalArgumentException if the userId is null */ - public List getEvaluationsForEvaluatee(String userId); + public List getEvaluationsForEvaluatee(String userId, Boolean includeRecentlyClosed); /** * Close an evaluation before the closing date, Property changes on: tool ___________________________________________________________________ Modified: svn:mergeinfo Merged /evaluation/branches/unicon-ucb/tool:r78148-81089 Index: tool/src/test/org/sakaiproject/evaluation/tool/utils/RenderingUtilsTest.java =================================================================== --- tool/src/test/org/sakaiproject/evaluation/tool/utils/RenderingUtilsTest.java (revision 81089) +++ tool/src/test/org/sakaiproject/evaluation/tool/utils/RenderingUtilsTest.java (working copy) @@ -16,6 +16,7 @@ import static org.junit.Assert.*; +import java.util.List; import org.junit.Test; import org.sakaiproject.evaluation.tool.utils.RenderingUtils.AnswersMean; @@ -59,5 +60,47 @@ assertNotNull(e.getMessage()); } } + + @Test + public void testGetMatrixLabels() { + String[] scaleOptions0 = {"a", "b"}; + List labels0 = RenderingUtils.getMatrixLabels(scaleOptions0); + assertEquals(2, labels0.size()); + assertEquals("a", labels0.get(0)); + assertEquals("b", labels0.get(1)); + + String[] scaleOptions1 = {"a", "b", "c"}; + List labels1 = RenderingUtils.getMatrixLabels(scaleOptions1); + assertEquals(2, labels1.size()); + assertEquals("a", labels1.get(0)); + assertEquals("c", labels1.get(1)); + + String[] scaleOptions2 = {"a", "b", "c", "d"}; + List labels2 = RenderingUtils.getMatrixLabels(scaleOptions2); + assertEquals(2, labels2.size()); + assertEquals("a", labels2.get(0)); + assertEquals("d", labels2.get(1)); + + String[] scaleOptions3 = {"a", "b", "c", "d", "e"}; + List labels3 = RenderingUtils.getMatrixLabels(scaleOptions3); + assertEquals(3, labels3.size()); + assertEquals("a", labels3.get(0)); + assertEquals("e", labels3.get(1)); + assertEquals("c", labels3.get(2)); + + String[] scaleOptions4 = {"a", "b", "c", "d", "e", "f"}; + List labels4 = RenderingUtils.getMatrixLabels(scaleOptions4); + assertEquals(3, labels4.size()); + assertEquals("a", labels4.get(0)); + assertEquals("f", labels4.get(1)); + assertEquals("c", labels4.get(2)); + + String[] scaleOptions5 = {"a", "b", "c", "d", "e", "f", "g"}; + List labels5 = RenderingUtils.getMatrixLabels(scaleOptions5); + assertEquals(3, labels5.size()); + assertEquals("a", labels5.get(0)); + assertEquals("g", labels5.get(1)); + assertEquals("d", labels5.get(2)); + } } Index: tool/src/java/org/sakaiproject/evaluation/tool/TemplateBBean.java =================================================================== --- tool/src/java/org/sakaiproject/evaluation/tool/TemplateBBean.java (revision 81089) +++ tool/src/java/org/sakaiproject/evaluation/tool/TemplateBBean.java (working copy) @@ -411,7 +411,7 @@ parent.getItem().setSharing(parent.getTemplate().getSharing()); parent.getItem().setUsesNA(parent.getUsesNA()); parent.getItem().setCategory(parent.getCategory()); - setIdealColorForBlockParent(parent); + parent.getItem().setScaleDisplaySetting(parent.getScaleDisplaySetting()); /* * UMD specific @@ -506,7 +506,6 @@ // update the parent EvalTemplateItem parent = authoringService.getTemplateItemById(Long.valueOf(blockId)); parent.getItem().setScaleDisplaySetting(parent.getScaleDisplaySetting()); - setIdealColorForBlockParent(parent); try { localTemplateLogic.saveItem(parent.getItem()); localTemplateLogic.saveTemplateItem(parent); @@ -548,24 +547,4 @@ return "success"; } - private void setIdealColorForBlockParent(EvalTemplateItem parent) { - if (idealColor != null && (idealColor == Boolean.TRUE)) { - if (parent.getScaleDisplaySetting().equals(EvalConstants.ITEM_SCALE_DISPLAY_STEPPED)) { - parent.setScaleDisplaySetting(EvalConstants.ITEM_SCALE_DISPLAY_STEPPED_COLORED); - parent.getItem().setScaleDisplaySetting(EvalConstants.ITEM_SCALE_DISPLAY_STEPPED_COLORED); - } else if (parent.getScaleDisplaySetting().equals(EvalConstants.ITEM_SCALE_DISPLAY_MATRIX)) { - parent.setScaleDisplaySetting(EvalConstants.ITEM_SCALE_DISPLAY_MATRIX_COLORED); - parent.getItem().setScaleDisplaySetting(EvalConstants.ITEM_SCALE_DISPLAY_MATRIX_COLORED); - } - } else { - if (parent.getScaleDisplaySetting().equals(EvalConstants.ITEM_SCALE_DISPLAY_STEPPED_COLORED)) { - parent.setScaleDisplaySetting(EvalConstants.ITEM_SCALE_DISPLAY_STEPPED); - parent.getItem().setScaleDisplaySetting(EvalConstants.ITEM_SCALE_DISPLAY_STEPPED); - } else if (parent.getScaleDisplaySetting().equals(EvalConstants.ITEM_SCALE_DISPLAY_MATRIX_COLORED)) { - parent.setScaleDisplaySetting(EvalConstants.ITEM_SCALE_DISPLAY_MATRIX); - parent.getItem().setScaleDisplaySetting(EvalConstants.ITEM_SCALE_DISPLAY_MATRIX); - } - } - } - } \ No newline at end of file Index: tool/src/java/org/sakaiproject/evaluation/tool/locators/ResponseBeanLocator.java =================================================================== --- tool/src/java/org/sakaiproject/evaluation/tool/locators/ResponseBeanLocator.java (revision 81089) +++ tool/src/java/org/sakaiproject/evaluation/tool/locators/ResponseBeanLocator.java (working copy) @@ -87,6 +87,10 @@ // we have a passed in start date so set the response start date response.setStartTime(startDate); } + + // store this state; once the date is set, the save function will need to + // know if this evaluation has been submitted before. + response.isSubmitted(response.complete); // saving so set the endTime to now if (isEvalComplete) { response.setEndTime(new Date()); Index: tool/src/java/org/sakaiproject/evaluation/tool/renderers/ItemRendererImpl.java =================================================================== --- tool/src/java/org/sakaiproject/evaluation/tool/renderers/ItemRendererImpl.java (revision 81089) +++ tool/src/java/org/sakaiproject/evaluation/tool/renderers/ItemRendererImpl.java (working copy) @@ -22,7 +22,6 @@ import org.sakaiproject.evaluation.model.EvalTemplateItem; import org.sakaiproject.evaluation.utils.TemplateItemUtils; -import uk.org.ponder.messageutil.MessageLocator; import uk.org.ponder.rsf.components.UIBranchContainer; import uk.org.ponder.rsf.components.UIContainer; import uk.org.ponder.rsf.components.UIInput; Index: tool/src/java/org/sakaiproject/evaluation/tool/renderers/BlockRenderer.java =================================================================== --- tool/src/java/org/sakaiproject/evaluation/tool/renderers/BlockRenderer.java (revision 81089) +++ tool/src/java/org/sakaiproject/evaluation/tool/renderers/BlockRenderer.java (working copy) @@ -24,6 +24,7 @@ import org.sakaiproject.evaluation.model.EvalScale; import org.sakaiproject.evaluation.model.EvalTemplateItem; import org.sakaiproject.evaluation.tool.EvalToolConstants; +import org.sakaiproject.evaluation.tool.utils.RenderingUtils; import org.sakaiproject.evaluation.utils.ArrayUtils; import uk.org.ponder.arrayutil.MapUtil; @@ -38,6 +39,7 @@ import uk.org.ponder.rsf.components.UISelectLabel; import uk.org.ponder.rsf.components.UIVerbatim; import uk.org.ponder.rsf.components.decorators.DecoratorList; +import uk.org.ponder.rsf.components.decorators.UIDisabledDecorator; import uk.org.ponder.rsf.components.decorators.UIFreeAttributeDecorator; import uk.org.ponder.rsf.components.decorators.UIStyleDecorator; @@ -101,6 +103,111 @@ String scaleDisplaySetting = templateItem.getScaleDisplaySetting(); + + /////////////// + // matrix block + /////////////// + if (templateItem.getScaleDisplaySetting().equals(EvalConstants.ITEM_SCALE_DISPLAY_MATRIX) || + templateItem.getScaleDisplaySetting().equals(EvalConstants.ITEM_SCALE_DISPLAY_MATRIX_COLORED)) { + + for (int count = 1; count <= optionCount; count++) { + scaleValues[optionCount - count] = new Integer(optionCount - count).toString(); + scaleLabels[optionCount - count] = scaleOptions[count-1]; + } + + if (usesNA) { + scaleValues = ArrayUtils.appendArray(scaleValues, EvalConstants.NA_VALUE.toString()); + scaleLabels = ArrayUtils.appendArray(scaleLabels, ""); + } + + UIBranchContainer matrixGroup = UIBranchContainer.make(container, "matrixGroupDisplay:"); + + if (usesNA) { + matrixGroup.decorate( new UIStyleDecorator("use-na") ); + UIMessage.make(matrixGroup,"response-scale-label-na", "viewitem.na.desc"); + } + + // display header labels + List headerLabels = RenderingUtils.getMatrixLabels(scaleOptions); + UIOutput.make(matrixGroup, "label-start", headerLabels.get(0)); + UIOutput.make(matrixGroup, "label-end", headerLabels.get(1)); + if (headerLabels.size() == 3) { + UIOutput.make(matrixGroup, "label-middle", headerLabels.get(2)); + } + + UIOutput.make(matrixGroup,"label-na", "NA"); + UIVerbatim.make(matrixGroup, "matrixGroupTitle", templateItem.getItem().getItemText()); + + // display number labels + for (int i = 0; i < optionCount; i++) { + UIOutput.make(matrixGroup, "response-scale-label:", (i + 1) + ""); + } + + // iterate through each question in the block + for (int j = 0; j < childList.size(); j++) { + + // build the question row container and apply decorations + UIBranchContainer matrix = UIBranchContainer.make(matrixGroup, "matrixDisplay:", j+""); + if (usesNA) { + matrix.decorate( new UIStyleDecorator("use-na") ); + } + + // get the child item + EvalTemplateItem childTemplateItem = (EvalTemplateItem) childList.get(j); + EvalItem childItem = childTemplateItem.getItem(); + + Map childRenderProperties = (Map) renderProperties.get("child-" + childTemplateItem.getId()); + if (childRenderProperties.containsKey(ItemRenderer.EVAL_PROP_RENDER_INVALID)) { + matrix.decorate( new UIStyleDecorator("validFail") ); // must match the existing CSS class + } else if ( childRenderProperties.containsKey(ItemRenderer.EVAL_PROP_ANSWER_REQUIRED) ) { + matrix.decorate( new UIStyleDecorator("compulsory") ); // must match the existing CSS class + } + + // display question text + UIOutput.make(matrix, "itemNum", Integer.valueOf(displayNumber + j).toString() ); //$NON-NLS-2$ + UIVerbatim.make(matrix, "itemText", childItem.getItemText()); + + UIBranchContainer rowBranch = UIBranchContainer.make(matrix, "response-list:"); + + // Bind the answers to a list of answers in evaluation bean (if enabled) + String childBinding = null; + if (! disabled && bindings != null) { + childBinding = bindings[j]; + } + UISelect childRadios = UISelect.make(rowBranch, "childRadio", scaleValues, scaleLabels, childBinding, initValue); + String selectID = childRadios.getFullID(); + + if (disabled) { + childRadios.selection.willinput = false; + childRadios.selection.fossilize = false; + } + + int scaleLength = scaleValues.length; + int limit = usesNA ? scaleLength - 1: scaleLength; // skip the NA value at the end + + for (int k = 0; k < limit; ++k) { + UIBranchContainer radioBranchSecond = UIBranchContainer.make(rowBranch, "scaleOption:", k+""); + UISelectChoice.make(radioBranchSecond, "radioValue", selectID, k); + // scaleLabels are in reverse order, indexed from (end - 1) to 0. If usesNA, + // an empty label is appended; ignore that one too + int labelIndex = scaleLabels.length - k - (usesNA ? 2 : 1); + UIVerbatim.make(radioBranchSecond, "radioValueLabel", scaleLabels[labelIndex]); + } + + // display the N/A radio button always; use CSS to hide if not needed (via the "use-na" class (above) + UIBranchContainer labelContainer = UIBranchContainer.make(rowBranch, "na-input-label:"); + UISelectChoice naChoice = UISelectChoice.make(labelContainer, "na-input", selectID, scaleLength - 1); + if (!usesNA) { + naChoice.decorate( new UIDisabledDecorator()); + } + UIMessage.make(rowBranch, "radioValueLabelNa", "viewitem.na.desc"); + } + + //////////////// + // stepped block + //////////////// + } else { + UIBranchContainer blockStepped = UIBranchContainer.make(container, "blockStepped:"); // setup simple variables to make code more clear @@ -147,9 +254,6 @@ int scaleLength = scaleValues.length; int limit = usesNA ? scaleLength - 1: scaleLength; // skip the NA value at the end - if (templateItem.getScaleDisplaySetting().equals(EvalConstants.ITEM_SCALE_DISPLAY_STEPPED) || - templateItem.getScaleDisplaySetting().equals(EvalConstants.ITEM_SCALE_DISPLAY_STEPPED_COLORED) ) { - for (int j = 0; j < limit; ++j) { UIBranchContainer rowBranch = UIBranchContainer.make(blockStepped, "blockRowBranch:", j+""); @@ -181,16 +285,6 @@ // the down arrow images UIBranchContainer bottomLabelBranch = UIBranchContainer.make(blockStepped, "blockBottomLabelBranch:", j+""); UILink.make(bottomLabelBranch, "bottomImage", EvalToolConstants.STEPPED_IMAGE_URLS[2]); - } - } else if (templateItem.getScaleDisplaySetting().equals(EvalConstants.ITEM_SCALE_DISPLAY_MATRIX) || - templateItem.getScaleDisplaySetting().equals(EvalConstants.ITEM_SCALE_DISPLAY_MATRIX_COLORED)) { - - UIBranchContainer rowBranch = UIBranchContainer.make(blockStepped, "blockRowMatrixBranch:"); - UIVerbatim headerText = UIVerbatim.make(rowBranch, "itemText", templateItem.getItem().getItemText()); - for (int j = 0; j < limit; ++j) { - // Actual label - UISelectLabel.make(rowBranch, "headerLabel:", selectIDLabel, j); - } } // the child items rendering loop @@ -253,6 +347,7 @@ } } + } } return container; Index: tool/src/java/org/sakaiproject/evaluation/tool/renderers/ScaledRenderer.java =================================================================== --- tool/src/java/org/sakaiproject/evaluation/tool/renderers/ScaledRenderer.java (revision 81089) +++ tool/src/java/org/sakaiproject/evaluation/tool/renderers/ScaledRenderer.java (working copy) @@ -14,12 +14,14 @@ */ package org.sakaiproject.evaluation.tool.renderers; +import java.util.List; import java.util.Map; import org.sakaiproject.evaluation.constant.EvalConstants; import org.sakaiproject.evaluation.model.EvalScale; import org.sakaiproject.evaluation.model.EvalTemplateItem; import org.sakaiproject.evaluation.tool.EvalToolConstants; +import org.sakaiproject.evaluation.tool.utils.RenderingUtils; import org.sakaiproject.evaluation.tool.utils.ScaledUtils; import org.sakaiproject.evaluation.utils.ArrayUtils; @@ -34,6 +36,7 @@ import uk.org.ponder.rsf.components.UISelectLabel; import uk.org.ponder.rsf.components.UIVerbatim; import uk.org.ponder.rsf.components.decorators.DecoratorList; +import uk.org.ponder.rsf.components.decorators.UIDisabledDecorator; import uk.org.ponder.rsf.components.decorators.UILabelTargetDecorator; import uk.org.ponder.rsf.components.decorators.UIStyleDecorator; @@ -102,12 +105,12 @@ UIOutput.make(compactEndContainer, "compactDisplayEnd", compactDisplayEnd); if (colored) { - compactStartContainer.decorators = - new DecoratorList( new UIStyleDecorator("compactDisplayStart") );// must match the existing CSS class - //new DecoratorList(new UIColourDecorator(null, ScaledUtils.getStartColor(scale))); - compactEndContainer.decorators = - new DecoratorList( new UIStyleDecorator("compactDisplayEnd") );// must match the existing CSS class - //new DecoratorList(new UIColourDecorator(null, ScaledUtils.getEndColor(scale))); + compactStartContainer.decorators = new DecoratorList( + new UIStyleDecorator(ScaledUtils.getStartClass(scale)) // must match an existing CSS class + ); + compactEndContainer.decorators = new DecoratorList( + new UIStyleDecorator(ScaledUtils.getEndClass(scale)) // must match an existing CSS class + ); } // For the radio buttons @@ -207,18 +210,97 @@ int limit = usesNA ? scaleLength - 1: scaleLength; // skip the NA value at the end for (int j = 0; j < limit; ++j) { UIBranchContainer radiobranchNested = UIBranchContainer.make(displayContainer, "scaleOption:", j+""); - UISelectChoice choice = UISelectChoice.make(radiobranchNested, "radioValue", selectID, j); + UISelectChoice.make(radiobranchNested, "radioValue", selectID, j); UISelectLabel.make(radiobranchNested, "radioLabel", selectID, j);//.decorate( new UILabelTargetDecorator(choice)); } if (usesNA) { UIBranchContainer radiobranch3 = UIBranchContainer.make(displayContainer, "showNA:"); radiobranch3.decorators = new DecoratorList( new UIStyleDecorator("na") );// must match the existing CSS class - UISelectChoice choice = UISelectChoice.make(radiobranch3, "na-input", selectID, scaleLength - 1); + UISelectChoice.make(radiobranch3, "na-input", selectID, scaleLength - 1); UIMessage.make(radiobranch3, "na-desc", "viewitem.na.desc");//.decorate( new UILabelTargetDecorator(choice)); } + } else if (EvalConstants.ITEM_SCALE_DISPLAY_MATRIX.equals(scaleDisplaySetting) + || EvalConstants.ITEM_SCALE_DISPLAY_MATRIX_COLORED.equals(scaleDisplaySetting)) { + // MATRIX item handling + // build the question row container and apply decorations + UIBranchContainer matrix = UIBranchContainer.make(container, "matrixDisplay:"); + if (renderProperties.containsKey(ItemRenderer.EVAL_PROP_RENDER_INVALID)) { + matrix.decorate( new UIStyleDecorator("validFail") ); // must match the existing CSS class + } else if ( renderProperties.containsKey(ItemRenderer.EVAL_PROP_ANSWER_REQUIRED) ) { + matrix.decorate( new UIStyleDecorator("compulsory") ); // must match the existing CSS class + } + boolean colored = EvalConstants.ITEM_SCALE_DISPLAY_MATRIX_COLORED.equals(scaleDisplaySetting); + if (colored) { + matrix.decorate( new UIStyleDecorator("colored") ); // must match the existing CSS class + } + + if (usesNA) { + matrix.decorate( new UIStyleDecorator("use-na") ); // must match the existing CSS class + } + + // display header labels + List headerLabels = RenderingUtils.getMatrixLabels(scaleOptions); + UIOutput.make(container, "label-start", headerLabels.get(0)); + UIOutput.make(container, "label-end", headerLabels.get(1)); + if (headerLabels.size() == 3) { + UIOutput.make(container, "label-middle", headerLabels.get(2)); + } + + UIOutput.make(container,"label-na", "NA"); + + // display question text + UIOutput.make(matrix, "itemNum", displayNumber+"" ); //$NON-NLS-2$ + UIVerbatim.make(matrix, "itemText", templateItem.getItem().getItemText()); + + for (int count = 1; count <= optionCount; count++) { + scaleValues[optionCount - count] = new Integer(optionCount - count).toString(); + scaleLabels[optionCount - count] = scaleOptions[count-1]; + } + + if (usesNA) { + scaleValues = ArrayUtils.appendArray(scaleValues, EvalConstants.NA_VALUE.toString()); + scaleLabels = ArrayUtils.appendArray(scaleLabels, ""); + } + + UIBranchContainer rowBranch = UIBranchContainer.make(matrix, "response-list:"); + UISelect radios = UISelect.make(rowBranch, "dummyRadio", scaleValues, scaleLabels, bindings[0], initValue); + String selectID = radios.getFullID(); + + if (disabled) { + radios.selection.willinput = false; + radios.selection.fossilize = false; + } + + int scaleLength = scaleValues.length; + int limit = usesNA ? scaleLength - 1: scaleLength; // skip the NA value at the end + UISelectChoice[] choices = new UISelectChoice[limit]; + + for (int j = 0; j < limit; ++j) { + UIBranchContainer radioBranchSecond = UIBranchContainer.make(rowBranch, "scaleOption:", j+""); + // decorate the li so it is easier to control the styles + if (j == 0) { + radioBranchSecond.decorate( new UIStyleDecorator("matrixRadioFirst") ); + } else { + radioBranchSecond.decorate( new UIStyleDecorator("matrixRadioItems-"+scaleLength) ); + } + choices[j] = UISelectChoice.make(radioBranchSecond, "radioValue", selectID, j); + // scaleLabels are in reverse order, indexed from (end - 1) to 0. If usesNA, + // an empty label is appended; ignore that one too + int labelIndex = scaleLabels.length - j - (usesNA ? 2 : 1); + UIVerbatim.make(radioBranchSecond, "radioValueLabel", (limit - labelIndex) + ""); + } + + // display the N/A radio button if needed + UIBranchContainer labelContainer = UIBranchContainer.make(rowBranch, "na-input-label:"); + UISelectChoice choice = UISelectChoice.make(labelContainer, "na-input", selectID, scaleLength - 1); + UIMessage.make(rowBranch, "radioValueLabelNa", "viewitem.na.desc"); //.decorate( new UILabelTargetDecorator(choice)); + if (!usesNA) { + choice.decorate( new UIDisabledDecorator()); + } + } else if (EvalConstants.ITEM_SCALE_DISPLAY_STEPPED.equals(scaleDisplaySetting) || EvalConstants.ITEM_SCALE_DISPLAY_STEPPED_COLORED.equals(scaleDisplaySetting) ) { Index: tool/src/java/org/sakaiproject/evaluation/tool/inferrers/EvaluationVPInferrer.java =================================================================== --- tool/src/java/org/sakaiproject/evaluation/tool/inferrers/EvaluationVPInferrer.java (revision 81089) +++ tool/src/java/org/sakaiproject/evaluation/tool/inferrers/EvaluationVPInferrer.java (working copy) @@ -122,6 +122,7 @@ } else { // authenticated evaluation URLs depend on the state of the evaluation and the users permissions String currentUserId = commonLogic.getCurrentUserId(); + boolean userAdmin = commonLogic.isUserAdmin(currentUserId); log.debug("Note: User ("+currentUserId+") accessing authenticated evaluation: " + evaluationId + " in state ("+EvalUtils.getEvaluationState(evaluation, false)+") for group: " + evalGroupId); // eval has not started @@ -149,6 +150,12 @@ return vp; } } + // otherwise just show the preview as long as the user is an admin + if (userAdmin) { + EvalViewParameters vp = new EvalViewParameters(PreviewEvalProducer.VIEW_ID, evaluationId); + vp.external = true; + return vp; + } // else just require auth throw new SecurityException("User must be authenticated to access this page"); } Index: tool/src/java/org/sakaiproject/evaluation/tool/utils/EvalResponseAggregatorUtil.java =================================================================== --- tool/src/java/org/sakaiproject/evaluation/tool/utils/EvalResponseAggregatorUtil.java (revision 81089) +++ tool/src/java/org/sakaiproject/evaluation/tool/utils/EvalResponseAggregatorUtil.java (working copy) @@ -190,7 +190,7 @@ else if (EvalConstants.ITEM_TYPE_MULTIPLECHOICE.equals(itemType) || EvalConstants.ITEM_TYPE_SCALED.equals(itemType) || EvalConstants.ITEM_TYPE_BLOCK_CHILD.equals(itemType)) { - String labels[] = templateItem.getItem().getScale().getOptions(); + String labels[] = RenderingUtils.makeReportingScaleLabels(templateItem, templateItem.getItem().getScale().getOptions()); int value = answer.getNumeric().intValue(); if (value >= 0 && value < labels.length) { togo = labels[value]; Index: tool/src/java/org/sakaiproject/evaluation/tool/utils/ScaledUtils.java =================================================================== --- tool/src/java/org/sakaiproject/evaluation/tool/utils/ScaledUtils.java (revision 81089) +++ tool/src/java/org/sakaiproject/evaluation/tool/utils/ScaledUtils.java (working copy) @@ -14,7 +14,6 @@ */ package org.sakaiproject.evaluation.tool.utils; -import java.awt.Color; import java.util.ArrayList; import java.util.List; @@ -44,19 +43,21 @@ EvalConstants.SCALE_IDEAL_HIGH, EvalConstants.SCALE_IDEAL_OUTSIDE}; - public static String[] startColours = { - EvalToolConstants.BLUE_COLOR, - EvalToolConstants.GREEN_COLOR, - EvalToolConstants.RED_COLOR, - EvalToolConstants.RED_COLOR, - EvalToolConstants.GREEN_COLOR}; + public static String[] scaleStartClass = { + "compactDisplayNeutral", + "compactDisplayPositive", + "compactDisplayNegative", + "compactDisplayNegative", + "compactDisplayPositive", + }; - public static String[] endColours = { - EvalToolConstants.BLUE_COLOR, - EvalToolConstants.RED_COLOR, - EvalToolConstants.RED_COLOR, - EvalToolConstants.GREEN_COLOR, - EvalToolConstants.GREEN_COLOR}; + public static String[] scaleEndClass = { + "compactDisplayNeutral", + "compactDisplayNegative", + "compactDisplayNegative", + "compactDisplayPositive", + "compactDisplayPositive", + }; public static int idealIndex(EvalScale scale) { int index = -1; @@ -68,7 +69,7 @@ } if (index == -1) { // Fix for http://www.caret.cam.ac.uk/jira/browse/CTL-562 - added to ensure this will not cause a failure - log.warn("Could not find index for scale ("+scale.getId()+") for ideal setting: " + scale.getIdeal() + ", setting to default of 0 (no ideal)"); + log.info("Could not find index for scale ("+scale.getId()+") for ideal setting: " + scale.getIdeal() + ", setting to default of 0 (no ideal)"); index = 0; } return index; @@ -78,12 +79,12 @@ return EvalToolConstants.COLORED_IMAGE_URLS[idealIndex(scale)]; } - public static Color getStartColor(EvalScale scale) { - return Color.decode(startColours[idealIndex(scale)]); + public static String getStartClass(EvalScale scale) { + return scaleStartClass[idealIndex(scale)]; } - public static Color getEndColor(EvalScale scale) { - return Color.decode(endColours[idealIndex(scale)]); + public static String getEndClass(EvalScale scale) { + return scaleEndClass[idealIndex(scale)]; } /** Index: tool/src/java/org/sakaiproject/evaluation/tool/utils/RenderingUtils.java =================================================================== --- tool/src/java/org/sakaiproject/evaluation/tool/utils/RenderingUtils.java (revision 81089) +++ tool/src/java/org/sakaiproject/evaluation/tool/utils/RenderingUtils.java (working copy) @@ -14,7 +14,10 @@ */ package org.sakaiproject.evaluation.tool.utils; +import java.text.DateFormat; import java.text.DecimalFormat; +import java.util.ArrayList; +import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -22,14 +25,33 @@ import javax.servlet.http.HttpServletResponse; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.sakaiproject.evaluation.constant.EvalConstants; +import org.sakaiproject.evaluation.logic.model.EvalGroup; import org.sakaiproject.evaluation.model.EvalEvaluation; +import org.sakaiproject.evaluation.model.EvalTemplateItem; +import org.sakaiproject.evaluation.tool.producers.EvaluationNotificationsProducer; +import org.sakaiproject.evaluation.tool.producers.EvaluationRespondersProducer; +import org.sakaiproject.evaluation.tool.producers.ReportChooseGroupsProducer; +import org.sakaiproject.evaluation.tool.producers.ReportsViewingProducer; import org.sakaiproject.evaluation.tool.renderers.ItemRenderer; +import org.sakaiproject.evaluation.tool.viewparams.EvalViewParameters; +import org.sakaiproject.evaluation.tool.viewparams.ReportParameters; import org.sakaiproject.evaluation.utils.EvalUtils; import org.sakaiproject.evaluation.utils.TemplateItemDataList; import org.sakaiproject.evaluation.utils.TemplateItemDataList.DataTemplateItem; +import org.sakaiproject.evaluation.utils.TemplateItemUtils; +import uk.org.ponder.rsf.components.UIBranchContainer; +import uk.org.ponder.rsf.components.UIComponent; +import uk.org.ponder.rsf.components.UIInternalLink; +import uk.org.ponder.rsf.components.UIMessage; +import uk.org.ponder.rsf.components.UIOutput; +import uk.org.ponder.rsf.components.decorators.UITooltipDecorator; +import uk.org.ponder.rsf.viewstate.ViewParameters; + /** * A class to keep sharing rendering logic in * @@ -37,6 +59,8 @@ */ public class RenderingUtils { + private static Log log = LogFactory.getLog(RenderingUtils.class); + /** * Calculates the weighted average and number of counted answers from the responseArray * (this comes from the {@link TemplateItemDataList#getAnswerChoicesCounts(String, int, List)})
@@ -98,8 +122,100 @@ } } + + /** + * getMatrixLabels() creates a list of either 2 or 3 labels that + * will be displayed above the Matrix rendered scale. By definition, + * no scales will have 0 or 1 entries; there will always be at least 2. + * The third entry will only be included if there are 5 or more + * entries. + *

If the list contains a 3rd element, the 3rd element will be the middle + * label. We always know that the 1st element is the beginning and the + * second element is the end. + *

2 entries in returns 2 entries (beginning and end) + *
3 entries in returns 2 entries (beginning and end) + *
4 entries in returns 2 entries (beginning and end) + *
5 entries or more returns 3 entries (beginning, end, and middle) + *

For scales with 5 or more entries, the middle entry of the scale will + * be returned. For lists with an even number of elements, the element before + * the middle will be returned (i.e. a 6 element scale will return 1st, 3rd, and 6th) + * + * @param scaleOptions the array of scale options for a matrix templateItem + * @return List (see method comment) + */ + public static List getMatrixLabels(String[] scaleOptions) { + List list = new ArrayList(); + if (scaleOptions != null && scaleOptions.length > 0) { + list.add(scaleOptions[0]); + list.add(scaleOptions[scaleOptions.length - 1]); + if (scaleOptions.length > 4) { + int middleIndex = (scaleOptions.length - 1) / 2; + list.add(scaleOptions[middleIndex]); + } + } + return list; + } /** + * Calculate the proper set of scale labels to use for a template item + * in a report based on the item type (note, this will only return useful data for scale items) + * + * @param templateItem any template item (should be fully populated) + * @param scaleOptions the array of scale options for this templateItem + * @return the array of scale labels (or null if this is not scaled/MC/MA/block child) + */ + public static String[] makeReportingScaleLabels(EvalTemplateItem templateItem, String[] scaleOptions) { + if (templateItem == null) { + throw new IllegalArgumentException("templateItem must be set"); + } + String scaleLabels[] = null; + String itemType = TemplateItemUtils.getTemplateItemType(templateItem); + if (EvalConstants.ITEM_TYPE_MULTIPLECHOICE.equals(itemType) + || EvalConstants.ITEM_TYPE_MULTIPLEANSWER.equals(itemType) + ) { + // default to scale options for MC and MA + scaleLabels = scaleOptions; + } else if (EvalConstants.ITEM_TYPE_SCALED.equals(itemType) + || EvalConstants.ITEM_TYPE_BLOCK_CHILD.equals(itemType) // since BLOCK_CHILD is always a scaled item + ) { + // only do something here if this item type can handle a scale + if (log.isDebugEnabled()) log.debug("templateItem ("+templateItem.getId()+") scaled item rendering check: "+templateItem); + if (scaleOptions == null || scaleOptions.length == 0) { + // if scale options are missing then try to get them from the item + // NOTE: this could throw a NPE - not much we can do about that if it happens + scaleOptions = templateItem.getItem().getScale().getOptions(); + } + scaleLabels = scaleOptions.clone(); // default to just using the options array (use a copy) + String scaleDisplaySetting = templateItem.getScaleDisplaySetting(); + if (scaleDisplaySetting == null && templateItem.getItem() != null) { + scaleDisplaySetting = templateItem.getItem().getScaleDisplaySetting(); + } + if (scaleDisplaySetting == null) { + // this should not happen but just in case it does, we want to trap and warn about it + log.warn("templateItem ("+templateItem.getId()+") without a scale display setting, using defaults for rendering: "+templateItem); + } else if (scaleDisplaySetting.equals(EvalConstants.ITEM_SCALE_DISPLAY_MATRIX) + || scaleDisplaySetting.equals(EvalConstants.ITEM_SCALE_DISPLAY_MATRIX_COLORED) + ) { + if (log.isDebugEnabled()) log.debug("templateItem ("+templateItem.getId()+") is a matrix type item: "); + /* MATRIX - special labels for the matrix items + * Show numbers in front (e.g. "blah" becomes "1 - blah") + * and only show text if the label was display in take evals (e.g. "1 - blah, 2, 3, 4 - blah, ...) + */ + List matrixLabels = RenderingUtils.getMatrixLabels(scaleOptions); + for (int i = 0; i < scaleLabels.length; i++) { + String label = scaleLabels[i]; + if (matrixLabels.contains(label)) { + scaleLabels[i] = (i+1) + " - " + scaleLabels[i]; + } else { + scaleLabels[i] = String.valueOf(i+1); + } + } + } + } + return scaleLabels; + } + + /** * This will produce the valid message key given a category constant * @param categoryConstant * @return the message key @@ -118,7 +234,161 @@ return categoryMessage; } + /** + * Renders the reports/results column content (since the logic is complex) + * + * @param container the branch container (must contain the following elements): + * evalReportDisplay (output) + * evalReportDisplayLink (link) + * evalRespondentsDisplayLink (link) + * @param eval the evaluation + * @param group the eval group + * @param viewDate the date at which results can be viewed + * @param df the formatter for the dates + * @param responsesNeeded responses needed before results can be viewed (0 indicates they can be viewed now), + * normally should be the output from EvalBeanUtils.getResponsesNeededToViewForResponseRate(responsesCount, enrollmentsCount) + * @param responsesRequired the int value of EvalSettings.RESPONSES_REQUIRED_TO_VIEW_RESULTS + * @param evalResultsViewable true if the reports can be viewed based on eval state, prefs, and dates, + * usually the result of EvalBeanUtils.checkInstructorViewResultsForEval(), + * NOTE: this doesn't guarantee the link is visible as there might not be enough respondents + * or the view date may not be reached yet (should handle EvalSettings.INSTRUCTOR_ALLOWED_VIEW_RESULTS) + * + * Sample rendering html (from summary.html): + + ... + + + results + respondents + + + * + */ + public static void renderResultsColumn(UIBranchContainer container, EvalEvaluation eval, EvalGroup group, + Date viewDate, DateFormat df, int responsesNeeded, int responsesRequired, boolean evalResultsViewable) { + if (container == null) { throw new IllegalArgumentException("container must be set"); } + if (eval == null) { throw new IllegalArgumentException("eval must be set"); } + String evalState = EvalUtils.getEvaluationState(eval, true); + if (viewDate == null) { + viewDate = eval.getSafeViewDate(); // ensure no NPE + } + if (df == null) { + df = DateFormat.getDateInstance(DateFormat.MEDIUM); + } + String viewableDate = df.format(viewDate); + /* Reports column logic: + * - if eval OPEN (in progress) + * -- if view date not reached and if responses count not reached: show "{viewDate}: if at least {num} responses" + * -- if responses count not reached: show "After {num} more responses" + * -- if view date not reached but responses count reached: show "{viewDate}" + * -- if INSTRUCTOR_ALLOWED_VIEW_RESULTS and responses count reached: show link to report view + * - if eval CLOSED + * -- if responses count not reached: show "After {num} more responses" + * -- if view date not reached but responses count reached: show "{viewDate}" + * -- if view date and responses count reached: show link to report view + */ + boolean evalOpen = EvalUtils.checkStateBefore(evalState, EvalConstants.EVALUATION_STATE_CLOSED, false); // eval is open (still in progress) + if (evalOpen && !evalResultsViewable && responsesNeeded > 0) { + // show view date + responses message (only if the eval is still OPEN) + // controlevaluations.eval.report.viewablew.awaiting.responses + UIMessage resultOutput = UIMessage.make(container, "evalReportDisplay", "controlevaluations.eval.report.viewable.least.responses", + new Object[] { viewableDate, responsesRequired }); + // indicate the viewable date as well + resultOutput.decorate(new UITooltipDecorator( + UIMessage.make("controlevaluations.eval.report.viewable.on", new Object[] { viewableDate }) )); + } else if ( responsesNeeded > 0 ) { + // not viewable yet because there are not enough responses + UIMessage resultOutput = UIMessage.make(container, "evalReportDisplay", "controlevaluations.eval.report.after.responses", + new Object[] { responsesNeeded }); + // indicate the viewable date as well + resultOutput.decorate(new UITooltipDecorator( + UIMessage.make("controlevaluations.eval.report.viewable.on", new Object[] { viewableDate }) )); + } else if (!evalResultsViewable) { + // not viewable yet because of the view date + UIOutput resultOutput = UIOutput.make(container, "evalReportDisplay", viewableDate ); + if ( responsesNeeded == 0 ) { + // just show date if we have enough responses + resultOutput.decorate(new UITooltipDecorator( + UIMessage.make("controlevaluations.eval.report.viewable.on", new Object[] { viewableDate }) )); + } else { + // show if responses are still needed + resultOutput.decorate(new UITooltipDecorator( + UIMessage.make("controlevaluations.eval.report.awaiting.responses", new Object[] { responsesNeeded }) )); + } + } else { // if (evalResultsViewable) + // reports are viewable so just display the reports link + ViewParameters viewparams; + if (group != null) { + viewparams = new ReportParameters(ReportsViewingProducer.VIEW_ID, eval.getId(), new String[] { group.evalGroupId }); + } else { + viewparams = new ReportParameters(ReportChooseGroupsProducer.VIEW_ID, eval.getId()); + } + UIInternalLink.make(container, "evalReportDisplayLink", UIMessage.make("controlevaluations.eval.report.link"), viewparams); + } + } + + /** + * Renders the response rate column (since the logic is complex) + * + * @param container the branch container (must contain the following elements): + * responseRateDisplay (output) + * responseRateLink (link) + * @param evaluationId the id of the evaluation + * @param responsesNeeded responses needed before results can be viewed (0 indicates they can be viewed now), + * normally should be the output from EvalBeanUtils.getResponsesNeededToViewForResponseRate(responsesCount, enrollmentsCount) + * @param responseString the string representing the response rate output + * @param allowedViewResponders if true, this user can view the responders listing, + * normally only if EvalSettings.INSTRUCTOR_ALLOWED_VIEW_RESPONDERS is true or is admin user + * @param allowedEmailStudents if true, this user can send emails to evaluators, + * normally only if EvalSettings.INSTRUCTOR_ALLOWED_EMAIL_STUDENTS is true or is admin/owner of eval + * + * Sample html (from summary.html): + + ... + + 2 of 39 + + + + * + */ + public static void renderReponseRateColumn(UIBranchContainer container, Long evaluationId, + int responsesNeeded, String responseString, boolean allowedViewResponders, boolean allowedEmailStudents) { + if (container == null) { throw new IllegalArgumentException("container must be set"); } + if (evaluationId == null) { throw new IllegalArgumentException("evaluationId must be set"); } + if (responseString == null || "".equals(responseString)) { throw new IllegalArgumentException("responseString must be set"); } + /* Responses column: + * - if min responses reached and INSTRUCTOR_ALLOWED_VIEW_RESPONDERS: link to the responders view + * - else if INSTRUCTOR_ALLOWED_EMAIL_STUDENTS: link to notifications (send emails) view + * - else no options enabled and not admin ONLY show the text of the responses info (and tooltip if min responses not reached) + */ + boolean showRespondersLink = (responsesNeeded == 0 && allowedViewResponders); + UIComponent responseRateCompoenent; + if (allowedEmailStudents || showRespondersLink) { + ViewParameters viewparams; + if (showRespondersLink) { + viewparams = new EvalViewParameters( EvaluationRespondersProducer.VIEW_ID, evaluationId ); + } else if (allowedEmailStudents) { + viewparams = new EvalViewParameters( EvaluationNotificationsProducer.VIEW_ID, evaluationId ); + } else { + throw new RuntimeException("Bad logic in renderReponseRateColumn: should not be possible to reach this"); + } + responseRateCompoenent = UIInternalLink.make(container, "responseRateLink", + UIMessage.make("controlevaluations.eval.responses.inline", new Object[] { responseString }), + viewparams ); + } else { + responseRateCompoenent = UIMessage.make(container, "responseRateDisplay", "controlevaluations.eval.responses.inline", + new Object[] { responseString } ); + } + if (responsesNeeded > 0) { + // show if responses are still needed + responseRateCompoenent.decorate(new UITooltipDecorator( + UIMessage.make("controlevaluations.eval.report.awaiting.responses", new Object[] { responsesNeeded }) )); + } + } + + /** * Ensures all rendering calcs work the same way and generate the same general properties * * @param dti the dti which holds the template item (wrap the template item if you need to) Index: tool/src/java/org/sakaiproject/evaluation/tool/TakeEvalBean.java =================================================================== --- tool/src/java/org/sakaiproject/evaluation/tool/TakeEvalBean.java (revision 81089) +++ tool/src/java/org/sakaiproject/evaluation/tool/TakeEvalBean.java (working copy) @@ -88,7 +88,7 @@ messages.addMessage(new TargettedMessage(messageKey, e)); return "failure"; } - messages.addMessage(new TargettedMessage("evaluations.take.message", new Object[] { + messages.addMessage(new TargettedMessage("evaluations.save.no.submit.message", new Object[] { eval.getTitle(), commonLogic.getDisplayTitle(evalGroupId) }, TargettedMessage.SEVERITY_INFO)); return "success"; Index: tool/src/java/org/sakaiproject/evaluation/tool/EvalToolConstants.java =================================================================== --- tool/src/java/org/sakaiproject/evaluation/tool/EvalToolConstants.java (revision 81089) +++ tool/src/java/org/sakaiproject/evaluation/tool/EvalToolConstants.java (working copy) @@ -79,6 +79,7 @@ EvalConstants.ITEM_SCALE_DISPLAY_COMPACT_COLORED, EvalConstants.ITEM_SCALE_DISPLAY_FULL, EvalConstants.ITEM_SCALE_DISPLAY_FULL_COLORED, + EvalConstants.ITEM_SCALE_DISPLAY_MATRIX, EvalConstants.ITEM_SCALE_DISPLAY_STEPPED, EvalConstants.ITEM_SCALE_DISPLAY_STEPPED_COLORED, EvalConstants.ITEM_SCALE_DISPLAY_VERTICAL @@ -90,6 +91,7 @@ "templateitem.scale.select.compactc", "templateitem.scale.select.full", "templateitem.scale.select.fullc", + "templateitem.scale.select.matrix", "templateitem.scale.select.stepped", "templateitem.scale.select.steppedc", "templateitem.scale.select.vertical" @@ -97,12 +99,14 @@ public static String[] SCALE_DISPLAY_GROUP_SETTING_VALUES = new String[] { EvalConstants.ITEM_SCALE_DISPLAY_MATRIX, - EvalConstants.ITEM_SCALE_DISPLAY_STEPPED + EvalConstants.ITEM_SCALE_DISPLAY_STEPPED, + EvalConstants.ITEM_SCALE_DISPLAY_STEPPED_COLORED }; public static String[] SCALE_DISPLAY_GROUP_SETTING_LABELS_PROPS = new String[] { "templateitem.scale.select.matrix", - "templateitem.scale.select.stepped" + "templateitem.scale.select.stepped", + "templateitem.scale.select.steppedc" }; Index: tool/src/java/org/sakaiproject/evaluation/tool/producers/ControlEvaluationsProducer.java =================================================================== --- tool/src/java/org/sakaiproject/evaluation/tool/producers/ControlEvaluationsProducer.java (revision 81089) +++ tool/src/java/org/sakaiproject/evaluation/tool/producers/ControlEvaluationsProducer.java (working copy) @@ -16,6 +16,7 @@ import java.text.DateFormat; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; @@ -30,9 +31,10 @@ import org.sakaiproject.evaluation.logic.entity.EvalCategoryEntityProvider; import org.sakaiproject.evaluation.model.EvalAssignGroup; import org.sakaiproject.evaluation.model.EvalEvaluation; +import org.sakaiproject.evaluation.tool.renderers.HumanDateRenderer; import org.sakaiproject.evaluation.tool.renderers.NavBarRenderer; +import org.sakaiproject.evaluation.tool.utils.RenderingUtils; import org.sakaiproject.evaluation.tool.viewparams.EvalViewParameters; -import org.sakaiproject.evaluation.tool.viewparams.ReportParameters; import org.sakaiproject.evaluation.utils.EvalUtils; import uk.org.ponder.rsf.components.UIBranchContainer; @@ -104,6 +106,11 @@ public void setNavBarRenderer(NavBarRenderer navBarRenderer) { this.navBarRenderer = navBarRenderer; } + + private HumanDateRenderer humanDateRenderer; + public void setHumanDateRenderer(HumanDateRenderer humanDateRenderer) { + this.humanDateRenderer = humanDateRenderer; + } /* (non-Javadoc) @@ -111,10 +118,6 @@ */ public void fill(UIContainer tofill, ViewParameters viewparams, ComponentChecker checker) { - String actionBean = "setupEvalBean."; - boolean earlyCloseAllowed = (Boolean) settings.get(EvalSettings.ENABLE_EVAL_EARLY_CLOSE); - boolean reopeningAllowed = (Boolean) settings.get(EvalSettings.ENABLE_EVAL_REOPEN); - // use a date which is related to the current users locale DateFormat df = DateFormat.getDateInstance(DateFormat.MEDIUM, locale); @@ -122,6 +125,12 @@ UIMessage.make(tofill, "page-title", "controlevaluations.page.title"); // local variables used in the render logic + String actionBean = "setupEvalBean."; + boolean earlyCloseAllowed = (Boolean) settings.get(EvalSettings.ENABLE_EVAL_EARLY_CLOSE); + boolean reopeningAllowed = (Boolean) settings.get(EvalSettings.ENABLE_EVAL_REOPEN); + boolean viewResultsIgnoreDates = (Boolean) settings.get(EvalSettings.VIEW_SURVEY_RESULTS_IGNORE_DATES); + int responsesRequired = ((Integer) settings.get(EvalSettings.RESPONSES_REQUIRED_TO_VIEW_RESULTS)).intValue(); + String currentUserId = commonLogic.getCurrentUserId(); /* @@ -134,8 +143,10 @@ List inqueueEvals = new ArrayList(); List activeEvals = new ArrayList(); List closedEvals = new ArrayList(); - List takableEvaluationIds = new ArrayList(); // collect evaluation Ids for evaluations that are pending and active ONLY + // UM specific code for checking unpublished groups - collect evaluation Ids for evaluations that are pending and active ONLY + List takableEvaluationIds = new ArrayList(); + List evals = evaluationSetupService.getVisibleEvaluationsForUser(commonLogic.getCurrentUserId(), false, false, true); for (int j = 0; j < evals.size(); j++) { // get queued, active, closed evaluations by date @@ -143,24 +154,29 @@ EvalEvaluation eval = (EvalEvaluation) evals.get(j); String evalStatus = evaluationService.updateEvaluationState(eval.getId()); - if ( EvalConstants.EVALUATION_STATE_INQUEUE.equals(evalStatus) ) { - inqueueEvals.add(eval); - takableEvaluationIds.add(eval.getId()); - } else if (EvalConstants.EVALUATION_STATE_CLOSED.equals(evalStatus) || - EvalConstants.EVALUATION_STATE_VIEWABLE.equals(evalStatus) ) { - closedEvals.add(eval); + if (EvalConstants.EVALUATION_STATE_PARTIAL.equals(evalStatus) ) { + partialEvals.add(eval); + } else if ( EvalConstants.EVALUATION_STATE_INQUEUE.equals(evalStatus) ) { + inqueueEvals.add(eval); + takableEvaluationIds.add(eval.getId()); } else if (EvalConstants.EVALUATION_STATE_ACTIVE.equals(evalStatus) || - EvalConstants.EVALUATION_STATE_GRACEPERIOD.equals(evalStatus) ) { - activeEvals.add(eval); - takableEvaluationIds.add(eval.getId()); - } else if (EvalConstants.EVALUATION_STATE_PARTIAL.equals(evalStatus) ) { - partialEvals.add(eval); + EvalConstants.EVALUATION_STATE_GRACEPERIOD.equals(evalStatus) ) { + activeEvals.add(eval); + takableEvaluationIds.add(eval.getId()); + } else if (EvalConstants.EVALUATION_STATE_CLOSED.equals(evalStatus) || + EvalConstants.EVALUATION_STATE_VIEWABLE.equals(evalStatus) ) { + closedEvals.add(eval); } } - - // get evalGroups for pending and active evals only. Later we will check if any of them are unpublished - Map> takableAssignGroups = evaluationService.getAssignGroupsForEvals(takableEvaluationIds.toArray(new Long[0]), true, null); + // UM specific code for checking unpublished groups + int countUnpublishedGroups = 0; + Map> takableAssignGroups = new HashMap>(); + if ((Boolean) settings.get(EvalSettings.ENABLE_SITE_GROUP_PUBLISH_CHECK)) { + // get evalGroups for pending and active evals only. Later we will check if any of them are unpublished + takableAssignGroups = evaluationService.getAssignGroupsForEvals(takableEvaluationIds.toArray(new Long[takableEvaluationIds.size()]), true, null); + } + // create start new eval link UIInternalLink.make(tofill, "begin-evaluation-link", UIMessage.make("starteval.page.title"), new EvalViewParameters(EvaluationCreateProducer.VIEW_ID, null) ); @@ -180,18 +196,17 @@ UIBranchContainer evaluationRow = UIBranchContainer.make(evalListing, "partial-eval-row:", evaluation.getId().toString()); UIOutput.make(evaluationRow, "partial-eval-title", evaluation.getTitle() ); - UIOutput.make(evaluationRow, "partial-eval-created", df.format(evaluation.getLastModified())); - UIInternalLink.make(evaluationRow, "inqueue-eval-edit-link", UIMessage.make("controlevaluations.partial.continue"), + UIInternalLink.make(evaluationRow, "partial-eval-edit-link", UIMessage.make("controlevaluations.partial.continue"), new EvalViewParameters(EvaluationSettingsProducer.VIEW_ID, evaluation.getId()) ); - - UIInternalLink.make(evaluationRow, "inqueue-eval-delete-link", UIMessage.make("general.command.delete"), + UIInternalLink.make(evaluationRow, "partial-eval-delete-link", UIMessage.make("general.command.delete"), new EvalViewParameters( RemoveEvalProducer.VIEW_ID, evaluation.getId() ) ); + + humanDateRenderer.renderDate(evaluationRow, "partial-eval-created", evaluation.getLastModified()); } } - - int countUnpublishedGroups = 0; + // create inqueue evaluations header if (inqueueEvals.size() > 0) { UIBranchContainer evalListing = UIBranchContainer.make(tofill, "inqueue-eval-listing:"); @@ -203,31 +218,47 @@ UIInternalLink evalTitleLink = UIInternalLink.make(evaluationRow, "inqueue-eval-link", evaluation.getTitle(), new EvalViewParameters( PreviewEvalProducer.VIEW_ID, evaluation.getId(), evaluation.getTemplate().getId() ) ); - UILink.make(evaluationRow, "eval-direct-link", UIMessage.make("controlevaluations.eval.direct.link"), + evalTitleLink.decorate( new UITooltipDecorator( UIMessage.make("controlevaluations.eval.title.tooltip")) ); + + if ((Boolean) settings.get(EvalSettings.ENABLE_SITE_GROUP_PUBLISH_CHECK)) { + // NOTE: UM specific code + // check if this eval has any site/group that is unpublished + List assignGroups = takableAssignGroups.get(evaluation.getId()); + int countUnpublished = 0; + for (EvalAssignGroup group : assignGroups){ + if (! commonLogic.isEvalGroupPublished(group.getEvalGroupId())){ + countUnpublished ++; + } + } + if (countUnpublished > 0){ + evalTitleLink.decorate( new UIStyleDecorator("elementAlertFront") ); + evalTitleLink.decorate( new UITooltipDecorator( UIMessage.make("controlevaluations.instructions.site.unpublished")) ); + countUnpublishedGroups ++; + } + } + + UILink directLink = UILink.make(evaluationRow, "eval-direct-link", UIMessage.make("controlevaluations.eval.direct.link"), commonLogic.getEntityURL(evaluation)); + directLink.decorate( new UITooltipDecorator( UIMessage.make("controlevaluations.eval.direct.tooltip")) ); if (evaluation.getEvalCategory() != null) { UILink catLink = UILink.make(evaluationRow, "eval-category-direct-link", shortenText(evaluation.getEvalCategory(), 20), commonLogic.getEntityURL(EvalCategoryEntityProvider.ENTITY_PREFIX, evaluation.getEvalCategory()) ); catLink.decorators = new DecoratorList( new UITooltipDecorator( UIMessage.make("general.category.link.tip", new Object[]{evaluation.getEvalCategory()}) ) ); } - - // check if this eval has any site/group that is unpublished - List assignGroups = takableAssignGroups.get(evaluation.getId()); - int countUnpublished = 0; - for (EvalAssignGroup group : assignGroups){ - if (! commonLogic.isEvalGroupPublished(group.getEvalGroupId())){ - countUnpublished ++; - } + + UIInternalLink.make(evaluationRow, "inqueue-eval-edit-link", UIMessage.make("general.command.edit"), + new EvalViewParameters(EvaluationSettingsProducer.VIEW_ID, evaluation.getId()) ); + + // do the locked check first since it is more efficient + if ( ! evaluation.getLocked().booleanValue() && + evaluationService.canRemoveEvaluation(currentUserId, evaluation.getId()) ) { + // evaluation removable + UIInternalLink.make(evaluationRow, "inqueue-eval-delete-link", UIMessage.make("general.command.delete"), + new EvalViewParameters( RemoveEvalProducer.VIEW_ID, evaluation.getId() ) ); } - - if (countUnpublished > 0){ - evalTitleLink.decorate( new UIStyleDecorator("elementAlertFront") ); - evalTitleLink.decorate( new UITooltipDecorator( UIMessage.make("controlevaluations.instructions.site.unpublished")) ); - countUnpublishedGroups ++; - } - UIInternalLink.make(evaluationRow, "notifications-link", + UIInternalLink.make(evaluationRow, "inqueue-eval-notifications-link", UIMessage.make("controlevaluations.eval.email.link"), new EvalViewParameters( EvaluationNotificationsProducer.VIEW_ID, evaluation.getId() ) ); // vary the display depending on the number of groups assigned @@ -241,21 +272,11 @@ new EvalViewParameters(EvaluationAssignmentsProducer.VIEW_ID, evaluation.getId()) ); } - UIOutput.make(evaluationRow, "inqueue-eval-startdate", df.format(evaluation.getStartDate())); + humanDateRenderer.renderDate(evaluationRow, "inqueue-eval-startdate", evaluation.getStartDate()); + // TODO add support for evals that do not close - summary.label.nevercloses - UIOutput.make(evaluationRow, "inqueue-eval-duedate", df.format(evaluation.getSafeDueDate())); + humanDateRenderer.renderDate(evaluationRow, "inqueue-eval-duedate", evaluation.getSafeDueDate()); - UIInternalLink.make(evaluationRow, "inqueue-eval-edit-link", UIMessage.make("general.command.edit"), - new EvalViewParameters(EvaluationSettingsProducer.VIEW_ID, evaluation.getId()) ); - - // do the locked check first since it is more efficient - if ( ! evaluation.getLocked().booleanValue() && - evaluationService.canRemoveEvaluation(currentUserId, evaluation.getId()) ) { - // evaluation removable - UIInternalLink.make(evaluationRow, "inqueue-eval-delete-link", UIMessage.make("general.command.delete"), - new EvalViewParameters( RemoveEvalProducer.VIEW_ID, evaluation.getId() ) ); - } - } } else { UIMessage.make(tofill, "no-inqueue-evals", "controlevaluations.inqueue.none"); @@ -263,35 +284,46 @@ // create active evaluations header and link - Boolean viewResultsIgnoreDate = (Boolean) settings.get(EvalSettings.VIEW_SURVEY_RESULTS_IGNORE_DATES); - if (activeEvals.size() > 0) { UIBranchContainer evalListing = UIBranchContainer.make(tofill, "active-eval-listing:"); - - if(viewResultsIgnoreDate) { - UIOutput.make(evalListing, "controlevaluations-eval-report-header", - UIMessage.make("controlevaluations.eval.report.header").getValue()); - } for (int i = 0; i < activeEvals.size(); i++) { EvalEvaluation evaluation = (EvalEvaluation) activeEvals.get(i); UIBranchContainer evaluationRow = UIBranchContainer.make(evalListing, "active-eval-row:", evaluation.getId().toString()); - UIInternalLink.make(evaluationRow, "active-eval-link", evaluation.getTitle(), + UIInternalLink evalTitleLink = UIInternalLink.make(evaluationRow, "active-eval-link", evaluation.getTitle(), new EvalViewParameters( PreviewEvalProducer.VIEW_ID, evaluation.getId(), evaluation.getTemplate().getId() ) ); - UILink.make(evaluationRow, "eval-direct-link", UIMessage.make("controlevaluations.eval.direct.link"), + evalTitleLink.decorate( new UITooltipDecorator( UIMessage.make("controlevaluations.eval.title.tooltip")) ); + + UILink directLink = UILink.make(evaluationRow, "eval-direct-link", UIMessage.make("controlevaluations.eval.direct.link"), commonLogic.getEntityURL(evaluation)); + directLink.decorate( new UITooltipDecorator( UIMessage.make("controlevaluations.eval.direct.tooltip")) ); if (evaluation.getEvalCategory() != null) { UILink catLink = UILink.make(evaluationRow, "eval-category-direct-link", shortenText(evaluation.getEvalCategory(), 20), commonLogic.getEntityURL(EvalCategoryEntityProvider.ENTITY_PREFIX, evaluation.getEvalCategory()) ); catLink.decorators = new DecoratorList( new UITooltipDecorator( UIMessage.make("general.category.link.tip", new Object[]{evaluation.getEvalCategory()}) ) ); } - - UIInternalLink.make(evaluationRow, "notifications-link", + UIInternalLink.make(evaluationRow, "active-eval-notifications-link", UIMessage.make("controlevaluations.eval.email.link"), new EvalViewParameters( EvaluationNotificationsProducer.VIEW_ID, evaluation.getId() ) ); + UIInternalLink.make(evaluationRow, "active-eval-edit-link", UIMessage.make("general.command.edit"), + new EvalViewParameters(EvaluationSettingsProducer.VIEW_ID, evaluation.getId()) ); + + if ( evaluationService.canRemoveEvaluation(currentUserId, evaluation.getId()) ) { + // evaluation removable + UIInternalLink.make(evaluationRow, "active-eval-delete-link", UIMessage.make("general.command.delete"), + new EvalViewParameters( RemoveEvalProducer.VIEW_ID, evaluation.getId() ) ); + } + + if (earlyCloseAllowed) { + UIForm form = UIForm.make(evaluationRow, "evalCloseForm"); + form.addParameter( new UIELBinding(actionBean + "evaluationId", evaluation.getId()) ); + UICommand.make(form, "evalCloseCommand", UIMessage.make("controlevaluations.active.close.now"), + actionBean + "closeEvalAction"); + } + // vary the display depending on the number of groups assigned int groupsCount = evaluationService.countEvaluationGroups(evaluation.getId(), false); if (groupsCount == 1) { @@ -303,66 +335,34 @@ new EvalViewParameters(EvaluationAssignmentsProducer.VIEW_ID, evaluation.getId()) ); } + humanDateRenderer.renderDate(evaluationRow, "active-eval-startdate", evaluation.getStartDate()); + // TODO add support for evals that do not close - summary.label.nevercloses + humanDateRenderer.renderDate(evaluationRow, "active-eval-duedate", evaluation.getSafeDueDate()); + // calculate the response rate int responsesCount = deliveryService.countResponses(evaluation.getId(), null, true); int enrollmentsCount = evaluationService.countParticipantsForEval(evaluation.getId(), null); int responsesNeeded = evalBeanUtils.getResponsesNeededToViewForResponseRate(responsesCount, enrollmentsCount); String responseString = EvalUtils.makeResponseRateStringFromCounts(responsesCount, enrollmentsCount); - if (responsesNeeded == 0) { - UIInternalLink.make(evaluationRow, "responders-link", - UIMessage.make("controlevaluations.eval.responses.inline", new Object[] { responseString }), - new EvalViewParameters( EvaluationRespondersProducer.VIEW_ID, evaluation.getId() ) ); - } else { - UIMessage.make(evaluationRow, "active-eval-response-rate", "controlevaluations.eval.responses.inline", - new Object[] { responseString } ); - } + RenderingUtils.renderReponseRateColumn(evaluationRow, evaluation.getId(), responsesNeeded, + responseString, true, true); - if(viewResultsIgnoreDate) { - - UIOutput.make(evaluationRow, "active-eval-view-report-node"); - - if (responsesNeeded == 0) { - - UIInternalLink.make(evaluationRow, "activeEvalViewReportLink", UIMessage.make("controlevaluations.active.report.title"), new ReportParameters( - ReportChooseGroupsProducer.VIEW_ID, evaluation.getId())); - } else { - - UIMessage.make(evaluationRow, "active-eval-view-report-item", - UIMessage.make( - "controlevaluations.eval.report.awaiting.responses", - new Object[] { responsesNeeded }).getValue()); - } - } - - UIOutput.make(evaluationRow, "active-eval-startdate", df.format(evaluation.getStartDate())); - // TODO add support for evals that do not close - summary.label.nevercloses - UIOutput.make(evaluationRow, "active-eval-duedate", df.format(evaluation.getSafeDueDate())); - - UIInternalLink.make(evaluationRow, "active-eval-edit-link", UIMessage.make("general.command.edit"), - new EvalViewParameters(EvaluationSettingsProducer.VIEW_ID, evaluation.getId()) ); - - if ( evaluationService.canRemoveEvaluation(currentUserId, evaluation.getId()) ) { - // evaluation removable - UIInternalLink.make(evaluationRow, "active-eval-delete-link", UIMessage.make("general.command.delete"), - new EvalViewParameters( RemoveEvalProducer.VIEW_ID, evaluation.getId() ) ); - } - - if (earlyCloseAllowed) { - UIForm form = UIForm.make(evaluationRow, "evalCloseForm"); - form.addParameter( new UIELBinding(actionBean + "evaluationId", evaluation.getId()) ); - UICommand.make(form, "evalCloseCommand", UIMessage.make("controlevaluations.active.close.now"), - actionBean + "closeEvalAction"); - } + // owner can view the results but only early IF the setting is enabled + boolean viewResultsEval = viewResultsIgnoreDates ? true : false; + // now render the results links depending on what the user is allowed to see + RenderingUtils.renderResultsColumn(evaluationRow, evaluation, null, evaluation.getSafeViewDate(), df, + responsesNeeded, responsesRequired, viewResultsEval); } } else { UIMessage.make(tofill, "no-active-evals", "controlevaluations.active.none"); } - - if (countUnpublishedGroups > 0){ - UIMessage.make(tofill, "eval-instructions-group-notpublished", "controlevaluations.instructions.site.unpublished"); + + if (countUnpublishedGroups > 0) { + UIMessage.make(tofill, "eval-instructions-group-notpublished", "controlevaluations.instructions.site.unpublished"); } + // create closed evaluations header and link if (closedEvals.size() > 0) { UIBranchContainer evalListing = UIBranchContainer.make(tofill, "closed-eval-listing:"); @@ -372,17 +372,32 @@ UIBranchContainer evaluationRow = UIBranchContainer.make(evalListing, "closed-eval-row:", evaluation.getId().toString()); - UIInternalLink.make(evaluationRow, "closed-eval-link", evaluation.getTitle(), + UIInternalLink evalTitleLink = UIInternalLink.make(evaluationRow, "closed-eval-link", evaluation.getTitle(), new EvalViewParameters( PreviewEvalProducer.VIEW_ID, evaluation.getId(), evaluation.getTemplate().getId() ) ); + evalTitleLink.decorate( new UITooltipDecorator( UIMessage.make("controlevaluations.eval.title.tooltip")) ); if (evaluation.getEvalCategory() != null) { UIOutput category = UIOutput.make(evaluationRow, "eval-category", shortenText(evaluation.getEvalCategory(), 20) ); - category.decorators = new DecoratorList( - new UITooltipDecorator( evaluation.getEvalCategory() ) ); + category.decorators = new DecoratorList( new UITooltipDecorator( evaluation.getEvalCategory() ) ); } - UIInternalLink.make(evaluationRow, "notifications-link", + UIInternalLink.make(evaluationRow, "closed-eval-edit-link", UIMessage.make("general.command.edit"), + new EvalViewParameters(EvaluationSettingsProducer.VIEW_ID, evaluation.getId()) ); + + if ( evaluationService.canRemoveEvaluation(currentUserId, evaluation.getId()) ) { + // evaluation removable + UIInternalLink.make(evaluationRow, "closed-eval-delete-link", UIMessage.make("general.command.delete"), + new EvalViewParameters( RemoveEvalProducer.VIEW_ID, evaluation.getId() ) ); + } + + UIInternalLink.make(evaluationRow, "closed-eval-notifications-link", UIMessage.make("controlevaluations.eval.email.link"), new EvalViewParameters( EvaluationNotificationsProducer.VIEW_ID, evaluation.getId() ) ); + if (reopeningAllowed) { + // add in link to settings page with reopen option + UIInternalLink.make(evaluationRow, "closed-eval-reopen-link", UIMessage.make("controlevaluations.closed.reopen.now"), + new EvalViewParameters(EvaluationSettingsProducer.VIEW_ID, evaluation.getId(), true) ); + } + // vary the display depending on the number of groups assigned int groupsCount = evaluationService.countEvaluationGroups(evaluation.getId(), false); if (groupsCount == 1) { @@ -394,52 +409,25 @@ new EvalViewParameters(EvaluationAssignmentsProducer.VIEW_ID, evaluation.getId()) ); } + humanDateRenderer.renderDate(evaluationRow, "closed-eval-startdate", evaluation.getStartDate()); + + humanDateRenderer.renderDate(evaluationRow, "closed-eval-duedate", evaluation.getSafeDueDate()); + // calculate the response rate int responsesCount = deliveryService.countResponses(evaluation.getId(), null, true); int enrollmentsCount = evaluationService.countParticipantsForEval(evaluation.getId(), null); int responsesNeeded = evalBeanUtils.getResponsesNeededToViewForResponseRate(responsesCount, enrollmentsCount); String responseString = EvalUtils.makeResponseRateStringFromCounts(responsesCount, enrollmentsCount); + String evalState = EvalUtils.getEvaluationState(evaluation, false); - if (responsesNeeded == 0) { - UIInternalLink.make(evaluationRow, "responders-link", responseString, - new EvalViewParameters( EvaluationRespondersProducer.VIEW_ID, evaluation.getId() ) ); - } else { - UIOutput.make(evaluationRow, "closed-eval-response-rate", responseString ); - } + RenderingUtils.renderReponseRateColumn(evaluationRow, evaluation.getId(), responsesNeeded, + responseString, true, true); - UIOutput.make(evaluationRow, "closed-eval-duedate", df.format(evaluation.getDueDate())); - - if (EvalConstants.EVALUATION_STATE_VIEWABLE.equals(EvalUtils.getEvaluationState(evaluation, false)) ) { - if ( responsesNeeded == 0 ) { - UIInternalLink.make(evaluationRow, "closed-eval-report-link", - UIMessage.make("controlevaluations.eval.report.link"), - new ReportParameters(ReportChooseGroupsProducer.VIEW_ID, evaluation.getId() )); - } else { - // cannot view yet, more responses needed - UIMessage.make(evaluationRow, "closed-eval-message", - "controlevaluations.eval.report.awaiting.responses", new Object[] { responsesNeeded }); - } - } else { - UIMessage.make(evaluationRow, "closed-eval-message", - "controlevaluations.eval.report.viewable.on", - new String[] { df.format(evaluation.getSafeViewDate()) }); - } - - UIInternalLink.make(evaluationRow, "closed-eval-edit-link", UIMessage.make("general.command.edit"), - new EvalViewParameters(EvaluationSettingsProducer.VIEW_ID, evaluation.getId()) ); - - if ( evaluationService.canRemoveEvaluation(currentUserId, evaluation.getId()) ) { - // evaluation removable - UIInternalLink.make(evaluationRow, "closed-eval-delete-link", UIMessage.make("general.command.delete"), - new EvalViewParameters( RemoveEvalProducer.VIEW_ID, evaluation.getId() ) ); - } - - if (reopeningAllowed) { - // add in link to settings page with reopen option - UIInternalLink.make(evaluationRow, "closed-eval-reopen-link", UIMessage.make("controlevaluations.closed.reopen.now"), - new EvalViewParameters(EvaluationSettingsProducer.VIEW_ID, evaluation.getId(), true) ); - } - + // owner can view the results but only early IF the setting is enabled + boolean viewResultsEval = viewResultsIgnoreDates ? true : EvalUtils.checkStateAfter(evalState, EvalConstants.EVALUATION_STATE_VIEWABLE, true); + // now render the results links depending on what the user is allowed to see + RenderingUtils.renderResultsColumn(evaluationRow, evaluation, null, evaluation.getSafeViewDate(), df, + responsesNeeded, responsesRequired, viewResultsEval); } } else { UIMessage.make(tofill, "no-closed-evals", "controlevaluations.closed.none"); Index: tool/src/java/org/sakaiproject/evaluation/tool/producers/TakeEvalProducer.java =================================================================== --- tool/src/java/org/sakaiproject/evaluation/tool/producers/TakeEvalProducer.java (revision 81089) +++ tool/src/java/org/sakaiproject/evaluation/tool/producers/TakeEvalProducer.java (working copy) @@ -66,6 +66,7 @@ import uk.org.ponder.rsf.components.UIContainer; import uk.org.ponder.rsf.components.UIELBinding; import uk.org.ponder.rsf.components.UIForm; +import uk.org.ponder.rsf.components.UIInitBlock; import uk.org.ponder.rsf.components.UIInternalLink; import uk.org.ponder.rsf.components.UIMessage; import uk.org.ponder.rsf.components.UIOutput; @@ -78,7 +79,6 @@ import uk.org.ponder.rsf.components.decorators.UICSSDecorator; import uk.org.ponder.rsf.components.decorators.UIFreeAttributeDecorator; import uk.org.ponder.rsf.components.decorators.UIIDStrategyDecorator; -import uk.org.ponder.rsf.components.decorators.UILabelTargetDecorator; import uk.org.ponder.rsf.components.decorators.UIStyleDecorator; import uk.org.ponder.rsf.flow.ARIResult; import uk.org.ponder.rsf.flow.ActionResultInterceptor; @@ -213,7 +213,8 @@ } if (! evalTakeViewParams.external) { - UIInternalLink.make(tofill, "summary-link", UIMessage.make("summary.page.title"), + UIBranchContainer navTool = UIBranchContainer.make(tofill, "navIntraTool:"); + UIInternalLink.make(navTool, "summary-link", UIMessage.make("summary.page.title"), new SimpleViewParameters(SummaryProducer.VIEW_ID)); } @@ -244,6 +245,7 @@ List validGroups = new ArrayList(); // stores EvalGroup objects if (canAccess) { + if (log.isDebugEnabled()) log.debug("User ("+currentUserId+") can take evalution ("+evaluationId+")"); // eval is accessible so check user can take it if (evalGroupId != null) { // there was an eval group passed in so make sure things are ok @@ -331,17 +333,20 @@ response = evaluationService.getResponseForUserAndGroup( evaluationId, currentUserId, evalGroupId); if (response == null) { + if (log.isDebugEnabled()) log.debug("User ("+currentUserId+") has no previous response for eval ("+evaluationId+")"); // create the initial response if there is not one // EVALSYS-360 because of a hibernate issue this will not work, do a binding instead -AZ //responseId = localResponsesLogic.createResponse(evaluationId, currentUserId, evalGroupId); } else { responseId = response.getId(); + if (log.isDebugEnabled()) log.debug("User ("+currentUserId+") has previous response ("+responseId+") in eval ("+evaluationId+")"); } } if (responseId != null) { // load up the previous responses for this user (no need to attempt to load if the response is new, there will be no answers yet) answerMap = localResponsesLogic.getAnswersMapByTempItemAndAssociated(responseId); + if (log.isDebugEnabled()) log.debug("User ("+currentUserId+"), eval ("+evaluationId+"), previous answers map: "+answerMap); } // show the switch group selection and form if there are other valid groups for this user @@ -367,6 +372,7 @@ UIBranchContainer groupTitle = UIBranchContainer.make(tofill, "show-group-title:"); UIMessage.make(groupTitle, "group-title-header", "takeeval.group.title.header"); UIOutput.make(groupTitle, "group-title", evalGroup.title ); + if (log.isDebugEnabled()) log.debug("Begin render of eval: "+eval.getTitle()+" ("+evaluationId+"), group: "+groupTitle+" ("+evalGroupId+")"); // show instructions if not null if (eval.getInstructions() != null && !("".equals(eval.getInstructions())) ) { @@ -402,14 +408,15 @@ Set instructorIds = tidl.getAssociateIds(EvalConstants.ITEM_CATEGORY_INSTRUCTOR); Set assistantIds = tidl.getAssociateIds(EvalConstants.ITEM_CATEGORY_ASSISTANT); List associatedTypes = tidl.getAssociateTypes(); + if (log.isDebugEnabled()) log.debug("TIDL: eval="+evaluationId+", group="+evalGroupId+", items="+tidl.getTemplateItemsCount()+" instructorIds: "+instructorIds+", "+" associatedTypes: "+associatedTypes); // SELECTION Code - EVALSYS-618 - Boolean selectionsEnabled = (Boolean) evalSettings - .get(EvalSettings.ENABLE_INSTRUCTOR_ASSISTANT_SELECTION); + Boolean selectionsEnabled = (Boolean) evalSettings.get(EvalSettings.ENABLE_INSTRUCTOR_ASSISTANT_SELECTION); String instructorSelectionOption = EvalAssignGroup.SELECTION_OPTION_ALL; String assistantSelectionOption = EvalAssignGroup.SELECTION_OPTION_ALL; + if (log.isDebugEnabled()) log.debug("Selections: enabled="+selectionsEnabled+", inst="+instructorSelectionOption+", asst="+assistantSelectionOption); Map savedSelections = new HashMap(); - if(response!=null){ + if (response != null) { savedSelections = response.getSelections(); } if (selectionsEnabled) { @@ -420,27 +427,21 @@ instructorSelectionOption = EvalUtils.getSelectionSetting( EvalAssignGroup.SELECTION_TYPE_INSTRUCTOR, assignGroup, null); selectorType.put(EvalConstants.ITEM_CATEGORY_INSTRUCTOR, instructorSelectionOption); - Boolean assistantsEnabled = (Boolean) evalSettings - .get(EvalSettings.ENABLE_ASSISTANT_CATEGORY); + Boolean assistantsEnabled = (Boolean) evalSettings.get(EvalSettings.ENABLE_ASSISTANT_CATEGORY); if (assistantsEnabled) { assistantSelectionOption = EvalUtils.getSelectionSetting( EvalAssignGroup.SELECTION_TYPE_ASSISTANT, assignGroup, null); selectorType.put(EvalConstants.ITEM_CATEGORY_ASSISTANT, assistantSelectionOption); } if (response != null) { - // emit currently selected people into hidden element - // for JS use + // emit currently selected people into hidden element for JS use Set savedIds = new HashSet(); - for (Iterator selector = savedSelections - .keySet().iterator(); selector.hasNext();) { + for (Iterator selector = savedSelections.keySet().iterator(); selector.hasNext();) { String selectKey = (String) selector.next(); - String[] usersFound = savedSelections - .get(selectKey); + String[] usersFound = savedSelections.get(selectKey); savedIds.add(usersFound[0]); } - UIOutput savedSel = UIOutput - .make(formBranch, "selectedPeopleInResponse", - savedIds.toString()); + UIOutput savedSel = UIOutput.make(formBranch, "selectedPeopleInResponse", savedIds.toString()); savedSel.decorators = new DecoratorList( new UIIDStrategyDecorator( "selectedPeopleInResponse")); @@ -478,10 +479,9 @@ assValues.add(user.userId); assLabels.add(user.displayName); UIBranchContainer row = UIBranchContainer.make(showSwitchGroup, uiTag + "-multiple-row:"); - UISelectChoice choice = UISelectChoice.make(row, uiTag + "-multiple-box", assSelectID, assLabels.size()-1); - UISelectLabel lb = UISelectLabel.make(row, uiTag + "-multiple-label", assSelectID, assLabels.size()-1); - UILabelTargetDecorator.targetLabel(lb, choice); - } + UISelectChoice.make(row, uiTag + "-multiple-box", assSelectID, assLabels.size()-1); + UISelectLabel.make(row, uiTag + "-multiple-label", assSelectID, assLabels.size()-1); + } assSelect.optionlist = UIOutputMany.make(assValues.toArray(new String[] {})); assSelect.optionnames = UIOutputMany.make(assLabels.toArray(new String[] {})); } else if (EvalAssignGroup.SELECTION_OPTION_ONE.equals(selectValue)) { @@ -505,14 +505,14 @@ throw new IllegalStateException("Invalid selection option (" + selectValue + "): do not know how to handle this."); } - } else if (selectUserIds.size() == 1 && associatedTypes.contains(selectKey) ) { + } else if (selectUserIds.size() == 1 && associatedTypes.contains(selectKey) ) { // handle case where there are selections set but ONLY 1 user in the role. if (! selectValue.equals(EvalAssignGroup.SELECTION_OPTION_ALL)) { for (String userId : selectUserIds) { form.parameters.add(new UIELBinding(selectionOTP, userId)); } } - }else{ + } else { // handle case where there are selections set but no users in the roles. if (! selectValue.equals(EvalAssignGroup.SELECTION_OPTION_ALL)) { form.parameters.add(new UIELBinding(selectionOTP, "none")); @@ -523,7 +523,9 @@ // loop through the TIGs and handle each associated category Boolean useCourseCategoryOnly = (Boolean) evalSettings.get(EvalSettings.ITEM_USE_COURSE_CATEGORY_ONLY); + if (log.isDebugEnabled()) log.debug("TIGs: useCourseCategoryOnly="+useCourseCategoryOnly); for (TemplateItemGroup tig : tidl.getTemplateItemGroups()) { + if (log.isDebugEnabled()) log.debug("TIGs: tig.associateType="+tig.associateType); UIBranchContainer categorySectionBranch = UIBranchContainer.make(form, "categorySection:"); // only do headers if we are allowed to use categories if (! useCourseCategoryOnly) { @@ -538,6 +540,7 @@ } // loop through the hierarchy node groups + if (log.isDebugEnabled()) log.debug("TIGs: tig.hierarchyNodeGroups="+tig.hierarchyNodeGroups.size()); for (HierarchyNodeGroup hng : tig.hierarchyNodeGroups) { // render a node title if (hng.node != null) { @@ -550,6 +553,7 @@ } List dtis = hng.getDataTemplateItems(false); + if (log.isDebugEnabled()) log.debug("DTIs: count="+dtis.size()); for (int i = 0; i < dtis.size(); i++) { DataTemplateItem dti = dtis.get(i); UIBranchContainer nodeItemsBranch = UIBranchContainer.make(categorySectionBranch, "itemrow:templateItem"); @@ -563,13 +567,19 @@ } if (response != null && !response.complete) { - UIOutput.make(tofill, "saveEvaluationWithoutSubmitWarning", null); + UIMessage.make(tofill, "saveEvaluationWithoutSubmitWarning", "takeeval.saved.warning"); } Boolean saveEvaluationWithoutSubmit = (Boolean) evalSettings.get(EvalSettings.STUDENT_SAVE_WITHOUT_SUBMIT); if (saveEvaluationWithoutSubmit && (response == null || !response.complete)) { UICommand.make(form, "saveEvaluationWithoutSubmit", UIMessage.make("takeeval.save.button"), "#{takeEvalBean.saveEvaluationWithoutSubmit}"); } UICommand.make(form, "submitEvaluation", UIMessage.make("takeeval.submit.button"), "#{takeEvalBean.submitEvaluation}"); + Boolean studentCancelAllowed = (Boolean) evalSettings.get(EvalSettings.STUDENT_CANCEL_ALLOWED); + if (studentCancelAllowed) { + UIMessage.make(form, "cancelEvaluation", "general.cancel.button"); + // populate the URL we will activate (do NOT use summary-link here) + UIInternalLink.make(tofill, "dashboard-link", new SimpleViewParameters(SummaryProducer.VIEW_ID)); + } } else { // user cannot access eval so give them a sad message EvalUser current = commonLogic.getEvalUserById(currentUserId); @@ -621,6 +631,7 @@ * @param missingKeys the invalid keys, needed for calculating rendering props */ private void renderItemPrep(UIBranchContainer parent, UIForm form, DataTemplateItem dti, EvalEvaluation eval, Set missingKeys) { + if (log.isDebugEnabled()) log.debug("renderItemPrep: eval="+eval.getId()+", dti="+dti); int displayIncrement = 0; // stores the increment in the display number String[] currentAnswerOTP = null; // holds array of bindings for items EvalTemplateItem templateItem = dti.templateItem; @@ -653,6 +664,7 @@ // setup the render properties to send along Map renderProps = RenderingUtils.makeRenderProps(dti, eval, missingKeys, null); // render the item + if (log.isDebugEnabled()) log.debug("render item: num="+displayNumber+" (count="+renderedItemCount+"), render="+renderProps+", templateItem="+templateItem); itemRenderer.renderItem(parent, "renderedItem:", currentAnswerOTP, templateItem, displayNumber, false, renderProps); /* increment the item counters, if we displayed 1 item, increment by 1, Index: tool/src/java/org/sakaiproject/evaluation/tool/producers/ModifyScaleProducer.java =================================================================== --- tool/src/java/org/sakaiproject/evaluation/tool/producers/ModifyScaleProducer.java (revision 81089) +++ tool/src/java/org/sakaiproject/evaluation/tool/producers/ModifyScaleProducer.java (working copy) @@ -75,6 +75,7 @@ public void setNavBarRenderer(NavBarRenderer navBarRenderer) { this.navBarRenderer = navBarRenderer; } + /* (non-Javadoc) * @see uk.org.ponder.rsf.view.ComponentProducer#fillComponents(uk.org.ponder.rsf.components.UIContainer, uk.org.ponder.rsf.viewstate.ViewParameters, uk.org.ponder.rsf.view.ComponentChecker) */ @@ -90,7 +91,7 @@ navBarRenderer.makeNavBar(tofill, NavBarRenderer.NAV_ELEMENT, this.getViewID()); EvalScaleParameters evalScaleParams = (EvalScaleParameters) viewparams; - Long scaleId = evalScaleParams.scaleId; + Long scaleId = evalScaleParams.id; String scaleOTP = "scaleBeanLocator."; if (scaleId == null) { @@ -144,9 +145,14 @@ } // command buttons - UIMessage.make(form, "scale-add-modify-cancel-button", "general.cancel.button"); UICommand.make(form, "scale-add-modify-save-button", UIMessage.make("modifyscale.save.scale.button"), "templateBBean.saveScaleAction"); + UIInternalLink.make(form, "scale-add-modify-preview", + UIMessage.make("modifyscale.save.preview.button"), + // NOTE: special case which generates the URL without any params, we will fill in the params later via JS + new EvalScaleParameters(PreviewScaleProducer.VIEW_ID) + ); + UIMessage.make(form, "scale-add-modify-cancel", "general.cancel.button"); } Index: tool/src/java/org/sakaiproject/evaluation/tool/producers/RemoveScaleProducer.java =================================================================== --- tool/src/java/org/sakaiproject/evaluation/tool/producers/RemoveScaleProducer.java (revision 81089) +++ tool/src/java/org/sakaiproject/evaluation/tool/producers/RemoveScaleProducer.java (working copy) @@ -82,7 +82,7 @@ // passed in values EvalScaleParameters evalScaleParams = (EvalScaleParameters) viewparams; - Long scaleId = evalScaleParams.scaleId; + Long scaleId = evalScaleParams.id; EvalScale scale = authoringService.getScaleById(scaleId); @@ -124,6 +124,7 @@ } public ViewParameters getViewParameters() { - return new EvalScaleParameters(VIEW_ID, null); + return new EvalScaleParameters(VIEW_ID); } + } Index: tool/src/java/org/sakaiproject/evaluation/tool/producers/ControlScalesProducer.java =================================================================== --- tool/src/java/org/sakaiproject/evaluation/tool/producers/ControlScalesProducer.java (revision 81089) +++ tool/src/java/org/sakaiproject/evaluation/tool/producers/ControlScalesProducer.java (working copy) @@ -76,7 +76,7 @@ UIInternalLink.make(tofill, "add-new-scale-link", UIMessage.make("controlscales.add.new.scale.link"), - new EvalScaleParameters(ModifyScaleProducer.VIEW_ID, null)); + new EvalScaleParameters(ModifyScaleProducer.VIEW_ID)); UIMessage.make(tofill, "scales-control-heading", "controlscales.page.heading"); UIMessage.make(tofill, "scales-control-instruction", "controlscales.page.instruction"); @@ -132,6 +132,11 @@ UIMessage.make(scaleBranch, "remove-dummy", "general.command.delete"); } + UIInternalLink.make(scaleBranch, "preview-link", + UIMessage.make("general.command.preview"), + new EvalScaleParameters(PreviewScaleProducer.VIEW_ID, scale.getId()) + ); + // Display the scale options vertically // ASCII value of 'a' = 97 so initial value is 96. // This is kinda weird, not sure it is really needed -AZ Index: tool/src/java/org/sakaiproject/evaluation/tool/producers/EvaluationRespondersProducer.java =================================================================== --- tool/src/java/org/sakaiproject/evaluation/tool/producers/EvaluationRespondersProducer.java (revision 81089) +++ tool/src/java/org/sakaiproject/evaluation/tool/producers/EvaluationRespondersProducer.java (working copy) @@ -27,6 +27,7 @@ import org.sakaiproject.evaluation.logic.EvalCommonLogic; import org.sakaiproject.evaluation.logic.EvalDeliveryService; import org.sakaiproject.evaluation.logic.EvalEvaluationService; +import org.sakaiproject.evaluation.logic.EvalSettings; import org.sakaiproject.evaluation.logic.model.EvalGroup; import org.sakaiproject.evaluation.logic.model.EvalUser; import org.sakaiproject.evaluation.model.EvalAssignUser; @@ -64,6 +65,11 @@ this.commonLogic = commonLogic; } + private EvalSettings settings; + public void setSettings(EvalSettings settings) { + this.settings = settings; + } + private EvalEvaluationService evaluationService; public void setEvaluationService(EvalEvaluationService evaluationService) { this.evaluationService = evaluationService; @@ -81,13 +87,15 @@ private NavBarRenderer navBarRenderer; public void setNavBarRenderer(NavBarRenderer navBarRenderer) { - this.navBarRenderer = navBarRenderer; - } + this.navBarRenderer = navBarRenderer; + } /* (non-Javadoc) * @see uk.org.ponder.rsf.view.ComponentProducer#fillComponents(uk.org.ponder.rsf.components.UIContainer, uk.org.ponder.rsf.viewstate.ViewParameters, uk.org.ponder.rsf.view.ComponentChecker) */ public void fill(UIContainer tofill, ViewParameters viewparams, ComponentChecker checker) { + String currentUserId = commonLogic.getCurrentUserId(); + boolean userAdmin = commonLogic.isUserAdmin(currentUserId); // local variables used in the render logic DateFormat dateFormat = DateFormat.getDateInstance(DateFormat.MEDIUM, locale); @@ -104,7 +112,13 @@ EvalEvaluation eval = evaluationService.getEvaluationById(evaluationId); String evalGroupId = evalViewParameters.evalGroupId; boolean evalAnonymous = EvalConstants.EVALUATION_AUTHCONTROL_NONE.equals(eval.getAuthControl()); + boolean controlEval = evaluationService.canControlEvaluation(currentUserId, evaluationId); + boolean allowEmailStudents = (Boolean) settings.get(EvalSettings.INSTRUCTOR_ALLOWED_EMAIL_STUDENTS); + boolean allowViewResponders = (Boolean) settings.get(EvalSettings.INSTRUCTOR_ALLOWED_VIEW_RESPONDERS); + int responsesRequired = ((Integer) settings.get(EvalSettings.RESPONSES_REQUIRED_TO_VIEW_RESULTS)).intValue(); + boolean currentUserViewResponses = controlEval || allowViewResponders; + // get the lists of participants and responses String[] evalGroupIds = null; if (evalGroupId != null) { @@ -124,6 +138,7 @@ String userId = response.getOwner(); groupToUserResponses.get(groupId).put(userId, response); } + boolean showStatus = ((responses.size() >= responsesRequired) || currentUserViewResponses); String statsAssigned; if (evalAnonymous) { @@ -163,10 +178,13 @@ dateFormat.format(eval.getSafeDueDate())} ); UIMessage.make(tofill, "responseStats", "evalresponders.stats", new Object[] {responses.size(), statsAssigned} ); - UIInternalLink.make(tofill, "responseEmailLink", - UIMessage.make("evalresponders.notifications.link", new Object[] {eval.getTitle()}), - new EvalViewParameters(EvaluationNotificationsProducer.VIEW_ID, evaluationId) ); + if (allowEmailStudents || userAdmin) { + UIInternalLink.make(tofill, "responseEmailLink", + UIMessage.make("evalresponders.notifications.link", new Object[] {eval.getTitle()}), + new EvalViewParameters(EvaluationNotificationsProducer.VIEW_ID, evaluationId) ); + } + UIInternalLink.make(tofill, "evalRespondersLink", UIMessage.make("evalresponders.page.title"), new EvalViewParameters(EvaluationSettingsProducer.VIEW_ID, evaluationId, evalGroupId) ); @@ -184,26 +202,38 @@ new Object[] {group.title}); UIMessage.make(groupBranch, "responseGroupStats", "evalresponders.stats", new Object[] {userResponses.size(), users.size()}); - UIInternalLink.make(groupBranch, "responseGroupEmailLink", - UIMessage.make("evalresponders.notifications.link", new Object[] {group.title}), - new EvalViewParameters(EvaluationNotificationsProducer.VIEW_ID, evaluationId, groupId) ); + if (allowEmailStudents || userAdmin) { + UIInternalLink.make(groupBranch, "responseGroupEmailLink", + UIMessage.make("evalresponders.notifications.link", new Object[] {group.title}), + new EvalViewParameters(EvaluationNotificationsProducer.VIEW_ID, evaluationId, groupId) ); + } } + // display the list of respondents // sort the list of users Collections.sort(users, new EvalUser.SortNameComparator()); UIBranchContainer showResponsesBranch = UIBranchContainer.make(groupBranch, "showGroupResponses:"); for (EvalUser evalUser : users) { UIBranchContainer userResponseBranch = UIBranchContainer.make(showResponsesBranch, "responses:"); UIOutput.make(userResponseBranch, "responseUser", evalUser.displayName); - String messagekey = "evalresponders.status.untaken"; // untaken (no response) - EvalResponse response = userResponses.get(evalUser.userId); - if (response != null) { - if (response.complete) { - messagekey = "evalresponders.status.complete"; - } else { - messagekey = "evalresponders.status.incomplete"; + if (showStatus) { + String messagekey = "evalresponders.status.untaken"; // untaken (no response) + EvalResponse response = userResponses.get(evalUser.userId); + if (response != null) { + if (response.complete) { + messagekey = "evalresponders.status.complete"; + } else { + messagekey = "evalresponders.status.incomplete"; + } } + UIMessage.make(userResponseBranch, "responseStatus", messagekey); + } else if (currentUserViewResponses) { + // user can view but not enough responses yet + UIMessage.make(userResponseBranch, "responseStatus", "controlevaluations.eval.report.after.responses", + new Object[] {responsesRequired}); + } else { + // user cannot view - period + UIOutput.make(userResponseBranch, "responseStatus", "-"); } - UIMessage.make(userResponseBranch, "responseStatus", messagekey); } } } Index: tool/src/java/org/sakaiproject/evaluation/tool/producers/AdministrateProducer.java =================================================================== --- tool/src/java/org/sakaiproject/evaluation/tool/producers/AdministrateProducer.java (revision 81089) +++ tool/src/java/org/sakaiproject/evaluation/tool/producers/AdministrateProducer.java (working copy) @@ -188,6 +188,9 @@ makeBoolean(form, "instructors-email-students", ADMIN_WBL, EvalSettings.INSTRUCTOR_ALLOWED_EMAIL_STUDENTS); UIMessage.make(form, "instructors-email-students-note", "administrate.instructors.email.students.note"); + makeBoolean(form, "instructors-view-responders", ADMIN_WBL, EvalSettings.INSTRUCTOR_ALLOWED_VIEW_RESPONDERS); + UIMessage.make(form, "instructors-view-responders-note", "administrate.instructors.view.responders.note"); + makeBoolean(form,"admin-enable-provider-sync", ADMIN_WBL, EvalSettings.ENABLE_PROVIDER_SYNC); UIMessage.make(form, "admin-enable-provider-sync-note", "administrate.admin.enable.provider.sync"); @@ -229,6 +232,7 @@ // Student Settings UIMessage.make(form, "student-settings-header", "administrate.student.settings.header"); + UIMessage.make(form, "student-settings-header-inner", "administrate.student.settings.header.inner"); //Select for whether students can leave questions unanswered or not makeSelect(form, "students-unanswered", //$NON-NLS-1$ @@ -245,22 +249,28 @@ UIMessage.make(form, "students-modify-responses-note", "administrate.students.modify.responses.note"); //Select whether students can save without submit or not - String[] booleanConfigurableLabels = - { - "administrate.true.label", - "administrate.false.label" - }; - String[] booleanConfigurableValues = - { - EvalToolConstants.ADMIN_BOOLEAN_YES, - EvalToolConstants.ADMIN_BOOLEAN_NO - }; - makeSelect(form, "students-save-without-submit", - booleanConfigurableValues, - booleanConfigurableLabels, - ADMIN_WBL, EvalSettings.STUDENT_SAVE_WITHOUT_SUBMIT, true); - UIMessage.make(form, "students-save-without-submit-note","administrate.students.save.without.submit.note"); +// String[] booleanConfigurableLabels = +// { +// "administrate.true.label", +// "administrate.false.label" +// }; +// String[] booleanConfigurableValues = +// { +// EvalToolConstants.ADMIN_BOOLEAN_YES, +// EvalToolConstants.ADMIN_BOOLEAN_NO +// }; +// makeSelect(form, "students-save-without-submit", +// booleanConfigurableValues, +// booleanConfigurableLabels, +// ADMIN_WBL, EvalSettings.STUDENT_SAVE_WITHOUT_SUBMIT, true); +// UIMessage.make(form, "students-save-without-submit-note","administrate.students.save.without.submit.note"); + makeBoolean(form,"students-save-without-submit", ADMIN_WBL, EvalSettings.STUDENT_SAVE_WITHOUT_SUBMIT); + UIMessage.make(form, "students-save-without-submit-note", "administrate.students.save.without.submit.note"); + + makeBoolean(form,"students-cancel-allowed", ADMIN_WBL, EvalSettings.STUDENT_CANCEL_ALLOWED); + UIMessage.make(form, "students-cancel-allowed-note", "administrate.students.cancel.allowed.note"); + //Select for whether students can view results makeSelect(form, "students-view-results", administrateConfigurableValues, @@ -290,7 +300,26 @@ makeBoolean(form, "hierarchy-display-node-headers", ADMIN_WBL, EvalSettings.DISPLAY_HIERARCHY_HEADERS); UIMessage.make(form, "hierarchy-display-node-headers-note", "administrate.hierarchy-display-node-headers-note"); + + // DASHBOARD settings + makeBoolean(form, "dash-enable-evaluatee-box", ADMIN_WBL, EvalSettings.ENABLE_EVALUATEE_BOX); + + //Number of days old can an eval be and still be recently closed + Integer evaluateeRecentlyClosedDays = (Integer) evalSettings.get(EvalSettings.EVAL_EVALUATEE_RECENTLY_CLOSED_DAYS); + if (evaluateeRecentlyClosedDays == null) { evaluateeRecentlyClosedDays = 10; } + UIInput.make(form, "dash-evaluatee-closed-still-recent", PathUtil.composePath(ADMIN_WBL, EvalSettings.EVAL_EVALUATEE_RECENTLY_CLOSED_DAYS), evaluateeRecentlyClosedDays.toString()); + + makeBoolean(form, "dash-enable-administrating-box", ADMIN_WBL, EvalSettings.ENABLE_ADMINISTRATING_BOX); + + //Number of days old can an eval be and still be recently closed + Integer recentlyClosedDays = (Integer) evalSettings.get(EvalSettings.EVAL_RECENTLY_CLOSED_DAYS); + if (recentlyClosedDays == null) { recentlyClosedDays = 10; } + UIInput.make(form, "dash-eval-closed-still-recent", PathUtil.composePath(ADMIN_WBL, EvalSettings.EVAL_RECENTLY_CLOSED_DAYS), recentlyClosedDays.toString()); + + makeBoolean(form, "dash-enable-sites-summary", ADMIN_WBL, EvalSettings.ENABLE_SUMMARY_SITES_BOX); + + // GENERAL settings // Select for number of responses before results could be viewed @@ -338,9 +367,6 @@ makeBoolean(form, "general-use-view-date", ADMIN_WBL, EvalSettings.EVAL_USE_VIEW_DATE); makeBoolean(form, "general-same-view-date", ADMIN_WBL, EvalSettings.EVAL_USE_SAME_VIEW_DATES); - makeBoolean(form, "general-enable-administrating-box", ADMIN_WBL, EvalSettings.ENABLE_ADMINISTRATING_BOX); - makeBoolean(form, "general-enable-sites-summary", ADMIN_WBL, EvalSettings.ENABLE_SUMMARY_SITES_BOX); - makeBoolean(form, "general-enable-evaluatee-box", ADMIN_WBL, EvalSettings.ENABLE_EVALUATEE_BOX); makeBoolean(form, "general-show-my-toplinks", ADMIN_WBL, EvalSettings.ENABLE_MY_TOPLINKS); makeBoolean(form, "general-use-eval-category", ADMIN_WBL, EvalSettings.ENABLE_EVAL_CATEGORIES); makeBoolean(form, "general-use-eval-term-id", ADMIN_WBL, EvalSettings.ENABLE_EVAL_TERM_IDS); @@ -365,11 +391,6 @@ // makeBoolean(form, "general-require-comments-block", EvalSettings.REQUIRE_COMMENTS_BLOCK); - //Number of days old can an eval be and still be recently closed - Integer recentlyClosedDays = (Integer) evalSettings.get(EvalSettings.EVAL_RECENTLY_CLOSED_DAYS); - UIInput.make(form, "general-eval-closed-still-recent", PathUtil.composePath(ADMIN_WBL, EvalSettings.EVAL_RECENTLY_CLOSED_DAYS), recentlyClosedDays.toString()); - UIMessage.make(form, "general-eval-closed-still-recent-note","administrate.general.eval.closed.still.recent.note"); - //Minimum time difference (in hours) between the start date and due date makeSelect(form, "general-mim-time-diff-between-dates", EvalToolConstants.MINIMUM_TIME_DIFFERENCE, @@ -384,6 +405,7 @@ makeBoolean(form, "general-disable-question-blocks", ADMIN_WBL, EvalSettings.DISABLE_QUESTION_BLOCKS); makeBoolean(form, "general-enable-ta-category", ADMIN_WBL, EvalSettings.ENABLE_ASSISTANT_CATEGORY); makeBoolean(form, "general-enable-selections", ADMIN_WBL, EvalSettings.ENABLE_INSTRUCTOR_ASSISTANT_SELECTION); + makeBoolean(form, "general-enable-site-publish-check", ADMIN_WBL, EvalSettings.ENABLE_SITE_GROUP_PUBLISH_CHECK); //makeBoolean(form, "general-filter-evalgroups", EvalSettings.ENABLE_FILTER_ASSIGNABLE_GROUPS); //TODO: refactor this code EVALSYS-942 UIInput.make(form, "general-local-css-path", PathUtil.composePath(ADMIN_WBL, EvalSettings.LOCAL_CSS_PATH), EvalUtils.safeStringSetting(evalSettings, EvalSettings.LOCAL_CSS_PATH)); Index: tool/src/java/org/sakaiproject/evaluation/tool/producers/ReportsViewingProducer.java =================================================================== --- tool/src/java/org/sakaiproject/evaluation/tool/producers/ReportsViewingProducer.java (revision 81089) +++ tool/src/java/org/sakaiproject/evaluation/tool/producers/ReportsViewingProducer.java (working copy) @@ -19,9 +19,11 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.sakaiproject.evaluation.beans.EvalBeanUtils; import org.sakaiproject.evaluation.constant.EvalConstants; import org.sakaiproject.evaluation.logic.EvalAuthoringService; import org.sakaiproject.evaluation.logic.EvalCommonLogic; +import org.sakaiproject.evaluation.logic.EvalDeliveryService; import org.sakaiproject.evaluation.logic.EvalEvaluationService; import org.sakaiproject.evaluation.logic.EvalSettings; import org.sakaiproject.evaluation.logic.ReportingPermissions; @@ -40,10 +42,10 @@ import org.sakaiproject.evaluation.utils.ArrayUtils; import org.sakaiproject.evaluation.utils.EvalUtils; import org.sakaiproject.evaluation.utils.TemplateItemDataList; -import org.sakaiproject.evaluation.utils.TemplateItemUtils; import org.sakaiproject.evaluation.utils.TemplateItemDataList.DataTemplateItem; import org.sakaiproject.evaluation.utils.TemplateItemDataList.HierarchyNodeGroup; import org.sakaiproject.evaluation.utils.TemplateItemDataList.TemplateItemGroup; +import org.sakaiproject.evaluation.utils.TemplateItemUtils; import org.sakaiproject.util.Validator; import uk.org.ponder.rsf.components.UIBranchContainer; @@ -112,6 +114,16 @@ public void setNavBarRenderer(NavBarRenderer navBarRenderer) { this.navBarRenderer = navBarRenderer; } + + private EvalDeliveryService deliveryService; + public void setDeliveryService(EvalDeliveryService deliveryService) { + this.deliveryService = deliveryService; + } + + private EvalBeanUtils evalBeanUtils; + public void setEvalBeanUtils(EvalBeanUtils evalBeanUtils) { + this.evalBeanUtils = evalBeanUtils; + } int totalCommentsCount = 0; int totalTextResponsesCount = 0; @@ -179,6 +191,17 @@ EvalEvaluation evaluation = evaluationService.getEvaluationById(evaluationId); + // prevent viewing the report if the report requires a minimum number of submissions that hasn't been met yet + int responsesCount = deliveryService.countResponses(evaluation.getId(), reportViewParams.groupIds[0], true); + int enrollmentsCount = evaluationService.countParticipantsForEval(evaluation.getId(), new String[]{reportViewParams.groupIds[0]}); + int responsesNeeded = evalBeanUtils.getResponsesNeededToViewForResponseRate(responsesCount, enrollmentsCount); + + // the eval owner (or anyone who can control this eval - like a super admin - can ignore the min responses check) + boolean controlEval = evaluationService.canControlEvaluation(currentUserId, evaluationId); + if (!controlEval && responsesNeeded > 0) { + throw new SecurityException("At least " + responsesNeeded + " more responses must be submitted to view this report"); + } + // do a permission check if (! reportingPermissions.canViewEvaluationResponses(evaluation, reportViewParams.groupIds)) { throw new SecurityException("Invalid user attempting to access reports page: " + currentUserId); @@ -315,13 +338,13 @@ // if we are in essay view mode then do not show the scale or the answers counts EvalScale scale = templateItem.getItem().getScale(); String[] scaleOptions = scale.getOptions(); - String scaleLabels[] = new String[scaleOptions.length]; + String scaleLabels[] = RenderingUtils.makeReportingScaleLabels(templateItem, scaleOptions); int[] choicesCounts = TemplateItemDataList.getAnswerChoicesCounts(templateItemType, scaleOptions.length, itemAnswers); for (int x = 0; x < scaleLabels.length; x++) { UIBranchContainer choicesBranch = UIBranchContainer.make(scaled, "choices:"); - UIOutput.make(choicesBranch, "choiceText", scaleOptions[x]); + UIOutput.make(choicesBranch, "choiceText", scaleLabels[x]); UIMessage.make(choicesBranch, "choiceCount", "viewreport.answers.percentage", new String[] { choicesCounts[x]+"", makePercentage(choicesCounts[x], responsesCount) }); } @@ -463,7 +486,7 @@ /** * Should we render this item based off the passed in parameters? - * (ie. Should we only render certain template items) + * (i.e. Should we only render certain template items) */ private boolean renderBasedOnOptions(EvalTemplateItem templateItem) { boolean togo = false; Index: tool/src/java/org/sakaiproject/evaluation/tool/producers/EvaluationSettingsProducer.java =================================================================== --- tool/src/java/org/sakaiproject/evaluation/tool/producers/EvaluationSettingsProducer.java (revision 81089) +++ tool/src/java/org/sakaiproject/evaluation/tool/producers/EvaluationSettingsProducer.java (working copy) @@ -21,6 +21,7 @@ import java.util.List; import java.util.Locale; +import org.azeckoski.reflectutils.ArrayUtils; import org.sakaiproject.evaluation.constant.EvalConstants; import org.sakaiproject.evaluation.logic.EvalAuthoringService; import org.sakaiproject.evaluation.logic.EvalCommonLogic; @@ -58,9 +59,6 @@ import uk.org.ponder.rsf.components.UISelectChoice; import uk.org.ponder.rsf.components.UISelectLabel; import uk.org.ponder.rsf.components.UIVerbatim; -import uk.org.ponder.rsf.components.decorators.DecoratorList; -import uk.org.ponder.rsf.components.decorators.UILabelTargetDecorator; -import uk.org.ponder.rsf.components.decorators.UITextDimensionsDecorator; import uk.org.ponder.rsf.components.decorators.UITooltipDecorator; import uk.org.ponder.rsf.evolvers.FormatAwareDateInputEvolver; import uk.org.ponder.rsf.evolvers.TextInputEvolver; @@ -320,9 +318,8 @@ String resultsSharingId = resultsSharingRadios.getFullID(); for (int i = 0; i < EvalToolConstants.EVAL_RESULTS_SHARING_VALUES.length; ++i) { UIBranchContainer radiobranch = UIBranchContainer.make(form, "resultsSharingChoice:", i + ""); - UISelectChoice choice = UISelectChoice.make(radiobranch, "radioValue", resultsSharingId, i); - UISelectLabel.make(radiobranch, "radioLabel", resultsSharingId, i) - .decorate( new UILabelTargetDecorator(choice) ); + UISelectChoice.make(radiobranch, "radioValue", resultsSharingId, i); + UISelectLabel.make(radiobranch, "radioLabel", resultsSharingId, i); } //EVALSYS-1117 @@ -485,17 +482,26 @@ } UIMessage.make(form, "enable-mass-email-label", "evalsettings.general.enable.email.onbegin"); } - + // render this only if *NOT* using consolidated emails UISelect reminderDaysSelect = null; - if(! consolidatedEmailsEnabled.booleanValue()) { - UIBranchContainer evaluation_reminder_area = UIBranchContainer.make(form, "evaluation_reminder_days:"); - // email reminder control - reminderDaysSelect = UISelect.make(evaluation_reminder_area, "reminderDays", EvalToolConstants.REMINDER_EMAIL_DAYS_VALUES, - EvalToolConstants.REMINDER_EMAIL_DAYS_LABELS, evaluationOTP + "reminderDays").setMessageKeys(); - if ( EvalUtils.checkStateAfter(currentEvalState, EvalConstants.EVALUATION_STATE_GRACEPERIOD, true) ) { - RSFUtils.disableComponent(reminderDaysSelect); - } + if (!consolidatedEmailsEnabled.booleanValue()) { + UIBranchContainer evaluation_reminder_area = UIBranchContainer.make(form, "evaluation_reminder_days:"); + // email reminder control + String[] reminderValues = EvalToolConstants.REMINDER_EMAIL_DAYS_VALUES; + String[] reminderLabels = EvalToolConstants.REMINDER_EMAIL_DAYS_LABELS; + if (userAdmin) { + // super admin can use the special testing setting + reminderValues = ArrayUtils.appendArray(reminderValues, "-2"); + reminderLabels = ArrayUtils.appendArray(reminderLabels, "evalsettings.reminder.days.-2"); + } + reminderDaysSelect = UISelect.make(evaluation_reminder_area, "reminderDays", + reminderValues, + reminderLabels, + evaluationOTP + "reminderDays").setMessageKeys(); + if (EvalUtils.checkStateAfter(currentEvalState, EvalConstants.EVALUATION_STATE_GRACEPERIOD, true)) { + RSFUtils.disableComponent(reminderDaysSelect); + } } // email reminder template link @@ -619,8 +625,7 @@ String binding, Boolean systemSetting, UIForm form, boolean disabled) { if (systemSetting == null) { UIBoundBoolean checkbox = UIBoundBoolean.make(parent, rsfId, binding); - UIMessage.make(parent, rsfId + "_label", "evalsettings." + rsfId + ".label") - .decorate( new UILabelTargetDecorator(checkbox) ); + UIMessage.make(parent, rsfId + "_label", "evalsettings." + rsfId + ".label"); if (disabled) { RSFUtils.disableComponent(checkbox); // disable the control } Index: tool/src/java/org/sakaiproject/evaluation/tool/producers/AdministrateEmailProducer.java =================================================================== --- tool/src/java/org/sakaiproject/evaluation/tool/producers/AdministrateEmailProducer.java (revision 81089) +++ tool/src/java/org/sakaiproject/evaluation/tool/producers/AdministrateEmailProducer.java (working copy) @@ -49,8 +49,8 @@ return VIEW_ID; } - public static final String EMAIL_SETTINGS_WBL = "emailSettingsBean"; - + public static final String EMAIL_SETTINGS_WBL = "emailSettingsBean"; + // Spring injection private EvalCommonLogic commonLogic; public void setCommonLogic(EvalCommonLogic commonLogic) { @@ -61,11 +61,11 @@ public void setEvalSettings(EvalSettings evalSettings) { this.evalSettings = evalSettings; } - + private NavBarRenderer navBarRenderer; public void setNavBarRenderer(NavBarRenderer navBarRenderer) { - this.navBarRenderer = navBarRenderer; - } + this.navBarRenderer = navBarRenderer; + } private FormatAwareDateInputEvolver dateevolver; public void setDateEvolver(FormatAwareDateInputEvolver dateevolver) { @@ -84,24 +84,24 @@ if (!userAdmin) { // Security check and denial throw new SecurityException( - "Non-admin users may not access this page"); + "Non-admin users may not access this page"); } navBarRenderer.makeNavBar(tofill, NavBarRenderer.NAV_ELEMENT, this.getViewID()); Boolean useConsolidatedNotifications = (Boolean) evalSettings.get(EvalSettings.ENABLE_SINGLE_EMAIL_PER_STUDENT); if(useConsolidatedNotifications == null) { - useConsolidatedNotifications = new Boolean(false); + useConsolidatedNotifications = new Boolean(false); } UIForm emailForm = UIForm.make(tofill, "emailcontrol-form"); - - String[] options = new String[]{Boolean.toString(false), Boolean.toString(true)}; + + String[] options = new String[]{Boolean.toString(false), Boolean.toString(true)}; String[] labels = new String[]{"controlemail.individual.emails", "controlemail.consolidated.emails"}; UISelect emailTypeChoice = UISelect.make(emailForm, "email-type-choice", options, labels, - PathUtil.composePath(EMAIL_SETTINGS_WBL, EvalSettings.ENABLE_SINGLE_EMAIL_PER_STUDENT), - Boolean.toString(useConsolidatedNotifications)).setMessageKeys(); + PathUtil.composePath(EMAIL_SETTINGS_WBL, EvalSettings.ENABLE_SINGLE_EMAIL_PER_STUDENT), + Boolean.toString(useConsolidatedNotifications)).setMessageKeys(); //AdministrateProducer.makeSelect(emailForm, "email-type-choice", options, labels, EvalSettings.ENABLE_SINGLE_EMAIL_PER_STUDENT, true); UISelectChoice.make(emailForm, "email-type-choice-individual", emailTypeChoice.getFullID(), 0); UISelectLabel.make(emailForm, "email-type-choice-individual-label", emailTypeChoice.getFullID(), 0); @@ -110,87 +110,98 @@ EvalToolConstants.REMINDER_EMAIL_DAYS_VALUES, EvalToolConstants.REMINDER_EMAIL_DAYS_LABELS, EMAIL_SETTINGS_WBL, EvalSettings.DEFAULT_EMAIL_REMINDER_FREQUENCY, true); - - /* enable an email to be sent to the admin/helpdesk address when a email job has completed. */ + + /* enable an email to be sent to the admin/helpdesk address when a email job has completed. */ AdministrateProducer.makeBoolean(emailForm, "enable-job-completion-email", EMAIL_SETTINGS_WBL, EvalSettings.ENABLE_JOB_COMPLETION_EMAIL); - - /* enable the updating of reminder status while remiders are running. */ + + /* enable the updating of reminder status while remiders are running. */ AdministrateProducer.makeBoolean(emailForm, "enable-reminder-status", EMAIL_SETTINGS_WBL, EvalSettings.ENABLE_REMINDER_STATUS); UIInput evalTimeToWaitSecs = AdministrateProducer.makeInput(emailForm, "eval-time-to-wait-secs", EMAIL_SETTINGS_WBL, EvalSettings.EVALUATION_TIME_TO_WAIT_SECS); //allow eval begin email notification - eval specific toggle AdministrateProducer.makeBoolean(emailForm, "allow-eval-begin-email", - EMAIL_SETTINGS_WBL, EvalSettings.ALLOW_EVALSPECIFIC_TOGGLE_EMAIL_NOTIFICATION); - + EMAIL_SETTINGS_WBL, EvalSettings.ALLOW_EVALSPECIFIC_TOGGLE_EMAIL_NOTIFICATION); + // control options for consolidated emails - + String nextReminderStr = (String) evalSettings.get(EvalSettings.NEXT_REMINDER_DATE); - - Date nextReminder = null; - if(nextReminderStr == null || nextReminderStr.trim().equals("")) { - nextReminder = new Date(); - } else { - DateFormat df = new SimpleDateFormat("EEE MMM dd kk:mm:ss zzz yyyy"); //DateFormat.getDateTimeInstance(DateFormat.FULL,DateFormat.FULL); - try { - nextReminder = df.parse( nextReminderStr ); - } catch (ParseException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - nextReminder = new Date(); - } - } + Date nextReminder = null; + if(nextReminderStr == null || nextReminderStr.trim().equals("")) { + nextReminder = new Date(); + } else { + DateFormat df = new SimpleDateFormat("EEE MMM dd kk:mm:ss zzz yyyy"); //DateFormat.getDateTimeInstance(DateFormat.FULL,DateFormat.FULL); + try { + nextReminder = df.parse( nextReminderStr ); + } catch (ParseException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + nextReminder = new Date(); + } + } + UISelectChoice.make(emailForm, "email-type-choice-consolidated", emailTypeChoice.getFullID(), 1); UISelectLabel.make(emailForm, "email-type-choice-consolidated-label", emailTypeChoice.getFullID(), 1); - UIBranchContainer oneemail = UIBranchContainer.make(emailForm, "consolidated-email-settings:"); - - AdministrateProducer.makeBoolean(oneemail, "consolidated-send-available", EMAIL_SETTINGS_WBL, EvalSettings.CONSOLIDATED_EMAIL_NOTIFY_AVAILABLE); + UIBranchContainer oneemail = UIBranchContainer.make(emailForm, "consolidated-email-settings:"); + AdministrateProducer.makeBoolean(oneemail, "consolidated-send-available", EMAIL_SETTINGS_WBL, EvalSettings.CONSOLIDATED_EMAIL_NOTIFY_AVAILABLE); + + // EVALSYS-1236 + // overrides logic to send an evaluation available e-mail. Logic contained in EvalJobLogicImpl.jobAction() + // would not send an available email for consolidated e-mails. This setting says send one anyway + AdministrateProducer.makeBoolean(oneemail, "force-send-available-notification-immediately", EMAIL_SETTINGS_WBL, EvalSettings.CONSOLIDATED_FORCE_SEND_AVAILABLE_NOTIFICATION); + + // EVALSYS-1236 + // overrides logic to send a created e-mail to instructors even if the instructor cannot modify the evaluation. + // Logic says that the instructor must be able to add a question or InstructorOpt must not be required + // This setting says it will send a created e-mail regardless + AdministrateProducer.makeBoolean(oneemail, "force-send-created-email", EMAIL_SETTINGS_WBL, EvalSettings.CONSOLIDATED_FORCE_SEND_CREATED_EMAIL); + AdministrateProducer.makeSelect(emailForm, "reminders-frequency-selection", EvalToolConstants.REMINDER_EMAIL_DAYS_VALUES, EvalToolConstants.REMINDER_EMAIL_DAYS_LABELS, EMAIL_SETTINGS_WBL, EvalSettings.SINGLE_EMAIL_REMINDER_DAYS, true); - + AdministrateProducer.makeSelect(oneemail, "consolidated-job-start-time", - EvalToolConstants.PULLDOWN_HOUR_VALUES, - EvalToolConstants.PULLDOWN_HOUR_LABELS, - EMAIL_SETTINGS_WBL, EvalSettings.CONSOLIDATED_EMAIL_DAILY_START_TIME, true); - + EvalToolConstants.PULLDOWN_HOUR_VALUES, + EvalToolConstants.PULLDOWN_HOUR_LABELS, + EMAIL_SETTINGS_WBL, EvalSettings.CONSOLIDATED_EMAIL_DAILY_START_TIME, true); + AdministrateProducer.makeSelect(oneemail, "consolidated-job-start-time-minutes", - EvalToolConstants.PULLDOWN_MINUTE_VALUES, - EvalToolConstants.PULLDOWN_MINUTE_LABELS, - EMAIL_SETTINGS_WBL, EvalSettings.CONSOLIDATED_EMAIL_DAILY_START_MINUTES, true); + EvalToolConstants.PULLDOWN_MINUTE_VALUES, + EvalToolConstants.PULLDOWN_MINUTE_LABELS, + EMAIL_SETTINGS_WBL, EvalSettings.CONSOLIDATED_EMAIL_DAILY_START_MINUTES, true); - UIBranchContainer nextReminderDiv = UIBranchContainer.make(oneemail, "nextReminderDateDiv:"); + UIBranchContainer nextReminderDiv = UIBranchContainer.make(oneemail, "nextReminderDateDiv:"); generateDatePicker(nextReminderDiv,"nextReminderDate",EvalSettings.NEXT_REMINDER_DATE, nextReminder); - - AdministrateProducer.makeSelect(oneemail, "log-progress-every", - EvalToolConstants.PULLDOWN_BATCH_VALUES, - EvalToolConstants.PULLDOWN_BATCH_VALUES, - EMAIL_SETTINGS_WBL, EvalSettings.LOG_PROGRESS_EVERY, false); - AdministrateProducer.makeSelect(oneemail, "email-batch-size", - EvalToolConstants.PULLDOWN_BATCH_VALUES, - EvalToolConstants.PULLDOWN_BATCH_VALUES, - EMAIL_SETTINGS_WBL, EvalSettings.EMAIL_BATCH_SIZE, false); - AdministrateProducer.makeSelect(oneemail, "wait-interval", - EvalToolConstants.PULLDOWN_BATCH_VALUES, - EvalToolConstants.PULLDOWN_BATCH_VALUES, - EMAIL_SETTINGS_WBL, EvalSettings.EMAIL_WAIT_INTERVAL, false); - AdministrateProducer.makeSelect(oneemail, "send-reminders", - EvalToolConstants.REMINDER_EMAIL_DAYS_VALUES, - EvalToolConstants.REMINDER_EMAIL_DAYS_LABELS, - EMAIL_SETTINGS_WBL, EvalSettings.SINGLE_EMAIL_REMINDER_DAYS, true); + AdministrateProducer.makeSelect(oneemail, "log-progress-every", + EvalToolConstants.PULLDOWN_BATCH_VALUES, + EvalToolConstants.PULLDOWN_BATCH_VALUES, + EMAIL_SETTINGS_WBL, EvalSettings.LOG_PROGRESS_EVERY, false); + AdministrateProducer.makeSelect(oneemail, "email-batch-size", + EvalToolConstants.PULLDOWN_BATCH_VALUES, + EvalToolConstants.PULLDOWN_BATCH_VALUES, + EMAIL_SETTINGS_WBL, EvalSettings.EMAIL_BATCH_SIZE, false); + AdministrateProducer.makeSelect(oneemail, "wait-interval", + EvalToolConstants.PULLDOWN_BATCH_VALUES, + EvalToolConstants.PULLDOWN_BATCH_VALUES, + EMAIL_SETTINGS_WBL, EvalSettings.EMAIL_WAIT_INTERVAL, false); + AdministrateProducer.makeSelect(oneemail, "send-reminders", + EvalToolConstants.REMINDER_EMAIL_DAYS_VALUES, + EvalToolConstants.REMINDER_EMAIL_DAYS_LABELS, + EMAIL_SETTINGS_WBL, EvalSettings.SINGLE_EMAIL_REMINDER_DAYS, true); + // Send submission confirmation? AdministrateProducer.makeBoolean(emailForm, "send-submitted", EMAIL_SETTINGS_WBL, EvalSettings.ENABLE_SUBMISSION_CONFIRMATION_EMAIL); - - // control the general email options + + // control the general email options AdministrateProducer.makeBoolean(emailForm, "general-use-admin-from-email", EMAIL_SETTINGS_WBL, EvalSettings.USE_ADMIN_AS_FROM_EMAIL); AdministrateProducer.makeInput(emailForm, "general-helpdesk-email", EMAIL_SETTINGS_WBL, EvalSettings.FROM_EMAIL_ADDRESS); - + //dispose of email by sending to email system, log, or dev/null AdministrateProducer.makeSelect(emailForm, "delivery-option", EvalToolConstants.EMAIL_DELIVERY_VALUES, @@ -198,20 +209,20 @@ EMAIL_SETTINGS_WBL, EvalSettings.EMAIL_DELIVERY_OPTION, false); -// -// //log email To: addresses -// AdministrateProducer.makeBoolean(form, "log-recipients", -// EvalSettings.LOG_EMAIL_RECIPIENTS); -// + // + // //log email To: addresses + // AdministrateProducer.makeBoolean(form, "log-recipients", + // EvalSettings.LOG_EMAIL_RECIPIENTS); + // // Save Settings button UICommand.make(emailForm, "saveSettings", UIMessage.make("administrate.save.settings.button"), PathUtil.buildPath(EMAIL_SETTINGS_WBL, "saveSettings")); - + // this fills in the javascript call UIInitBlock.make(tofill, "initEvalJS", "EvalSystem.addNumericOnly", new Object[] { evalTimeToWaitSecs.getFullID(), "time-wait-errmsg"} ); } - - + + /** * @param parent * @param rsfId @@ -222,6 +233,6 @@ UIInput datePicker = UIInput.make(parent, rsfId + ":", PathUtil.composePath(EMAIL_SETTINGS_WBL, adminkey)); dateevolver.setStyle(FormatAwareDateInputEvolver.DATE_TIME_INPUT); dateevolver.evolveDateInput(datePicker, initValue); -} + } } Index: tool/src/java/org/sakaiproject/evaluation/tool/producers/SummaryProducer.java =================================================================== --- tool/src/java/org/sakaiproject/evaluation/tool/producers/SummaryProducer.java (revision 81089) +++ tool/src/java/org/sakaiproject/evaluation/tool/producers/SummaryProducer.java (working copy) @@ -14,39 +14,25 @@ */ package org.sakaiproject.evaluation.tool.producers; -import java.text.DateFormat; import java.util.ArrayList; -import java.util.Iterator; import java.util.List; -import java.util.Locale; -import java.util.Map; - -import org.sakaiproject.evaluation.beans.EvalBeanUtils; import org.sakaiproject.evaluation.constant.EvalConstants; import org.sakaiproject.evaluation.logic.EvalAuthoringService; import org.sakaiproject.evaluation.logic.EvalCommonLogic; -import org.sakaiproject.evaluation.logic.EvalDeliveryService; import org.sakaiproject.evaluation.logic.EvalEvaluationService; -import org.sakaiproject.evaluation.logic.EvalEvaluationSetupService; import org.sakaiproject.evaluation.logic.EvalSettings; import org.sakaiproject.evaluation.logic.model.EvalGroup; -import org.sakaiproject.evaluation.model.EvalAssignGroup; -import org.sakaiproject.evaluation.model.EvalEvaluation; -import org.sakaiproject.evaluation.model.EvalResponse; +import org.sakaiproject.evaluation.tool.renderers.AdminBoxRenderer; +import org.sakaiproject.evaluation.tool.renderers.BeEvaluatedBoxRenderer; +import org.sakaiproject.evaluation.tool.renderers.EvaluateBoxRenderer; import org.sakaiproject.evaluation.tool.renderers.NavBarRenderer; import org.sakaiproject.evaluation.tool.viewparams.EvalViewParameters; -import org.sakaiproject.evaluation.tool.viewparams.ReportParameters; import org.sakaiproject.evaluation.tool.viewparams.TemplateViewParameters; -import org.sakaiproject.evaluation.utils.EvalUtils; - -import uk.org.ponder.messageutil.MessageLocator; import uk.org.ponder.rsf.components.UIBranchContainer; import uk.org.ponder.rsf.components.UIContainer; -import uk.org.ponder.rsf.components.UIForm; import uk.org.ponder.rsf.components.UIInternalLink; import uk.org.ponder.rsf.components.UIMessage; import uk.org.ponder.rsf.components.UIOutput; -import uk.org.ponder.rsf.components.decorators.UITooltipDecorator; import uk.org.ponder.rsf.flow.jsfnav.NavigationCase; import uk.org.ponder.rsf.flow.jsfnav.NavigationCaseReporter; import uk.org.ponder.rsf.view.ComponentChecker; @@ -84,42 +70,32 @@ this.evaluationService = evaluationService; } - private EvalEvaluationSetupService evaluationSetupService; - public void setEvaluationSetupService(EvalEvaluationSetupService evaluationSetupService) { - this.evaluationSetupService = evaluationSetupService; - } - - private EvalDeliveryService deliveryService; - public void setDeliveryService(EvalDeliveryService deliveryService) { - this.deliveryService = deliveryService; - } - private EvalSettings settings; public void setSettings(EvalSettings settings) { this.settings = settings; } - private EvalBeanUtils evalBeanUtils; - public void setEvalBeanUtils(EvalBeanUtils evalBeanUtils) { - this.evalBeanUtils = evalBeanUtils; + private NavBarRenderer navBarRenderer; + public void setNavBarRenderer(NavBarRenderer navBarRenderer) { + this.navBarRenderer = navBarRenderer; } - - private MessageLocator messageLocator; - public void setMessageLocator(MessageLocator messageLocator) { - this.messageLocator = messageLocator; + + private AdminBoxRenderer adminBoxRenderer; + public void setAdminBoxRenderer(AdminBoxRenderer adminBoxRenderer) { + this.adminBoxRenderer = adminBoxRenderer; } - private Locale locale; - public void setLocale(Locale locale) { - this.locale = locale; + private BeEvaluatedBoxRenderer beEvaluatedBoxRenderer; + public void setBeEvaluatedBoxRenderer(BeEvaluatedBoxRenderer beEvaluatedBoxRenderer) { + this.beEvaluatedBoxRenderer = beEvaluatedBoxRenderer; } - - private NavBarRenderer navBarRenderer; - public void setNavBarRenderer(NavBarRenderer navBarRenderer) { - this.navBarRenderer = navBarRenderer; - } - /* + private EvaluateBoxRenderer evaluateBoxRenderer; + public void setEvaluateBoxRenderer(EvaluateBoxRenderer evaluateBoxRenderer) { + this.evaluateBoxRenderer = evaluateBoxRenderer; + } + + /* * (non-Javadoc) * * @see @@ -131,18 +107,15 @@ // local variables used in the render logic String currentUserId = commonLogic.getCurrentUserId(); - String currentGroup = commonLogic.getCurrentEvalGroup(); - boolean userAdmin = commonLogic.isUserAdmin(currentUserId); + //boolean userAdmin = commonLogic.isUserAdmin(currentUserId); boolean createTemplate = authoringService.canCreateTemplate(currentUserId); boolean beginEvaluation = evaluationService.canBeginEvaluation(currentUserId); - DateFormat df = DateFormat.getDateInstance(DateFormat.MEDIUM, locale); - navBarRenderer.makeNavBar(tofill, NavBarRenderer.NAV_ELEMENT, this.getViewID()); - + if (beginEvaluation) { - // show instructor instructions - UIMessage.make(tofill, "instructor-instructions", "summary.instructor.instruction"); + // show instructor instructions + UIMessage.make(tofill, "instructor-instructions", "summary.instructor.instruction"); } /* @@ -156,254 +129,24 @@ // add other stuff } - /* - * for the evaluations taking box - * http://jira.sakaiproject.org/jira/browse/EVALSYS-618 - * Changed this to reduce the load on the services and make this load faster - */ - List evalsToTake = evaluationSetupService.getEvaluationsForUser(currentUserId, true, null, null); - UIBranchContainer evalBC = UIBranchContainer.make(tofill, "evaluationsBox:"); - if (evalsToTake.size() > 0) { - // build an array of evaluation ids - Long[] evalIds = new Long[evalsToTake.size()]; - for (int i = 0; i < evalsToTake.size(); i++) { - evalIds[i] = ((EvalEvaluation) evalsToTake.get(i)).getId(); - } + // + // for the evaluations taking box + // http://jira.sakaiproject.org/jira/browse/EVALSYS-618 + // Changed this to reduce the load on the services and make this load faster + evaluateBoxRenderer.renderBox(tofill, currentUserId); - List evalResponses = deliveryService.getEvaluationResponsesForUser(currentUserId, evalIds, null); - - for (Iterator itEvals = evalsToTake.iterator(); itEvals.hasNext();) { - EvalEvaluation eval = (EvalEvaluation) itEvals.next(); - - // make sure state is up to date http://jira.sakaiproject.org/browse/EVALSYS-1013 - String evalState = evaluationService.returnAndFixEvalState(eval, true); - // skip evaluations that are in a non-active state - if(! EvalConstants.EVALUATION_STATE_ACTIVE.equals(evalState)){ - continue; - } - - UIBranchContainer evalrow = UIBranchContainer.make(evalBC, "evaluationsList:", eval.getId().toString()); - - UIOutput.make(evalrow, "evaluationTitleTitle", EvalUtils.makeMaxLengthString(eval.getTitle(), 70)); - - for (EvalAssignGroup eag : eval.getEvalAssignGroups()) { - EvalGroup group = commonLogic.makeEvalGroupObject(eag.getEvalGroupId()); - if (EvalConstants.GROUP_TYPE_INVALID.equals(group.type)) { - continue; // skip processing for invalid groups - } - - String groupId = group.evalGroupId; - String title = EvalUtils.makeMaxLengthString(group.title, 50); - String status = "unknown.caps"; - - // find the object in the list matching the evalGroupId and evalId, - // leave as null if not found -AZ - EvalResponse response = null; - for (int k = 0; k < evalResponses.size(); k++) { - EvalResponse er = (EvalResponse) evalResponses.get(k); - if (groupId.equals(er.getEvalGroupId()) - && eval.getId().equals(er.getEvaluation().getId())) { - response = er; - break; - } - } - - if (groupId.equals(currentGroup)) { - // TODO - do something when the evalGroupId matches - } - - UIBranchContainer evalcourserow = UIBranchContainer.make(evalrow, "evaluationsCourseList:", groupId); - - // set status - if (response != null && response.getEndTime() != null) { - // there is a response for this eval/group - status = "summary.status.completed"; - if (eval.getModifyResponsesAllowed().booleanValue()) { - // can modify responses so show the link still - // take eval link when pending - UIInternalLink.make(evalcourserow, "evaluationCourseLink", title, - new EvalViewParameters(TakeEvalProducer.VIEW_ID, - eval.getId(), response.getId(), groupId)); - } else { - // show title only when completed and cannot - // modify - UIOutput.make(evalcourserow, "evaluationCourseLink_disabled", title); - } - } else if (response != null && response.getEndTime() == null) { - // there is an in progress for this eval/group - UIInternalLink.make(evalcourserow, "evaluationCourseLink", title, - new EvalViewParameters(TakeEvalProducer.VIEW_ID, - eval.getId(), response.getId(), groupId)); - status = "summary.status.inprogress"; - } else { - // no response yet for this eval/group - // take eval link when pending - UIInternalLink.make(evalcourserow, "evaluationCourseLink", title, - new EvalViewParameters(TakeEvalProducer.VIEW_ID, eval.getId(), - groupId)); - status = "summary.status.pending"; - } - UIMessage.make(evalcourserow, "evaluationCourseStatus", status); - // moved down here as requested by UI design - UIOutput.make(evalcourserow, "evaluationStartDate", df.format(eval.getStartDate())); - UIOutput.make(evalcourserow, "evaluationDueDate", df.format(eval.getDueDate())); - } - } - } else { - UIMessage.make(tofill, "evaluationsNone", "summary.evaluations.none"); - } - - // determine whether instructor widget is enabled + // show evaluations that the user is being evaluated in boolean showEvaluateeBox = ((Boolean) settings.get(EvalSettings.ENABLE_EVALUATEE_BOX)).booleanValue(); - boolean evalsToShow = false; if(showEvaluateeBox) { - // need to determine if there are any evals in which the user can be evaluated - List evalsForInstructor = this.evaluationSetupService.getEvaluationsForEvaluatee(currentUserId); - if(evalsForInstructor == null || evalsForInstructor.isEmpty()) { - // no evals found - // show a message saying no evals? - } else { - // evals found; show the widget - UIBranchContainer evalResponsesBC = UIBranchContainer.make(tofill, "evalResponsesBox:"); - UIForm evalResponsesForm = UIForm.make(evalResponsesBC , "evalResponsesForm"); - - UIBranchContainer evalResponseTable = null; - // build an array of evaluation ids - Long[] evalIds = new Long[evalsForInstructor.size()]; - int i = 0; - for(EvalEvaluation eval : evalsForInstructor) { - evalIds[i++] = eval.getId(); - } - - // get the eval groups - Map> evalGroups = evaluationService.getEvalGroupsForEval(evalIds, false, null); - - // show a list of evals with four columns: - for(EvalEvaluation eval : evalsForInstructor) { - //is this eval partial, in-queue, active or grace period? - if(EvalConstants.EVALUATION_STATE_INQUEUE.equals(eval.getState()) || - EvalConstants.EVALUATION_STATE_PARTIAL.equals(eval.getState()) || - EvalConstants.EVALUATION_STATE_ACTIVE.equals(eval.getState()) || - EvalConstants.EVALUATION_STATE_GRACEPERIOD.equals(eval.getState())) { - //there is an eval in-queue, active or grace period - evalsToShow = true; - if(evalResponseTable == null) { - evalResponseTable = UIBranchContainer.make(evalResponsesForm, "evalResponseTable:"); - // show four column headings - UIMessage.make(evalResponseTable, "evalresponses-header-title","summary.header.title"); - UIMessage.make(evalResponseTable, "evalresponses-header-status", "summary.header.status"); - UIMessage.make(evalResponseTable, "evalresponses-header-date", "summary.header.date"); - UIMessage.make(evalResponseTable, "evalresponses-header-responses", "summary.header.responses"); - - } - //set display values for this eval - String evalState = evaluationService.updateEvaluationState(eval.getId()); - //show one link per group assigned to in-queue, active or grace period eval - List groups = evalGroups.get(eval.getId()); - for(EvalGroup group : groups) { - UIBranchContainer evalrow = UIBranchContainer.make(evalResponseTable,"evalResponsesList:"); - - String evalTitle = messageLocator.getMessage("summary.responses.eval.title", new String[]{ group.title, eval.getTitle() }); - UIInternalLink.make(evalrow, "evalResponsesTitleLink_preview", - EvalUtils.makeMaxLengthString(evalTitle, 70), - new EvalViewParameters(PreviewEvalProducer.VIEW_ID, eval.getId(), group.evalGroupId));//view params - //UIOutput.make(evalrow, "evalResponsesStatus", eval.getState()); - - makeDateComponent(evalrow, eval, evalState, "evalResponsesDateLabel", "evalResponsesDate", "evalResponsesStatus"); - - int responsesCount = deliveryService.countResponses(eval.getId(), group.evalGroupId, true); - int enrollmentsCount = evaluationService.countParticipantsForEval(eval.getId(), new String[]{group.evalGroupId}); - UIMessage.make(evalrow, "evalResponsesDisplay", "summary.responses.counts", new Integer[]{responsesCount,enrollmentsCount}); - }//link per group - }//partial, in-queue, active or grace period eval - }//for evals iterator - if(!evalsToShow) { - UIMessage.make(evalResponsesForm, "summary-be-evaluated-none", "summary.be.evaluated.none"); - } - - }//there are evals for instructor + beEvaluatedBoxRenderer.renderBox(tofill, currentUserId); } - /* - * for the evaluations admin box - */ - Boolean showAdministratingBox = (Boolean) settings.get(EvalSettings.ENABLE_ADMINISTRATING_BOX); - if(showAdministratingBox != null && showAdministratingBox == true) { - - Boolean instViewResults = (Boolean) settings.get(EvalSettings.INSTRUCTOR_ALLOWED_VIEW_RESULTS); - if (instViewResults == null) { - instViewResults = true; - } // if configurable then we will assume some are probably shared - - List evals = evaluationSetupService.getVisibleEvaluationsForUser(currentUserId, true, instViewResults, false); - /* - * If the person is an admin, then just point new evals to existing - * object. If the person is not an admin then only show owned evals + - * not-owned evals that are available for viewing results. - */ - List newEvals = evals; - if (instViewResults && !userAdmin) { - newEvals = new ArrayList(); - for (EvalEvaluation evaluation : evals) { - // Add the owned evals - if (currentUserId.equals(evaluation.getOwner())) { - newEvals.add(evaluation); - } else { - // From the not-owned evals show those that are available - // for viewing results - String forcedViewableState = calculateViewability(evaluation.getState()); - if (EvalUtils.checkStateAfter(forcedViewableState, EvalConstants.EVALUATION_STATE_VIEWABLE, true)) { - newEvals.add(evaluation); - } - } - } - } - - if (!newEvals.isEmpty()) { - UIBranchContainer evalAdminBC = UIBranchContainer.make(tofill, "evalAdminBox:"); - // Temporary fix for http://www.caret.cam.ac.uk/jira/browse/CTL-583 - // (need to send them to the eval control page eventually) -AZ - if (beginEvaluation) { - UIInternalLink.make(evalAdminBC, "evaladmin-title-link", UIMessage.make("summary.evaluations.admin"), new SimpleViewParameters( - ControlEvaluationsProducer.VIEW_ID)); - } else { - UIMessage.make(evalAdminBC, "evaladmin-title", "summary.evaluations.admin"); - } - UIForm evalAdminForm = UIForm.make(evalAdminBC, "evalAdminForm"); + // show evaluations that user is administering + Boolean showAdministratingBox = (Boolean) settings.get(EvalSettings.ENABLE_ADMINISTRATING_BOX); + if(showAdministratingBox != null && showAdministratingBox == true) { + adminBoxRenderer.renderItem(tofill, "evalAdminBox"); + } //showAdministratingBox true - UIMessage.make(evalAdminForm, "evaladmin-header-title", "summary.header.title"); - UIMessage.make(evalAdminForm, "evaladmin-header-status", "summary.header.status"); - UIMessage.make(evalAdminForm, "evaladmin-header-date", "summary.header.date"); - - for (Iterator iter = newEvals.iterator(); iter.hasNext();) { - EvalEvaluation eval = (EvalEvaluation) iter.next(); - - UIBranchContainer evalrow = UIBranchContainer.make(evalAdminForm, "evalAdminList:", eval.getId().toString()); - - String evalState = evaluationService.returnAndFixEvalState(eval, true); - evalState = calculateViewability(evalState); - - makeDateComponent(evalrow, eval, evalState, "evalAdminDateLabel", "evalAdminDate", "evalAdminStatus"); - - /* - * 1) if a evaluation is queued, title link go to EditSettings - * page with populated data 2) if a evaluation is active, title - * link go to EditSettings page with populated data but start - * date should be disabled 3) if a evaluation is closed, title - * link go to previewEval page with populated data - */ - if (EvalUtils.checkStateAfter(evalState, EvalConstants.EVALUATION_STATE_CLOSED, true)) { - UIInternalLink.make(evalrow, "evalAdminTitleLink_preview", EvalUtils.makeMaxLengthString(eval.getTitle(), 70), new EvalViewParameters( - PreviewEvalProducer.VIEW_ID, eval.getId(), eval.getTemplate().getId())); - } else { - UIInternalLink.make(evalrow, "evalAdminTitleLink_edit", EvalUtils.makeMaxLengthString(eval.getTitle(), 70), new EvalViewParameters( - EvaluationSettingsProducer.VIEW_ID, eval.getId())); - } - - } - } - } //showAdministratingBox true - /* * Site/Group listing box */ @@ -472,89 +215,6 @@ } - private String calculateViewability(String state) { - Boolean viewResultsIgnoreDate = (Boolean) settings.get(EvalSettings.VIEW_SURVEY_RESULTS_IGNORE_DATES); - - if(viewResultsIgnoreDate != null && viewResultsIgnoreDate) { - if(EvalConstants.EVALUATION_STATE_ACTIVE.equals(state) || - EvalConstants.EVALUATION_STATE_GRACEPERIOD.equals(state) || - EvalConstants.EVALUATION_STATE_CLOSED.equals(state)) { - - return EvalConstants.EVALUATION_STATE_VIEWABLE; - } - } - - return state; - } - - /** - * @param evalrow - * @param eval - * @param evalState - * @param evalDateLabel - * @param evalDateItem - */ - protected void makeDateComponent(UIContainer evalrow, - EvalEvaluation eval, String evalState, - String evalDateLabel, String evalDateItem, String evalStatusItem) { - // use a date which is related to the current users locale - DateFormat df = DateFormat.getDateInstance(DateFormat.MEDIUM, locale); - if (EvalConstants.EVALUATION_STATE_INQUEUE.equals(evalState)) { - // If we are in the queue we are yet to start, - // so say when we will - UIMessage.make(evalrow, evalDateLabel, "summary.label.starts"); - UIOutput.make(evalrow, evalDateItem, df.format(eval.getStartDate())); - - UIMessage.make(evalrow, evalStatusItem, "summary.status." + evalState); - } else if (EvalConstants.EVALUATION_STATE_ACTIVE.equals(evalState)) { - // Active evaluations can either be open forever or close at - // some point: - if (eval.getDueDate() != null) { - UIMessage.make(evalrow, evalDateLabel, "summary.label.due"); - UIOutput.make(evalrow, evalDateItem, df.format(eval.getDueDate())); - // Should probably add something here if there's a grace period - } else { - UIMessage.make(evalrow, evalDateLabel, "summary.label.nevercloses"); - } - - UIMessage.make(evalrow, evalStatusItem, "summary.status." + evalState); - } else if (EvalConstants.EVALUATION_STATE_GRACEPERIOD.equals(evalState)) { - // Evaluations can have a grace period, if so that must - // close at some point; - // Grace periods never remain open forever - UIMessage.make(evalrow, evalDateLabel, "summary.label.gracetill"); - UIOutput.make(evalrow, evalDateItem, df.format(eval.getSafeStopDate())); - - UIMessage.make(evalrow, evalStatusItem, "summary.status." + evalState); - } else if (EvalConstants.EVALUATION_STATE_CLOSED.equals(evalState)) { - // if an evaluation is closed then it is not yet viewable - // and ViewDate must have been set - UIMessage.make(evalrow, evalDateLabel, "summary.label.resultsviewableon"); - UIOutput.make(evalrow, evalDateItem, df.format(eval.getSafeViewDate())); - - UIMessage.make(evalrow, evalStatusItem, "summary.status." + evalState); - } else if (EvalConstants.EVALUATION_STATE_VIEWABLE.equals(evalState)) { - // TODO if an evaluation is viewable we may want to notify - // if there are instructor/student dates - UIMessage.make(evalrow, evalDateLabel, "summary.label.resultsviewablesince"); - UIOutput.make(evalrow, evalDateItem, df.format(eval.getSafeViewDate())); - - int responsesCount = deliveryService.countResponses(eval.getId(), null, true); - int enrollmentsCount = evaluationService.countParticipantsForEval(eval.getId(), null); - int responsesNeeded = evalBeanUtils.getResponsesNeededToViewForResponseRate(responsesCount, enrollmentsCount); - if (responsesNeeded == 0) { - UIInternalLink.make(evalrow, "viewReportLink", UIMessage.make("viewreport.page.title"), new ReportParameters( - ReportChooseGroupsProducer.VIEW_ID, eval.getId())); - } else { - UIMessage.make(evalrow, evalStatusItem, "summary.status." + evalState).decorate( - new UITooltipDecorator(UIMessage.make("controlevaluations.eval.report.awaiting.responses", new Object[] { responsesNeeded }))); - } - } else { - UIMessage.make(evalrow, evalDateLabel, "summary.label.fallback"); - UIOutput.make(evalrow, evalDateItem, df.format(eval.getStartDate())); - } - } - @SuppressWarnings({ "unchecked", "rawtypes" }) public List reportNavigationCases() { List i = new ArrayList(); Index: tool/src/java/org/sakaiproject/evaluation/tool/producers/PreviewItemProducer.java =================================================================== --- tool/src/java/org/sakaiproject/evaluation/tool/producers/PreviewItemProducer.java (revision 81089) +++ tool/src/java/org/sakaiproject/evaluation/tool/producers/PreviewItemProducer.java (working copy) @@ -24,11 +24,12 @@ import org.sakaiproject.evaluation.tool.utils.RenderingUtils; import org.sakaiproject.evaluation.tool.viewparams.ItemViewParameters; import org.sakaiproject.evaluation.utils.TemplateItemDataList; +import org.sakaiproject.evaluation.utils.TemplateItemDataList.DataTemplateItem; import org.sakaiproject.evaluation.utils.TemplateItemUtils; -import org.sakaiproject.evaluation.utils.TemplateItemDataList.DataTemplateItem; import uk.org.ponder.rsf.components.UIContainer; -import uk.org.ponder.rsf.components.UIMessage; +import uk.org.ponder.rsf.content.ContentTypeInfoRegistry; +import uk.org.ponder.rsf.content.ContentTypeReporter; import uk.org.ponder.rsf.view.ComponentChecker; import uk.org.ponder.rsf.viewstate.ViewParameters; import uk.org.ponder.rsf.viewstate.ViewParamsReporter; @@ -40,7 +41,7 @@ * @author Aaron Zeckoski (aaronz@vt.edu) * @author Kapil Ahuja (kahuja@vt.edu) */ -public class PreviewItemProducer extends EvalCommonProducer implements ViewParamsReporter { +public class PreviewItemProducer extends EvalCommonProducer implements ViewParamsReporter, ContentTypeReporter { public static final String VIEW_ID = "preview_item"; public String getViewID() { @@ -68,16 +69,38 @@ EvalTemplateItem templateItem = null; if (previewItemViewParams.templateItemId != null) { templateItem = authoringService.getTemplateItemById(previewItemViewParams.templateItemId); + } else if (previewItemViewParams.itemId != null) { EvalItem item = authoringService.getItemById(previewItemViewParams.itemId); templateItem = TemplateItemUtils.makeTemplateItem(item); if (templateItem.getId() == null){ - templateItem.setId(item.getId()); + templateItem.setId(item.getId()); } + } else { throw new IllegalArgumentException("Must have itemId or templateItemId to do preview"); } + // override values if they are set (this is for live previews) + if (previewItemViewParams.scaleDisplay != null) { + templateItem.setScaleDisplaySetting(previewItemViewParams.scaleDisplay); + } + if (previewItemViewParams.na != null) { + templateItem.setUsesNA(previewItemViewParams.na); + } + if (previewItemViewParams.compulsory != null) { + templateItem.setCompulsory(previewItemViewParams.compulsory); + } + if (previewItemViewParams.showComment != null) { + templateItem.setUsesComment(previewItemViewParams.showComment); + } + if (previewItemViewParams.text != null) { + templateItem.getItem().setItemText(previewItemViewParams.text); + } + if (previewItemViewParams.textLines != null) { + templateItem.setDisplayRows(previewItemViewParams.textLines); + } + // use the renderer evolver to show the item List templateItems = new ArrayList(); templateItems.add(templateItem); @@ -86,11 +109,12 @@ } TemplateItemDataList tidl = new TemplateItemDataList(templateItems, null, null, null); DataTemplateItem dti = tidl.getDataTemplateItem(templateItem.getId()); + itemRenderer.renderItem(tofill, "previewed-item:", null, templateItem, templateItem.getDisplayOrder(), true, RenderingUtils.makeRenderProps(dti, null, null, null) ); // render the close button - UIMessage.make(tofill, "close-button", "general.close.window.button"); + //UIMessage.make(tofill, "close-button", "general.close.window.button"); } /* (non-Javadoc) @@ -100,4 +124,11 @@ return new ItemViewParameters(); } + /* (non-Javadoc) + * @see uk.org.ponder.rsf.content.ContentTypeReporter#getContentType() + */ + public String getContentType() { + return ContentTypeInfoRegistry.HTML_FRAGMENT; + } + } \ No newline at end of file Index: tool/src/java/org/sakaiproject/evaluation/tool/producers/ModifyBlockProducer.java =================================================================== --- tool/src/java/org/sakaiproject/evaluation/tool/producers/ModifyBlockProducer.java (revision 81089) +++ tool/src/java/org/sakaiproject/evaluation/tool/producers/ModifyBlockProducer.java (working copy) @@ -230,17 +230,6 @@ itemPath = "templateItemWBL." + blockId; - // this sets the ideal color setting - if ((firstTemplateItem.getScaleDisplaySetting() != null) - && (firstTemplateItem.getScaleDisplaySetting() - .equals(EvalConstants.ITEM_SCALE_DISPLAY_STEPPED_COLORED) || - firstTemplateItem.getScaleDisplaySetting() - .equals(EvalConstants.ITEM_SCALE_DISPLAY_MATRIX_COLORED))) { - UIBoundBoolean.make(form, "idealColor", "#{templateBBean.idealColor}", Boolean.TRUE); - } else { - UIBoundBoolean.make(form, "idealColor", "#{templateBBean.idealColor}", null); - } - /* * If the system setting (admin setting) for * "EvalSettings.NOT_AVAILABLE_ALLOWED" is set as true then only we need to show the @@ -355,11 +344,6 @@ String scaleDisplaySetting = EvalConstants.ITEM_SCALE_DISPLAY_MATRIX; if (modify && blockItemList.size() == 1) { scaleDisplaySetting = blockItemList.get(0).getScaleDisplaySetting(); - if (EvalConstants.ITEM_SCALE_DISPLAY_STEPPED_COLORED.equals(scaleDisplaySetting)) { - scaleDisplaySetting = EvalConstants.ITEM_SCALE_DISPLAY_STEPPED; - } else if (EvalConstants.ITEM_SCALE_DISPLAY_MATRIX_COLORED.equals(scaleDisplaySetting)) { - scaleDisplaySetting = EvalConstants.ITEM_SCALE_DISPLAY_MATRIX; - } } renderScaleDisplaySelect(form, commonDisplayOTP, scaleDisplaySetting, EvalToolConstants.SCALE_DISPLAY_GROUP_SETTING_VALUES, Index: tool/src/java/org/sakaiproject/evaluation/tool/producers/ModifyItemProducer.java =================================================================== --- tool/src/java/org/sakaiproject/evaluation/tool/producers/ModifyItemProducer.java (revision 81089) +++ tool/src/java/org/sakaiproject/evaluation/tool/producers/ModifyItemProducer.java (working copy) @@ -53,7 +53,6 @@ import uk.org.ponder.rsf.components.UISelectChoice; import uk.org.ponder.rsf.components.UISelectLabel; import uk.org.ponder.rsf.components.decorators.UIDisabledDecorator; -import uk.org.ponder.rsf.components.decorators.UILabelTargetDecorator; import uk.org.ponder.rsf.evolvers.BoundedDynamicListInputEvolver; import uk.org.ponder.rsf.flow.ARIResult; import uk.org.ponder.rsf.flow.ActionResultInterceptor; @@ -70,7 +69,6 @@ * * @author Aaron Zeckoski (aaronz@vt.edu) */ -@SuppressWarnings("deprecation") public class ModifyItemProducer extends EvalCommonProducer implements ViewParamsReporter, ActionResultInterceptor { public static final String VIEW_ID = "modify_item"; @@ -104,7 +102,7 @@ this.hierarchyNodeSelectorRenderer = hierarchyNodeSelectorRenderer; } - /* (non-Javadoc) + /* (non-Javadoc) * @see uk.org.ponder.rsf.view.ComponentProducer#fillComponents(uk.org.ponder.rsf.components.UIContainer, uk.org.ponder.rsf.viewstate.ViewParameters, uk.org.ponder.rsf.view.ComponentChecker) */ public void fill(UIContainer tofill, ViewParameters viewparams, ComponentChecker checker) { @@ -112,7 +110,7 @@ // local variables used in the render logic String currentUserId = commonLogic.getCurrentUserId(); boolean userAdmin = commonLogic.isUserAdmin(currentUserId); - + // create the form to allow submission of this item UIForm form = UIForm.make(tofill, "item-form"); @@ -131,7 +129,7 @@ String itemOwnerName = null; // this is the name of the owner of the item EvalScale currentScale = null; // this is the current scale (if there is one) - + /* these keep track of whether items are locked, we are not tracking TIs because * the user should not be able to get here if the template is locked, if they did then * they cheated so they can get an exception, we don't track scales since if the item @@ -146,12 +144,12 @@ Boolean compulsory = null; //whether or no this question must be answered Long scaleId = null; // this holds the current scale id if there is one Long itemGroupId = null; // this holds the current eval item group id if there is one - EVALSYS-1026 - - + + Boolean isGrouped = (groupItemId != null && groupItemId == -1l ); //We are working with an existing child item Boolean isGroupable = ( ! isGrouped && groupItemId != null); - - // now we validate the incoming view params + + // now we validate the incoming view params if (templateId == null && templateItemId != null) { throw new IllegalArgumentException("templateId cannot be null when modifying template items, must pass in a valid template id"); } @@ -175,14 +173,14 @@ form.parameters.add( new UIELBinding(templateItemOTP + "template", ELReference.make(templateOTP + templateId)) ); } - + //>>> if ( isGroupable ){ - // New child item - List groupedItemList = authoringService.getBlockChildTemplateItemsForBlockParent(groupItemId, false); - EvalTemplateItem itemClone = groupedItemList.get(1); - EvalItem item = itemClone.getItem(); - form.parameters.add( + // New child item + List groupedItemList = authoringService.getBlockChildTemplateItemsForBlockParent(groupItemId, false); + EvalTemplateItem itemClone = groupedItemList.get(1); + EvalItem item = itemClone.getItem(); + form.parameters.add( new UIELBinding(itemOTP + "sharing", item.getSharing()) ); form.parameters.add( new UIELBinding(itemOTP + "scale.id", item.getScale().getId()) ); @@ -198,12 +196,12 @@ new UIELBinding(itemOTP + "usesNA", item.getUsesNA()) ); form.parameters.add( new UIELBinding(itemOTP + "classification", item.getClassification()) ); - + // add group item id form.parameters.add( - new UIELBinding("templateBBean.groupItemId", groupItemId) ); + new UIELBinding("templateBBean.groupItemId", groupItemId) ); }else{ - // add binding for the item classification + // add binding for the item classification form.parameters.add( new UIELBinding(itemOTP + "classification", itemClassification) ); } @@ -255,7 +253,7 @@ itemOTP = templateItemOTP + "item."; commonDisplayOTP = templateItemOTP; }else if (isGrouped){ - // Editing an existing child item + // Editing an existing child item EvalTemplateItem templateItem = authoringService.getTemplateItemById(templateItemId); if (templateItem == null) { throw new IllegalArgumentException("Invalid template item id passed in by VP: " + templateItemId); @@ -284,8 +282,8 @@ new UIELBinding(itemOTP + "classification", templateItem.getItem().getClassification()) ); form.parameters.add( new UIELBinding(itemOTP + "displayRows", templateItem.getDisplayRows() != null ? templateItem.getDisplayRows().toString() : null ) ); - - + + } // now we begin with the rendering logic @@ -382,86 +380,86 @@ List itemGroups = authoringService.getAllItemGroups(currentUserId, true); UIBranchContainer showItemExpert = UIBranchContainer.make(form, "show-item-expert:"); - + if (userAdmin && templateId == null && ! isGroupable) { // only show the expert items if the user is an admin AND we are modifying the item only //UIBranchContainer showItemExpert = UIBranchContainer.make(form, "show-item-expert:"); - Boolean useExpertItems = (Boolean) settings.get(EvalSettings.USE_EXPERT_ITEMS); + Boolean useExpertItems = (Boolean) settings.get(EvalSettings.USE_EXPERT_ITEMS); if (useExpertItems) { - UIMessage.make(showItemExpert, "item-expert-header", "modifyitem.item.expert.header"); - UIMessage.make(showItemExpert, "item-expert-instruction", "modifyitem.item.expert.instruction"); - UIBoundBoolean.make(showItemExpert, "item-expert", itemOTP + "expert", null); + UIMessage.make(showItemExpert, "item-expert-header", "modifyitem.item.expert.header"); + UIMessage.make(showItemExpert, "item-expert-instruction", "modifyitem.item.expert.instruction"); + UIBoundBoolean.make(showItemExpert, "item-expert", itemOTP + "expert", null); - /* - * EVALSYS-1026 - * Creating combo box for expert item groups and matching the item to the - * item group category or objective - */ - //Boolean useExpertItems = (Boolean) settings.get(EvalSettings.USE_EXPERT_ITEMS); - //if (useExpertItems) { - ArrayList listExpertCat = new ArrayList(); - ArrayList listExpertValues = new ArrayList(); - listExpertCat.add("None"); - listExpertValues.add("0"); - for (int i = 0; i < itemGroups.size(); i++) { - EvalItemGroup eig = (EvalItemGroup) itemGroups.get(i); - // loop through all expert items - boolean foundItemGroup = false; - if (!foundItemGroup) { - List expertItems = authoringService.getItemsInItemGroup(eig.getId(), true); - for (int j = 0; j < expertItems.size(); j++) { - EvalItem expertItem = (EvalItem) expertItems.get(j); - if (expertItem.getId()== itemId) { - itemGroupId = eig.getId(); - foundItemGroup = true; - } - } - } - - if ( EvalConstants.ITEM_GROUP_TYPE_CATEGORY.equals(eig.getType())) { - listExpertCat.add(eig.getTitle()); - listExpertValues.add(eig.getId().toString()); - } else { - listExpertCat.add("..." + eig.getTitle()); - listExpertValues.add(eig.getId().toString()); - } - } - String[] expertValues = listExpertValues.toArray(new String[]{}); - UISelect expertList = UISelect.make( - showItemExpert, "item-expert-list", - expertValues, - listExpertCat.toArray(new String[]{}), - itemOTP+"itemGroupId", - itemGroupId != null ? itemGroupId.toString() : expertValues[0]); - expertList.selection.mustapply = true; // this is required to ensure that the value gets passed even if it is not changed - - UIMessage.make(showItemExpert, "expert-desc-header", "modifyitem.item.expert.desc.header"); - UIMessage.make(showItemExpert, "expert-desc-instruction", "modifyitem.item.expert.desc.instruction"); - UIMessage.make(showItemExpert, "expert-itemgroup-header", "modifyitem.item.expert.itemgroup.header"); - UIInput.make(showItemExpert, "expert-desc", itemOTP + "expertDescription"); + /* + * EVALSYS-1026 + * Creating combo box for expert item groups and matching the item to the + * item group category or objective + */ + //Boolean useExpertItems = (Boolean) settings.get(EvalSettings.USE_EXPERT_ITEMS); + //if (useExpertItems) { + ArrayList listExpertCat = new ArrayList(); + ArrayList listExpertValues = new ArrayList(); + listExpertCat.add("None"); + listExpertValues.add("0"); + for (int i = 0; i < itemGroups.size(); i++) { + EvalItemGroup eig = (EvalItemGroup) itemGroups.get(i); + // loop through all expert items + boolean foundItemGroup = false; + if (!foundItemGroup) { + List expertItems = authoringService.getItemsInItemGroup(eig.getId(), true); + for (int j = 0; j < expertItems.size(); j++) { + EvalItem expertItem = (EvalItem) expertItems.get(j); + if (expertItem.getId()== itemId) { + itemGroupId = eig.getId(); + foundItemGroup = true; + } + } + } + + if ( EvalConstants.ITEM_GROUP_TYPE_CATEGORY.equals(eig.getType())) { + listExpertCat.add(eig.getTitle()); + listExpertValues.add(eig.getId().toString()); + } else { + listExpertCat.add("..." + eig.getTitle()); + listExpertValues.add(eig.getId().toString()); + } + } + String[] expertValues = listExpertValues.toArray(new String[]{}); + UISelect expertList = UISelect.make( + showItemExpert, "item-expert-list", + expertValues, + listExpertCat.toArray(new String[]{}), + itemOTP+"itemGroupId", + itemGroupId != null ? itemGroupId.toString() : expertValues[0]); + expertList.selection.mustapply = true; // this is required to ensure that the value gets passed even if it is not changed + + UIMessage.make(showItemExpert, "expert-desc-header", "modifyitem.item.expert.desc.header"); + UIMessage.make(showItemExpert, "expert-desc-instruction", "modifyitem.item.expert.desc.instruction"); + UIMessage.make(showItemExpert, "expert-itemgroup-header", "modifyitem.item.expert.itemgroup.header"); + UIInput.make(showItemExpert, "expert-desc", itemOTP + "expertDescription"); } } else { - // if an expert item, must carry eval item group along with it. - itemGroupId = new Long(0); - if (templateItemId != null) { - EvalTemplateItem templateItem = authoringService.getTemplateItemById(templateItemId); - for (int i = 0; i < itemGroups.size(); i++) { - EvalItemGroup eig = (EvalItemGroup) itemGroups.get(i); - // loop through all expert items - boolean foundItemGroup = false; - if (!foundItemGroup) { - List expertItems = authoringService.getItemsInItemGroup(eig.getId(), true); - for (int j = 0; j < expertItems.size(); j++) { - EvalItem expertItem = (EvalItem) expertItems.get(j); - if (expertItem.getId()== templateItem.getItem().getId()) { - itemGroupId = eig.getId(); - foundItemGroup = true; - } - } - } - } - } - UIInput.make(showItemExpert, "expertitem-eigId", itemOTP+"itemGroupId", itemGroupId.toString()); + // if an expert item, must carry eval item group along with it. + itemGroupId = new Long(0); + if (templateItemId != null) { + EvalTemplateItem templateItem = authoringService.getTemplateItemById(templateItemId); + for (int i = 0; i < itemGroups.size(); i++) { + EvalItemGroup eig = (EvalItemGroup) itemGroups.get(i); + // loop through all expert items + boolean foundItemGroup = false; + if (!foundItemGroup) { + List expertItems = authoringService.getItemsInItemGroup(eig.getId(), true); + for (int j = 0; j < expertItems.size(); j++) { + EvalItem expertItem = (EvalItem) expertItems.get(j); + if (expertItem.getId()== templateItem.getItem().getId()) { + itemGroupId = eig.getId(); + foundItemGroup = true; + } + } + } + } + } + UIInput.make(showItemExpert, "expertitem-eigId", itemOTP+"itemGroupId", itemGroupId.toString()); } // Check to see if should show ITEM display hints @@ -490,7 +488,7 @@ } UIMessage.make(itemDisplayHintsBranch, "item-display-hint-header", headerKey); if(! isGroupable && ! isGrouped ){ - UIMessage.make(itemDisplayHintsBranch, "item-display-hint-instruction", instructionKey); + UIMessage.make(itemDisplayHintsBranch, "item-display-hint-instruction", instructionKey); } if (EvalConstants.ITEM_TYPE_SCALED.equals(itemClassification) && ! isGroupable && ! isGrouped ) { @@ -519,9 +517,8 @@ Boolean naAllowed = (Boolean) settings.get(EvalSettings.ENABLE_NOT_AVAILABLE); if (naAllowed && ! isGroupable && ! isGrouped ) { UIBranchContainer showNA = UIBranchContainer.make(itemDisplayHintsBranch, "showNA:"); - UIBoundBoolean bb = UIBoundBoolean.make(showNA, "item-na", commonDisplayOTP + "usesNA", usesNA); - UIMessage.make(showNA,"item-na-header", "modifyitem.item.na.header") - .decorate( new UILabelTargetDecorator(bb) ); + UIBoundBoolean.make(showNA, "item-na", commonDisplayOTP + "usesNA", usesNA); + UIMessage.make(showNA,"item-na-header", "modifyitem.item.na.header"); } if (! EvalConstants.ITEM_TYPE_TEXT.equals(itemClassification) && ! isGroupable && ! isGrouped ) { @@ -529,9 +526,8 @@ Boolean commentAllowed = (Boolean) settings.get(EvalSettings.ENABLE_ITEM_COMMENTS); if (commentAllowed) { UIBranchContainer showComment = UIBranchContainer.make(itemDisplayHintsBranch, "showItemComment:"); - UIBoundBoolean bb = UIBoundBoolean.make(showComment, "item-comment", commonDisplayOTP + "usesComment", usesComment); - UIMessage.make(showComment,"item-comment-header", "modifyitem.item.comment.header") - .decorate( new UILabelTargetDecorator(bb) ); + UIBoundBoolean.make(showComment, "item-comment", commonDisplayOTP + "usesComment", usesComment); + UIMessage.make(showComment,"item-comment-header", "modifyitem.item.comment.header"); } } @@ -540,9 +536,8 @@ Boolean selectOptionsCompulsory = true; if (selectOptionsCompulsory) { UIBranchContainer showComp = UIBranchContainer.make(itemDisplayHintsBranch, "showItemCompulsory:"); - UIBoundBoolean bb = UIBoundBoolean.make(showComp, "item-compulsory", commonDisplayOTP + "compulsory", compulsory); - UIMessage.make(showComp,"item-compulsory-header", "modifyitem.item.compulsory.header") - .decorate( new UILabelTargetDecorator(bb) ); + UIBoundBoolean.make(showComp, "item-compulsory", commonDisplayOTP + "compulsory", compulsory); + UIMessage.make(showComp,"item-compulsory-header", "modifyitem.item.compulsory.header"); } } } @@ -565,9 +560,8 @@ commonDisplayOTP + "category").setMessageKeys(); for (int i = 0; i < categoryValues.length; i++) { UIBranchContainer radioBranch = UIBranchContainer.make(showItemCategory, "item-category-branch:", i+""); - UISelectChoice choice = UISelectChoice.make(radioBranch, "item-category-radio", radios.getFullID(), i); - UISelectLabel.make(radioBranch, "item-category-label", radios.getFullID(), i) - .decorate( new UILabelTargetDecorator(choice) ); + UISelectChoice.make(radioBranch, "item-category-radio", radios.getFullID(), i); + UISelectLabel.make(radioBranch, "item-category-label", radios.getFullID(), i); } } } @@ -580,7 +574,7 @@ if (showHierarchyOptions && ! isGroupable && ! isGrouped ) { hierarchyNodeSelectorRenderer.renderHierarchyNodeSelector(form, "hierarchyNodeSelector:", templateItemOTP + "hierarchyNodeId", null); } - + /* * UMD Specific * If the system setting (admin setting) for "EvalSettings.ITEM_USE_RESULTS_SHARING" is set as true then all @@ -608,13 +602,13 @@ new UIELBinding(templateItemOTP + "resultsSharing", EvalConstants.SHARING_PUBLIC)); } - + // hierarchy node selector control - // Boolean showHierarchyOptions = (Boolean) settings.get(EvalSettings.DISPLAY_HIERARCHY_OPTIONS); - // if (showHierarchyOptions) { - // hierarchyNodeSelectorRenderer.renderHierarchyNodeSelector(form, "hierarchyNodeSelector:", templateItemOTP + "hierarchyNodeId", null); - // } - + // Boolean showHierarchyOptions = (Boolean) settings.get(EvalSettings.DISPLAY_HIERARCHY_OPTIONS); + // if (showHierarchyOptions) { + // hierarchyNodeSelectorRenderer.renderHierarchyNodeSelector(form, "hierarchyNodeSelector:", templateItemOTP + "hierarchyNodeId", null); + // } + } @@ -634,9 +628,9 @@ saveBinding = "#{templateBBean.saveTemplateItemAction}"; } } - + if(isGroupable){ - // saving template item straight into a group + // saving template item straight into a group saveBinding = "#{templateBBean.saveTemplateItemToGroupAction}"; } if (saveBinding != null) { @@ -670,19 +664,19 @@ // go to the Items view if we are not working with a template currently result.resultingView = new SimpleViewParameters(ControlItemsProducer.VIEW_ID); }else{ - if(actionReturn != null){ - try{ - Long itemId = Long.parseLong(actionReturn.toString()); - result.resultingView = new TemplateViewParameters(ModifyTemplateItemsProducer.VIEW_ID, ivp.templateId, itemId); - }catch(NumberFormatException e){ - if ("success".equals(actionReturn.toString())){ - result.resultingView = new TemplateViewParameters(ModifyTemplateItemsProducer.VIEW_ID, ivp.templateId); - }else{ - //This is an unexpected return string, possibly an error. So return an error view: - result.resultingView = new SimpleViewParameters(MessagesProducer.VIEW_ID); - } - } - } + if(actionReturn != null){ + try{ + Long itemId = Long.parseLong(actionReturn.toString()); + result.resultingView = new TemplateViewParameters(ModifyTemplateItemsProducer.VIEW_ID, ivp.templateId, itemId); + }catch(NumberFormatException e){ + if ("success".equals(actionReturn.toString())){ + result.resultingView = new TemplateViewParameters(ModifyTemplateItemsProducer.VIEW_ID, ivp.templateId); + }else{ + //This is an unexpected return string, possibly an error. So return an error view: + result.resultingView = new SimpleViewParameters(MessagesProducer.VIEW_ID); + } + } + } } } Index: tool/src/java/org/sakaiproject/evaluation/tool/producers/PreviewEvalProducer.java =================================================================== --- tool/src/java/org/sakaiproject/evaluation/tool/producers/PreviewEvalProducer.java (revision 81089) +++ tool/src/java/org/sakaiproject/evaluation/tool/producers/PreviewEvalProducer.java (working copy) @@ -46,6 +46,7 @@ import uk.org.ponder.messageutil.MessageLocator; import uk.org.ponder.rsf.components.UIBranchContainer; import uk.org.ponder.rsf.components.UIContainer; +import uk.org.ponder.rsf.components.UIInitBlock; import uk.org.ponder.rsf.components.UIInternalLink; import uk.org.ponder.rsf.components.UIMessage; import uk.org.ponder.rsf.components.UIOutput; @@ -130,7 +131,7 @@ Long templateId = previewEvalViewParams.templateId; String evalGroupId = previewEvalViewParams.evalGroupId; EvalEvaluation eval = null; - + if (! previewEvalViewParams.external) { UIInternalLink.make(tofill, "summary-link", UIMessage.make("summary.page.title"), @@ -161,9 +162,9 @@ EvalAssignGroup group = null; String groupDisplayTitle = null; Boolean useGroupSpecificPreview = (Boolean) evalSettings.get(EvalSettings.ENABLE_GROUP_SPECIFIC_PREVIEW); - if(useGroupSpecificPreview.booleanValue() && evaluationId != null) { + if (useGroupSpecificPreview.booleanValue() && evaluationId != null) { int groupCount = this.evaluationService.countEvaluationGroups(evaluationId, true); - if(groupCount == 0) { + if (groupCount == 0) { useGroupSpecificPreview = new Boolean(false); } else if(groupCount == 1) { Map> groupMap = this.evaluationService.getAssignGroupsForEvals(new Long[]{evaluationId}, false, false); @@ -213,7 +214,7 @@ } TemplateItemDataList tidl = null; - if(group == null) { + if (group == null) { // get all items for this template List allItems = authoringService.getTemplateItemsForTemplate(templateId, new String[] {}, new String[] {}, new String[] {}); @@ -248,7 +249,7 @@ evaluationService, authoringService, hierarchyLogic, null); } - if(tidl == null) { + if (tidl == null) { // this is an empty template so just display some ugly message UIMessage.make(tofill, "noItemsToShow", "no.list.items"); } else { @@ -310,11 +311,16 @@ } } } - + //explain groups if using any groups in this template if ( countAssistants > 0 || countInstructors > 0 ){ UIOutput.make(tofill, "show-eval-instructions-groups"); } + + if (! previewEvalViewParams.external) { + // only show back button when navigating inside the tool + UIOutput.make(tofill, "show-back-button"); + } } } Index: tool/src/java/org/sakaiproject/evaluation/tool/bundle/messages.properties =================================================================== --- tool/src/java/org/sakaiproject/evaluation/tool/bundle/messages.properties (revision 81089) +++ tool/src/java/org/sakaiproject/evaluation/tool/bundle/messages.properties (working copy) @@ -40,6 +40,9 @@ item.classification.expert=Expert label.process=Processing... placeholder={0} +## displaying the eval title: 0=eval title, 1=group title, 2=eval state, 3=eval term, 4=group type +#eval.display.title={0} / {1} / {2} / {3} / {4} +eval.display.title={0} - {1} # Messages for the user @@ -57,20 +60,27 @@ summary.notifications.title=Current notifications summary.evaluations.title=Current evaluations to take summary.evaluations.courseeval.title=Course - Evaluation -summary.evaluations.starts.title=Starts -summary.evaluations.ends.title=Ends +summary.evaluations.evaluation.title=Evaluation +summary.evaluation.status.title=Status +summary.evaluations.starts.title=Open +summary.evaluations.ends.title=Close summary.evaluations.none=There are no evaluations to take at present summary.be.evaluated.none=You currently have no active or pending evaluations summary.evaluations.admin=Evaluations I am creating or administering -summary.responses.title=Evaluations in which I may be evaluated +## be evaluated specific +summary.evaluated.title=Evaluations in which I may be evaluated +summary.evaluated.inprogress=In Progress +summary.evaluated.closed=Closed +# general responses (used in be evaluated) summary.responses.evaltitle=Evaluation title summary.responses.state=State summary.responses.date=Date -summary.responses.responses=Responses +summary.responses.responses=Response Rate +summary.responses.results=Reports Available # "summary.responses.eval.title" shows the group-title ({0}) and eval-title ({1}) # (in either order, with approp punctuation) for an assigned eval in the instructor widget summary.responses.eval.title={0} [{1}] -summary.responses.counts = {0} of {1} +summary.responses.counts={0} of {1} summary.sitelisting.title=Site/Group Listing summary.sitelisting.evaluated=Groups I can be evaluated in: summary.sitelisting.evaluate=Groups I can evaluate: @@ -110,13 +120,16 @@ administrate.instructors.eval.create.note=Instructors allowed to create evaluations administrate.instructors.view.results.note=Instructors allowed to view results administrate.instructors.email.students.note=Instructors allowed to email students +administrate.instructors.view.responders.note=Instructors allowed to view responders administrate.instructors.hierarchy.note=Instructors must use evaluations from above in the hierarchy administrate.instructors.num.questions.note=Instructors may add this number of questions to evaluations from above in the hierarchy before the release date administrate.student.settings.header=Student Settings: -administrate.students.unanswered.note=Students may leave questions unanswered -administrate.students.modify.responses.note=Students may edit their responses up to the due date -administrate.students.save.without.submit.note=Students allowed to save their response without submitting -administrate.students.view.results.note=Students allowed to view results +administrate.student.settings.header.inner=Students may.. +administrate.students.unanswered.note=Leave questions unanswered +administrate.students.modify.responses.note=Edit their responses up to the due date +administrate.students.save.without.submit.note=Save and Complete later (adds button in addition to submitting) +administrate.students.cancel.allowed.note=Cancel while filing out evaluation +administrate.students.view.results.note=View results administrate.admin.settings.header=Administrator Settings: administrate.admin.hierarchy.num.questions.note=Admins below the hierarchy level of the owner may add this number of questions to the evaluation before the release date administrate.admin.view.instructor.added.results.note=Admins allowed to view instructor added question results @@ -125,8 +138,17 @@ administrate.hierarchy.settings.header=Hierarchy Settings: administrate.hierarchy-display-node-headers-note=Display hierarchy node headers on the take eval and preview eval views administrate.general.show.hierarchy.information=Use Hierarchy menus, options, and data in the system +## admin dash settings +administrate.dash.settings.header=Dashboard Settings +administrate.dash.summary.note=Summary lists to display: +administrate.dash.enable.evaluatee.box=Instructor +administrate.dash.evaluatee.closed.still.recent.note=Display evaluations after they close for this many days +administrate.dash.enable.administrating.box=Administration +administrate.dash.admin.closed.still.recent.note=Display evaluations after they close for this many days +administrate.dash.enable.sites.summary=Sites +## admin general settings +administrate.general.settings.header=General Settings administrate.general.show.my.toplinks=Show links to My Evaluations, My Templates, My Items, My Scales and My Email Templates -administrate.general.settings.header=General Settings: administrate.general.helpdesk.email.note=Helpdesk email address (email messages appear to come from this email address by default) administrate.general.responses.before.view.note=Number of responses required before results can be viewed administrate.general.na.allowed.note=Not Applicable allowed when creating questions @@ -136,9 +158,7 @@ administrate.general.enable.eval.close.note=Allow evaluations to be closed early administrate.general.enable.eval.reopen.note=Allow evaluations to be reopened after they close administrate.general.enable.item.comments.note=Enable the optional use of text comments on non-text items -administrate.general.enable.administrating.box=Show the "Evaluations I am creating or administering" box (Administrator widget) on the main screen administrate.general.enable.group.specific.preview.note=Show group-specific preview when possible -administrate.general.enable.sites.summary=Show the sites summary box on the main screen administrate.general.enable.response.removal=Allow responses to evaluations to be removed administrate.general.template.sharing.note=Template sharing and visibility setting administrate.general.template.copying.note=Copy templates, items and scales when saving new evaluations @@ -156,6 +176,7 @@ administrate.institution.specific.settings.header=Institution Specific Settings: administrate.general.item.sharing.note=Enable option to flag specific items in evaluations for database export and sharing (UMD) administrate.general.enable.importing.note=Enable importing options and controls (UM) +administrate.general.enable.site.published.check=Enable Site (group) publish check - NOTE: this will break all other group types (UM) administrate.general.disable.item.bank=Disable the Item Bank administrate.general.disable.question.blocks=Disable Question Blocks administrate.general.view.results.ignore.dates.note=View results whilst survey is still open @@ -169,14 +190,13 @@ administrate.top.control.import.settings=Import Configuration administrate.top.control.search=Search administrate.general.require.comments.block.note=Require a comments block to be included in every evaluation -administrate.general.eval.closed.still.recent.note=Number of days old can an eval be and still be recently closed administrate.sharing.owner=Owner - Visibility set by owner administrate.true.label=Yes administrate.false.label=No administrate.email.delivery=Control Email Settings is currently set to {0} - this is appropriate to {1} administrate.general.enable.ta.category=Enable Teaching Assistant item category administrate.use.admin.from.email=Use evaluation admin email address to send from for notifications (uses the system help address otherwise) (CAM) -administrate.job.completion.email=Enable an email to be sent to the evaluation admin when an email job has completed +administrate.job.completion.email=Enable confirmation emails to the helpdesk user (and logging) when an email job has completed administrate.enable.reminder.status=Enable the job status while reminders are running. administrate.email.time.wait.secs=The time in seconds between the creation of an evaluation and the send of the available notification, default 300 (5 mins) administrate.general.enable.selections=Enable advanced Instructor / Teaching Assistant selection options when assigning evaluations @@ -185,7 +205,6 @@ administrate.reset.button=Reset Config Cache administrate.reset.cache=Force the configuration cache to clear immediately, use this if you have changed the config settings and they appear to be out of sync, the cache should automatically reset once per hour administrate.reset.message=Configuration settings cache has been cleared and reloaded -administrate.general.enable.evaluatee.box=Show the instructor summary box on the main screen #Administrative search administrate.search.page.title=Administrative Search administrate.search.instruction=Search by evaluation title. Search term should be a substring within the title of the evaluation. Matching is case sensitive. @@ -297,7 +316,8 @@ # eval general evaluations.add.message=Added new evaluation ({0}) which starts on {1} -evaluations.take.message=Evaluation response saved for evaluation ({0}) of {1} +evaluations.take.message=Thank you for submitting your evaluation response! Your input will help us improve and recognize good teaching. +evaluations.save.no.submit.message=You have saved your evaluation for completion later. Please make sure to come back, complete and submit your evaluation so your input can help us improve and recognize good teaching. # Control evaluations controlevaluations.page.title=My Evaluations @@ -307,35 +327,36 @@ controlevaluations.partial.created.date.header=Created On controlevaluations.partial.continue=Continue creating this evaluation controlevaluations.inqueue.header=In-Queue Evaluations -controlevaluations.inqueue.description=Your Evaluations in queue that have not started yet +controlevaluations.inqueue.description=Created but not open yet controlevaluations.inqueue.none=No evaluations in-queue controlevaluations.active.header=Active Evaluations -controlevaluations.active.description=Your Evaluations which are active and can be taken +controlevaluations.active.description=Currently open and can be taken controlevaluations.active.none=No active evaluations controlevaluations.active.close.now=Close Now controlevaluations.active.report.title=View Report controlevaluations.closed.header=Closed Evaluations -controlevaluations.closed.description=Your Evaluations which have been completed +controlevaluations.closed.description=Completed controlevaluations.closed.none=No closed evaluations controlevaluations.closed.reopen.now=Re-open controlevaluations.eval.title.header=Evaluation Title controlevaluations.eval.assigned.header=Assigned controlevaluations.eval.startdate.header=Start Date controlevaluations.eval.duedate.header=Due Date -controlevaluations.eval.settings.header=Settings -controlevaluations.eval.reminders.header=Reminders +controlevaluations.eval.settings.header=Actions controlevaluations.eval.responses.header=Responses -controlevaluations.eval.report.header=Report +controlevaluations.eval.report.header=Reports Available controlevaluations.eval.responserate.header=Response Rate controlevaluations.eval.responses.inline={0} -controlevaluations.eval.report.header=Report +controlevaluations.eval.title.tooltip=View Preview controlevaluations.eval.direct.link=Permalink +controlevaluations.eval.direct.tooltip=Link directly to the evaluation controlevaluations.eval.groups.link={0} groups -controlevaluations.eval.report.link=Report +controlevaluations.eval.email.link=Send email +controlevaluations.eval.report.link=View report controlevaluations.eval.report.viewable.on=Viewable on {0} controlevaluations.eval.report.awaiting.responses=Awaiting {0} responses -controlevaluations.eval.preview.title=Preview: -controlevaluations.eval.link.title=Quick link: +controlevaluations.eval.report.after.responses=After {0} more responses +controlevaluations.eval.report.viewable.least.responses={0}: if at least {1} responses controlevaluations.create.user.message=New evaluation ({0}) has been created and will begin on {1} controlevaluations.delete.user.message=Evaluation ({0}) has been deleted controlevaluations.closed.user.message=Evaluation ({0}) has been closed early @@ -431,6 +452,7 @@ evalsettings.reminder.days.6=Every 6 days evalsettings.reminder.days.7=Every week evalsettings.reminder.days.-1=24 hours before the survey closes +evalsettings.reminder.days.-2=Every 5 minutes (TESTING ONLY!) evalsettings.admin.settings.header=Administrative Settings evalsettings.auth.control.instructions=This setting allows you to choose whether to require authentication to take this evaluation. evalsettings.auth.control.header=Authentication control setting @@ -818,6 +840,7 @@ modifyscale.scale.ideal.note.main.text=Indicate the position of the "best" answer in this scale (used for graphs and coloring) modifyscale.scale.hidden.note=This scale is not visible in the interface (pull down menus) modifyscale.save.scale.button=Save Scale +modifyscale.save.preview.button=Preview Scale modifyscale.sharing.note=Sharing # Scale remove confirmation screen @@ -889,6 +912,8 @@ about them. If she has two evaluations using the "Chemistry" email template and four evaluations using the "Biology" email template, she will get two emails. controlemail.consolidated.emails.settings=Consolidated email settings controlemail.consolidated.available.enabled=Send notifications when evaluations open +controlemail.consolidated.force.send.created.email=Force Send E-mail Creation notification, even if instructor cannot modify evaluation +controlemail.consolidated.force.send.available.notification.immediately=Force Send E-mail Available notification controlemail.next-reminder-date=Next reminder date controlemail.setting-reminder-date=If this shows the current date and time, reminders are not yet scheduled. In that case, you can select the first time \ to send reminders by setting the date and time here. Scheduling of later reminders will be determined by the reminder frequency below. @@ -989,6 +1014,7 @@ takeeval.assistant.questions.header=Teaching Assistant Items: {0} takeeval.save.button=Save Evaluation without Submit takeeval.submit.button=Submit Evaluation +takeeval.saved.warning=Evaluation has been Saved but not Submitted takeeval.user.cannot.take=You do not have permission to take this evaluation at this time as user: {0} ({1}) [{2}] takeeval.switch.group.header=Switch group: takeeval.switch.group.button=Switch @@ -996,7 +1022,7 @@ takeeval.eval.closed=Evaluation closed on {0} and can no longer be taken takeeval.eval.site.notpublished=You are either not expected to complete this evaluation or the site this evaluation is linked to is currently unpublished. If you think it is the latter then please contact your department or the site owner. takeeval.user.must.answer.all.note=You must answer all non-textual response items in this evaluation -takeeval.user.must.answer.all.exception=You left some non-textual response items blank, all non-textual response items (indicated below) in this evaluation must be answered before you can submit +takeeval.user.must.answer.all.exception=You left some required items blank. All required items (indicated with a red asterisk below) must be answered before you can submit your evaluation takeeval.user.blank.response.exception=You left all response items blank, you must fill in at least one to submit the evaluation takeeval.user.cannot.take.now.exception=You cannot submit responses for this evaluation right now takeeval.user.cannot.save.reponse=You cannot save this response right now, this usually happens when attempting to save a response which has already been saved @@ -1008,7 +1034,6 @@ takeeval.selection.warn=Are you sure you don't want to evaluate XXX anymore? takeeval.selection.dropdown=--- Select --- - # Special RSF code for rendering exception GeneralShowError=There was an unexpected error rendering this view. Please contact \ the administrator of this site with details of the link you operated and the \ @@ -1162,6 +1187,25 @@ evalresponders.status.incomplete=Incomplete evalresponders.status.untaken=Not Taken +## human readable dates +# human dates without times (days = 0) +humandate.today=Today +humandate.tomorrow=Tomorrow +humandate.indays=In {0} days +humandate.inweek=In a week +humandate.yesterday=Yesterday +humandate.daysago={0} days ago +humandate.weekago=A week ago +humandate.date={0} +# human readable dates with times (days = 0, time = 1) +humandatetime.today=Today at {1} +humandatetime.tomorrow=Tomorrow at {1} +humandatetime.indays=In {0} days at {1} +humandatetime.inweek=In a week at {1} +humandatetime.yesterday=Yesterday at {1} +humandatetime.daysago={0} days ago at {1} +humandatetime.weekago=A week ago at {1} +humandatetime.date={0} # Comment strings for the views that show items with a comment option comment.hide=Hide this comment Index: tool/src/java/org/sakaiproject/evaluation/tool/reporting/CSVReportExporter.java =================================================================== --- tool/src/java/org/sakaiproject/evaluation/tool/reporting/CSVReportExporter.java (revision 81089) +++ tool/src/java/org/sakaiproject/evaluation/tool/reporting/CSVReportExporter.java (working copy) @@ -90,10 +90,8 @@ continue; } - questionTypeRow.add(responseAggregator.getHeaderLabelForItemType(dti - .getTemplateItemType())); - questionTextRow.add(commonLogic.makePlainTextFromHTML(dti.templateItem.getItem() - .getItemText())); + questionTypeRow.add(responseAggregator.getHeaderLabelForItemType(dti.getTemplateItemType())); + questionTextRow.add(commonLogic.makePlainTextFromHTML(dti.templateItem.getItem().getItemText())); if (EvalConstants.ITEM_CATEGORY_INSTRUCTOR.equals(dti.associateType)) { EvalUser user = commonLogic.getEvalUserById( dti.associateId ); String instructorMsg = messageLocator.getMessage("reporting.spreadsheet.instructor", @@ -144,12 +142,10 @@ EvalAnswer answer = dti.getAnswer(responseId); if (answer != null) { - nextResponseRow.add(responseAggregator.formatForSpreadSheet(answer - .getTemplateItem(), answer)); + nextResponseRow.add(responseAggregator.formatForSpreadSheet(answer.getTemplateItem(), answer)); if (dti.usesComments()) { // put comment in the next column - nextResponseRow.add(EvalUtils.isBlank(answer.getComment()) ? "" : answer - .getComment()); + nextResponseRow.add(EvalUtils.isBlank(answer.getComment()) ? "" : answer.getComment()); } } else { nextResponseRow.add(""); Index: tool/src/java/org/sakaiproject/evaluation/tool/reporting/XLSReportExporter.java =================================================================== --- tool/src/java/org/sakaiproject/evaluation/tool/reporting/XLSReportExporter.java (revision 81089) +++ tool/src/java/org/sakaiproject/evaluation/tool/reporting/XLSReportExporter.java (working copy) @@ -269,14 +269,13 @@ Cell responseCell = row.createCell(dtiCounter); // In Eval, users can leave questions blank, in which case this will be null if (answer != null) { - setPlainStringCell(responseCell, responseAggregator.formatForSpreadSheet(answer - .getTemplateItem(), answer)); + setPlainStringCell(responseCell, responseAggregator.formatForSpreadSheet(answer.getTemplateItem(), answer)); } if (dti.usesComments()) { // put comment in the extra column dtiCounter++; - setPlainStringCell(row.createCell(dtiCounter), (answer == null || EvalUtils - .isBlank(answer.getComment())) ? "" : answer.getComment()); + setPlainStringCell(row.createCell(dtiCounter), + (answer == null || EvalUtils.isBlank(answer.getComment())) ? "" : answer.getComment()); } dtiCounter++; } Index: tool/src/java/org/sakaiproject/evaluation/tool/reporting/PDFReportExporter.java =================================================================== --- tool/src/java/org/sakaiproject/evaluation/tool/reporting/PDFReportExporter.java (revision 81089) +++ tool/src/java/org/sakaiproject/evaluation/tool/reporting/PDFReportExporter.java (working copy) @@ -17,6 +17,7 @@ import java.io.OutputStream; import java.text.DateFormat; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -123,13 +124,17 @@ String groupNames = responseAggregator.getCommaSeparatedGroupNames(groupIds); // TODO this is so hard to read it makes me cry, it should not be written as a giant single line like this -AZ - evalPDFReportBuilder.addTitlePage(evaluation.getTitle(), groupNames, messageLocator - .getMessage("reporting.pdf.startdatetime", df.format(evaluation.getStartDate())), - messageLocator.getMessage("reporting.pdf.enddatetime", df.format(evaluation - .getDueDate())), messageLocator.getMessage("reporting.pdf.replyrate", - new String[] { EvalUtils.makeResponseRateStringFromCounts(responsesCount, - enrollmentsCount) }), bannerImageBytes, messageLocator - .getMessage("reporting.pdf.defaultsystemname")); + evalPDFReportBuilder.addTitlePage( + evaluation.getTitle(), + groupNames, + messageLocator.getMessage("reporting.pdf.startdatetime", df.format(evaluation.getStartDate())), + messageLocator.getMessage("reporting.pdf.enddatetime", df.format(evaluation.getDueDate())), + messageLocator.getMessage("reporting.pdf.replyrate", new String[] { + EvalUtils.makeResponseRateStringFromCounts(responsesCount, enrollmentsCount) + }), + bannerImageBytes, + messageLocator.getMessage("reporting.pdf.defaultsystemname") + ); /** * set title and instructions @@ -150,7 +155,6 @@ TemplateItemDataList tidl = responseAggregator.prepareTemplateItemDataStructure(evaluation.getId(), groupIds); // Loop through the major group types: Course Questions, Instructor Questions, etc. - int renderedItemCount = 0; for (TemplateItemGroup tig : tidl.getTemplateItemGroups()) { if (!instructorViewAllResults // If the eval is so configured, @@ -184,15 +188,13 @@ // Render the Node title if it's enabled in the admin settings. if (hng.node != null) { // Showing the section title is system configurable via the administrate view - Boolean showHierSectionTitle = (Boolean) evalSettings - .get(EvalSettings.DISPLAY_HIERARCHY_HEADERS); + Boolean showHierSectionTitle = (Boolean) evalSettings.get(EvalSettings.DISPLAY_HIERARCHY_HEADERS); if (showHierSectionTitle) { evalPDFReportBuilder.addSectionHeader(hng.node.title); } } - List dtis = hng.getDataTemplateItems(true); // include block - // children + List dtis = hng.getDataTemplateItems(true); // include block children for (int i = 0; i < dtis.size(); i++) { DataTemplateItem dti = dtis.get(i); @@ -206,7 +208,6 @@ } renderDataTemplateItem(evalPDFReportBuilder, dti); - renderedItemCount++; } } } @@ -273,16 +274,11 @@ int[] responseArray = TemplateItemDataList.getAnswerChoicesCounts(templateItemType, itemScaleOptions.length, itemAnswers); - String[] optionLabels; + String[] optionLabels = RenderingUtils.makeReportingScaleLabels(templateItem, itemScaleOptions); if (templateItem.getUsesNA()) { - optionLabels = new String[itemScaleOptions.length + 1]; - for (int m = 0; m < itemScaleOptions.length; m++) { - optionLabels[m] = itemScaleOptions[m]; - } - optionLabels[optionLabels.length - 1] = messageLocator - .getMessage("reporting.notapplicable.longlabel"); - } else { - optionLabels = itemScaleOptions; + // add in the N/A label to the end + optionLabels = Arrays.copyOf(optionLabels, optionLabels.length+1); + optionLabels[optionLabels.length - 1] = messageLocator.getMessage("reporting.notapplicable.longlabel"); } // http://www.caret.cam.ac.uk/jira/browse/CTL-1504 @@ -297,9 +293,11 @@ // handle comments if (dti.usesComments()) { List comments = dti.getComments(); - evalPDFReportBuilder.addCommentList(messageLocator - .getMessage("viewreport.comments.header"), comments, messageLocator - .getMessage("viewreport.no.comments")); + evalPDFReportBuilder.addCommentList( + messageLocator.getMessage("viewreport.comments.header"), + comments, + messageLocator.getMessage("viewreport.no.comments") + ); } } else { Index: tool/src/java/org/sakaiproject/evaluation/tool/SetupEvalBean.java =================================================================== --- tool/src/java/org/sakaiproject/evaluation/tool/SetupEvalBean.java (revision 81089) +++ tool/src/java/org/sakaiproject/evaluation/tool/SetupEvalBean.java (working copy) @@ -22,11 +22,9 @@ import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Map.Entry; import java.util.Set; -import java.util.Map.Entry; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; import org.sakaiproject.evaluation.constant.EvalConstants; import org.sakaiproject.evaluation.logic.EvalAuthoringService; import org.sakaiproject.evaluation.logic.EvalCommonLogic; @@ -62,7 +60,7 @@ */ public class SetupEvalBean { - private static Log log = LogFactory.getLog(SetupEvalBean.class); + //private static Log log = LogFactory.getLog(SetupEvalBean.class); private final String EVENT_EVAL_REOPENED = "eval.evaluation.reopened"; @@ -453,21 +451,23 @@ userIdsForEvalGroup.addAll(commonLogic.getUserIdsForEvalGroup(evalGroupIDs[i], EvalConstants.PERM_ASSISTANT_ROLE)); userIdsForEvalGroup.addAll(commonLogic.getUserIdsForEvalGroup(evalGroupIDs[i], EvalConstants.PERM_TAKE_EVALUATION)); } - - for (String userId : userIdsForEvalGroup) { - - //ignore invalid users - if(EvalUser.USER_TYPE_INVALID.equals(commonLogic.getEvalUsersByIds(new String[] {userId}).get(0).type)) { - continue; - } - - if(commonLogic.isUserAnonymous(userId)) { - EvalUser user = commonLogic.getEvalUsersByIds(new String[] {userId}).get(0); - messages.addMessage(new TargettedMessage( - "assigneval.invalid.user", new Object[] {user.username}, - TargettedMessage.SEVERITY_ERROR)); - return "fail"; - } + + if (userIdsForEvalGroup != null) { + for (String userId : userIdsForEvalGroup) { + + //ignore invalid users + if(EvalUser.USER_TYPE_INVALID.equals(commonLogic.getEvalUsersByIds(new String[] {userId}).get(0).type)) { + continue; + } + + if(commonLogic.isUserAnonymous(userId)) { + EvalUser user = commonLogic.getEvalUsersByIds(new String[] {userId}).get(0); + messages.addMessage(new TargettedMessage( + "assigneval.invalid.user", new Object[] {user.username}, + TargettedMessage.SEVERITY_ERROR)); + return "fail"; + } + } } } Index: tool/src/java/org/sakaiproject/evaluation/tool/viewparams/ItemViewParameters.java =================================================================== --- tool/src/java/org/sakaiproject/evaluation/tool/viewparams/ItemViewParameters.java (revision 81089) +++ tool/src/java/org/sakaiproject/evaluation/tool/viewparams/ItemViewParameters.java (working copy) @@ -29,6 +29,40 @@ public String itemClassification; public Long groupItemId; + // special params for live item previews + /** + * Live Preview + * The scale display setting for live previews + * EvalConstants.ITEM_SCALE_DISPLAY_FULL_COLORED; + */ + public String scaleDisplay; + /** + * Live Preview + * Current text for live preview (might need to truncate this) + */ + public String text; + /** + * Live Preview + * Whether or not to show the N/A + */ + public Boolean na; + /** + * Live Preview + * whether to show the user comments box + */ + public Boolean showComment; + /** + * Live Preview + * Is this item required + */ + public Boolean compulsory; + /** + * Live Preview + * How many lines of text to show for essay + */ + public Integer textLines; + + public ItemViewParameters() { } public ItemViewParameters(String viewID, Long itemId, Long templateItemId) { Index: tool/src/java/org/sakaiproject/evaluation/tool/viewparams/EvalScaleParameters.java =================================================================== --- tool/src/java/org/sakaiproject/evaluation/tool/viewparams/EvalScaleParameters.java (revision 81089) +++ tool/src/java/org/sakaiproject/evaluation/tool/viewparams/EvalScaleParameters.java (working copy) @@ -14,6 +14,8 @@ */ package org.sakaiproject.evaluation.tool.viewparams; +import org.sakaiproject.evaluation.constant.EvalConstants; + import uk.org.ponder.rsf.viewstate.SimpleViewParameters; /** @@ -21,16 +23,56 @@ * that are passed from one page to another. * * @author kahuja@vt.edu + * @author azeckoski */ public class EvalScaleParameters extends SimpleViewParameters { - public Long scaleId; - - public EvalScaleParameters() { - } - + public Long id; + public String[] points; + public String ideal; // EvalConstants.SCALE_IDEAL_NONE; + public String displaySetting; // EvalConstants.ITEM_SCALE_DISPLAY_FULL_COLORED; + + public String findDisplaySetting() { + return displaySetting == null ? EvalConstants.ITEM_SCALE_DISPLAY_FULL_COLORED : displaySetting; + } + public String findIdeal() { + return ideal == null ? EvalConstants.SCALE_IDEAL_NONE : ideal; + } + public String[] findPoints() { + return points == null ? new String[] {} : points; + } + + public EvalScaleParameters() { } + + public EvalScaleParameters(String viewID) { + this.viewID = viewID; + this.id = null; + } + public EvalScaleParameters(String viewID, Long scaleId) { this.viewID = viewID; - this.scaleId = scaleId; + this.id = scaleId; } - + + /** + * SPECIAL case for handling scale previews + * @param viewID the view id + * @param scaleId the scale id (must exist) + * @param scaleDisplaySetting the constant from {@link EvalConstants} ITEM_SCALE_DISPLAY_* + */ + public EvalScaleParameters(String viewID, Long scaleId, String scaleDisplaySetting) { + this.viewID = viewID; + this.id = scaleId; + this.points = null; + this.ideal = null; + if (scaleDisplaySetting != null) { + this.displaySetting = scaleDisplaySetting; + } + } + + public EvalScaleParameters(String viewID, String[] scalePoints) { + this.viewID = viewID; + this.id = null; + this.points = scalePoints; + } + } Index: tool/src/webapp/WEB-INF/applicationContext.xml =================================================================== --- tool/src/webapp/WEB-INF/applicationContext.xml (revision 81089) +++ tool/src/webapp/WEB-INF/applicationContext.xml (working copy) @@ -201,7 +201,7 @@ Index: tool/src/webapp/WEB-INF/requestContext.xml =================================================================== --- tool/src/webapp/WEB-INF/requestContext.xml (revision 81089) +++ tool/src/webapp/WEB-INF/requestContext.xml (working copy) @@ -43,6 +43,62 @@ ref="org.sakaiproject.evaluation.logic.EvalCommonLogic" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - + + + @@ -634,7 +685,7 @@ ref="org.sakaiproject.evaluation.logic.EvalAuthoringService" /> - + @@ -645,7 +696,16 @@ ref="org.sakaiproject.evaluation.logic.EvalAuthoringService" /> + + + + + + + @@ -662,6 +722,7 @@ ref="org.sakaiproject.evaluation.beans.EvalBeanUtils" /> + @@ -770,6 +831,7 @@ + + + Index: tool/src/webapp/content/css/jquery-ui-1.8.7.custom.css =================================================================== --- tool/src/webapp/content/css/jquery-ui-1.8.7.custom.css (revision 81089) +++ tool/src/webapp/content/css/jquery-ui-1.8.7.custom.css (working copy) @@ -1,572 +0,0 @@ -/* - * jQuery UI CSS Framework 1.8.7 - * - * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Theming/API - */ - -/* Layout helpers -----------------------------------*/ -.ui-helper-hidden { display: none; } -.ui-helper-hidden-accessible { position: absolute !important; clip: rect(1px 1px 1px 1px); clip: rect(1px,1px,1px,1px); } -.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; } -.ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; } -.ui-helper-clearfix { display: inline-block; } -/* required comment for clearfix to work in Opera \*/ -* html .ui-helper-clearfix { height:1%; } -.ui-helper-clearfix { display:block; } -/* end clearfix */ -.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); } - - -/* Interaction Cues -----------------------------------*/ -.ui-state-disabled { cursor: default !important; } - - -/* Icons -----------------------------------*/ - -/* states and images */ -.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; } - - -/* Misc visuals -----------------------------------*/ - -/* Overlays */ -.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; } - - -/* - * jQuery UI CSS Framework 1.8.7 - * - * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Theming/API - * - * To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Trebuchet%20MS,%20Tahoma,%20Verdana,%20Arial,%20sans-serif&fwDefault=bold&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=f6a828&bgTextureHeader=12_gloss_wave.png&bgImgOpacityHeader=35&borderColorHeader=e78f08&fcHeader=ffffff&iconColorHeader=ffffff&bgColorContent=eeeeee&bgTextureContent=03_highlight_soft.png&bgImgOpacityContent=100&borderColorContent=dddddd&fcContent=333333&iconColorContent=222222&bgColorDefault=f6f6f6&bgTextureDefault=02_glass.png&bgImgOpacityDefault=100&borderColorDefault=cccccc&fcDefault=1c94c4&iconColorDefault=ef8c08&bgColorHover=fdf5ce&bgTextureHover=02_glass.png&bgImgOpacityHover=100&borderColorHover=fbcb09&fcHover=c77405&iconColorHover=ef8c08&bgColorActive=ffffff&bgTextureActive=02_glass.png&bgImgOpacityActive=65&borderColorActive=fbd850&fcActive=eb8f00&iconColorActive=ef8c08&bgColorHighlight=ffe45c&bgTextureHighlight=03_highlight_soft.png&bgImgOpacityHighlight=75&borderColorHighlight=fed22f&fcHighlight=363636&iconColorHighlight=228ef1&bgColorError=b81900&bgTextureError=08_diagonals_thick.png&bgImgOpacityError=18&borderColorError=cd0a0a&fcError=ffffff&iconColorError=ffd27a&bgColorOverlay=666666&bgTextureOverlay=08_diagonals_thick.png&bgImgOpacityOverlay=20&opacityOverlay=50&bgColorShadow=000000&bgTextureShadow=01_flat.png&bgImgOpacityShadow=10&opacityShadow=20&thicknessShadow=5px&offsetTopShadow=-5px&offsetLeftShadow=-5px&cornerRadiusShadow=5px - */ - - -/* Component containers -----------------------------------*/ -.ui-widget { font-family: Trebuchet MS, Tahoma, Verdana, Arial, sans-serif; font-size: 1.1em; } -.ui-widget .ui-widget { font-size: 1em; } -.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Trebuchet MS, Tahoma, Verdana, Arial, sans-serif; font-size: 1em; } -.ui-widget-content { border: 1px solid #dddddd; background: #eeeeee url(images/ui-bg_highlight-soft_100_eeeeee_1x100.png) 50% top repeat-x; color: #333333; } -.ui-widget-content a { color: #333333; } -.ui-widget-header { border: 1px solid #e78f08; background: #f6a828 url(images/ui-bg_gloss-wave_35_f6a828_500x100.png) 50% 50% repeat-x; color: #ffffff; font-weight: bold; } -.ui-widget-header a { color: #ffffff; } - -/* Interaction states -----------------------------------*/ -.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #cccccc; background: #f6f6f6 url(images/ui-bg_glass_100_f6f6f6_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #1c94c4; } -.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #1c94c4; text-decoration: none; } -.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #fbcb09; background: #fdf5ce url(images/ui-bg_glass_100_fdf5ce_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #c77405; } -.ui-state-hover a, .ui-state-hover a:hover { color: #c77405; text-decoration: none; } -.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #fbd850; background: #ffffff url(images/ui-bg_glass_65_ffffff_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #eb8f00; } -.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #eb8f00; text-decoration: none; } -.ui-widget :active { outline: none; } - -/* Interaction Cues -----------------------------------*/ -.ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight {border: 1px solid #fed22f; background: #ffe45c url(images/ui-bg_highlight-soft_75_ffe45c_1x100.png) 50% top repeat-x; color: #363636; } -.ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #363636; } -.ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #cd0a0a; background: #b81900 url(images/ui-bg_diagonals-thick_18_b81900_40x40.png) 50% 50% repeat; color: #ffffff; } -.ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #ffffff; } -.ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #ffffff; } -.ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; } -.ui-priority-secondary, .ui-widget-content .ui-priority-secondary, .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; } -.ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; } - -/* Icons -----------------------------------*/ - -/* states and images */ -.ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_222222_256x240.png); } -.ui-widget-content .ui-icon {background-image: url(images/ui-icons_222222_256x240.png); } -.ui-widget-header .ui-icon {background-image: url(images/ui-icons_ffffff_256x240.png); } -.ui-state-default .ui-icon { background-image: url(images/ui-icons_ef8c08_256x240.png); } -.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_ef8c08_256x240.png); } -.ui-state-active .ui-icon {background-image: url(images/ui-icons_ef8c08_256x240.png); } -.ui-state-highlight .ui-icon {background-image: url(images/ui-icons_228ef1_256x240.png); } -.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_ffd27a_256x240.png); } - -/* positioning */ -.ui-icon-carat-1-n { background-position: 0 0; } -.ui-icon-carat-1-ne { background-position: -16px 0; } -.ui-icon-carat-1-e { background-position: -32px 0; } -.ui-icon-carat-1-se { background-position: -48px 0; } -.ui-icon-carat-1-s { background-position: -64px 0; } -.ui-icon-carat-1-sw { background-position: -80px 0; } -.ui-icon-carat-1-w { background-position: -96px 0; } -.ui-icon-carat-1-nw { background-position: -112px 0; } -.ui-icon-carat-2-n-s { background-position: -128px 0; } -.ui-icon-carat-2-e-w { background-position: -144px 0; } -.ui-icon-triangle-1-n { background-position: 0 -16px; } -.ui-icon-triangle-1-ne { background-position: -16px -16px; } -.ui-icon-triangle-1-e { background-position: -32px -16px; } -.ui-icon-triangle-1-se { background-position: -48px -16px; } -.ui-icon-triangle-1-s { background-position: -64px -16px; } -.ui-icon-triangle-1-sw { background-position: -80px -16px; } -.ui-icon-triangle-1-w { background-position: -96px -16px; } -.ui-icon-triangle-1-nw { background-position: -112px -16px; } -.ui-icon-triangle-2-n-s { background-position: -128px -16px; } -.ui-icon-triangle-2-e-w { background-position: -144px -16px; } -.ui-icon-arrow-1-n { background-position: 0 -32px; } -.ui-icon-arrow-1-ne { background-position: -16px -32px; } -.ui-icon-arrow-1-e { background-position: -32px -32px; } -.ui-icon-arrow-1-se { background-position: -48px -32px; } -.ui-icon-arrow-1-s { background-position: -64px -32px; } -.ui-icon-arrow-1-sw { background-position: -80px -32px; } -.ui-icon-arrow-1-w { background-position: -96px -32px; } -.ui-icon-arrow-1-nw { background-position: -112px -32px; } -.ui-icon-arrow-2-n-s { background-position: -128px -32px; } -.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; } -.ui-icon-arrow-2-e-w { background-position: -160px -32px; } -.ui-icon-arrow-2-se-nw { background-position: -176px -32px; } -.ui-icon-arrowstop-1-n { background-position: -192px -32px; } -.ui-icon-arrowstop-1-e { background-position: -208px -32px; } -.ui-icon-arrowstop-1-s { background-position: -224px -32px; } -.ui-icon-arrowstop-1-w { background-position: -240px -32px; } -.ui-icon-arrowthick-1-n { background-position: 0 -48px; } -.ui-icon-arrowthick-1-ne { background-position: -16px -48px; } -.ui-icon-arrowthick-1-e { background-position: -32px -48px; } -.ui-icon-arrowthick-1-se { background-position: -48px -48px; } -.ui-icon-arrowthick-1-s { background-position: -64px -48px; } -.ui-icon-arrowthick-1-sw { background-position: -80px -48px; } -.ui-icon-arrowthick-1-w { background-position: -96px -48px; } -.ui-icon-arrowthick-1-nw { background-position: -112px -48px; } -.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; } -.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; } -.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; } -.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; } -.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; } -.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; } -.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; } -.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; } -.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; } -.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; } -.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; } -.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; } -.ui-icon-arrowreturn-1-w { background-position: -64px -64px; } -.ui-icon-arrowreturn-1-n { background-position: -80px -64px; } -.ui-icon-arrowreturn-1-e { background-position: -96px -64px; } -.ui-icon-arrowreturn-1-s { background-position: -112px -64px; } -.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; } -.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; } -.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; } -.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; } -.ui-icon-arrow-4 { background-position: 0 -80px; } -.ui-icon-arrow-4-diag { background-position: -16px -80px; } -.ui-icon-extlink { background-position: -32px -80px; } -.ui-icon-newwin { background-position: -48px -80px; } -.ui-icon-refresh { background-position: -64px -80px; } -.ui-icon-shuffle { background-position: -80px -80px; } -.ui-icon-transfer-e-w { background-position: -96px -80px; } -.ui-icon-transferthick-e-w { background-position: -112px -80px; } -.ui-icon-folder-collapsed { background-position: 0 -96px; } -.ui-icon-folder-open { background-position: -16px -96px; } -.ui-icon-document { background-position: -32px -96px; } -.ui-icon-document-b { background-position: -48px -96px; } -.ui-icon-note { background-position: -64px -96px; } -.ui-icon-mail-closed { background-position: -80px -96px; } -.ui-icon-mail-open { background-position: -96px -96px; } -.ui-icon-suitcase { background-position: -112px -96px; } -.ui-icon-comment { background-position: -128px -96px; } -.ui-icon-person { background-position: -144px -96px; } -.ui-icon-print { background-position: -160px -96px; } -.ui-icon-trash { background-position: -176px -96px; } -.ui-icon-locked { background-position: -192px -96px; } -.ui-icon-unlocked { background-position: -208px -96px; } -.ui-icon-bookmark { background-position: -224px -96px; } -.ui-icon-tag { background-position: -240px -96px; } -.ui-icon-home { background-position: 0 -112px; } -.ui-icon-flag { background-position: -16px -112px; } -.ui-icon-calendar { background-position: -32px -112px; } -.ui-icon-cart { background-position: -48px -112px; } -.ui-icon-pencil { background-position: -64px -112px; } -.ui-icon-clock { background-position: -80px -112px; } -.ui-icon-disk { background-position: -96px -112px; } -.ui-icon-calculator { background-position: -112px -112px; } -.ui-icon-zoomin { background-position: -128px -112px; } -.ui-icon-zoomout { background-position: -144px -112px; } -.ui-icon-search { background-position: -160px -112px; } -.ui-icon-wrench { background-position: -176px -112px; } -.ui-icon-gear { background-position: -192px -112px; } -.ui-icon-heart { background-position: -208px -112px; } -.ui-icon-star { background-position: -224px -112px; } -.ui-icon-link { background-position: -240px -112px; } -.ui-icon-cancel { background-position: 0 -128px; } -.ui-icon-plus { background-position: -16px -128px; } -.ui-icon-plusthick { background-position: -32px -128px; } -.ui-icon-minus { background-position: -48px -128px; } -.ui-icon-minusthick { background-position: -64px -128px; } -.ui-icon-close { background-position: -80px -128px; } -.ui-icon-closethick { background-position: -96px -128px; } -.ui-icon-key { background-position: -112px -128px; } -.ui-icon-lightbulb { background-position: -128px -128px; } -.ui-icon-scissors { background-position: -144px -128px; } -.ui-icon-clipboard { background-position: -160px -128px; } -.ui-icon-copy { background-position: -176px -128px; } -.ui-icon-contact { background-position: -192px -128px; } -.ui-icon-image { background-position: -208px -128px; } -.ui-icon-video { background-position: -224px -128px; } -.ui-icon-script { background-position: -240px -128px; } -.ui-icon-alert { background-position: 0 -144px; } -.ui-icon-info { background-position: -16px -144px; } -.ui-icon-notice { background-position: -32px -144px; } -.ui-icon-help { background-position: -48px -144px; } -.ui-icon-check { background-position: -64px -144px; } -.ui-icon-bullet { background-position: -80px -144px; } -.ui-icon-radio-off { background-position: -96px -144px; } -.ui-icon-radio-on { background-position: -112px -144px; } -.ui-icon-pin-w { background-position: -128px -144px; } -.ui-icon-pin-s { background-position: -144px -144px; } -.ui-icon-play { background-position: 0 -160px; } -.ui-icon-pause { background-position: -16px -160px; } -.ui-icon-seek-next { background-position: -32px -160px; } -.ui-icon-seek-prev { background-position: -48px -160px; } -.ui-icon-seek-end { background-position: -64px -160px; } -.ui-icon-seek-start { background-position: -80px -160px; } -/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */ -.ui-icon-seek-first { background-position: -80px -160px; } -.ui-icon-stop { background-position: -96px -160px; } -.ui-icon-eject { background-position: -112px -160px; } -.ui-icon-volume-off { background-position: -128px -160px; } -.ui-icon-volume-on { background-position: -144px -160px; } -.ui-icon-power { background-position: 0 -176px; } -.ui-icon-signal-diag { background-position: -16px -176px; } -.ui-icon-signal { background-position: -32px -176px; } -.ui-icon-battery-0 { background-position: -48px -176px; } -.ui-icon-battery-1 { background-position: -64px -176px; } -.ui-icon-battery-2 { background-position: -80px -176px; } -.ui-icon-battery-3 { background-position: -96px -176px; } -.ui-icon-circle-plus { background-position: 0 -192px; } -.ui-icon-circle-minus { background-position: -16px -192px; } -.ui-icon-circle-close { background-position: -32px -192px; } -.ui-icon-circle-triangle-e { background-position: -48px -192px; } -.ui-icon-circle-triangle-s { background-position: -64px -192px; } -.ui-icon-circle-triangle-w { background-position: -80px -192px; } -.ui-icon-circle-triangle-n { background-position: -96px -192px; } -.ui-icon-circle-arrow-e { background-position: -112px -192px; } -.ui-icon-circle-arrow-s { background-position: -128px -192px; } -.ui-icon-circle-arrow-w { background-position: -144px -192px; } -.ui-icon-circle-arrow-n { background-position: -160px -192px; } -.ui-icon-circle-zoomin { background-position: -176px -192px; } -.ui-icon-circle-zoomout { background-position: -192px -192px; } -.ui-icon-circle-check { background-position: -208px -192px; } -.ui-icon-circlesmall-plus { background-position: 0 -208px; } -.ui-icon-circlesmall-minus { background-position: -16px -208px; } -.ui-icon-circlesmall-close { background-position: -32px -208px; } -.ui-icon-squaresmall-plus { background-position: -48px -208px; } -.ui-icon-squaresmall-minus { background-position: -64px -208px; } -.ui-icon-squaresmall-close { background-position: -80px -208px; } -.ui-icon-grip-dotted-vertical { background-position: 0 -224px; } -.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; } -.ui-icon-grip-solid-vertical { background-position: -32px -224px; } -.ui-icon-grip-solid-horizontal { background-position: -48px -224px; } -.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; } -.ui-icon-grip-diagonal-se { background-position: -80px -224px; } - - -/* Misc visuals -----------------------------------*/ - -/* Corner radius */ -.ui-corner-tl { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; border-top-left-radius: 4px; } -.ui-corner-tr { -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; border-top-right-radius: 4px; } -.ui-corner-bl { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; } -.ui-corner-br { -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; } -.ui-corner-top { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; border-top-left-radius: 4px; -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; border-top-right-radius: 4px; } -.ui-corner-bottom { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; } -.ui-corner-right { -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; border-top-right-radius: 4px; -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; } -.ui-corner-left { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; border-top-left-radius: 4px; -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; } -.ui-corner-all { -moz-border-radius: 4px; -webkit-border-radius: 4px; border-radius: 4px; } - -/* Overlays */ -.ui-widget-overlay { background: #666666 url(images/ui-bg_diagonals-thick_20_666666_40x40.png) 50% 50% repeat; opacity: .50;filter:Alpha(Opacity=50); } -.ui-widget-shadow { margin: -5px 0 0 -5px; padding: 5px; background: #000000 url(images/ui-bg_flat_10_000000_40x100.png) 50% 50% repeat-x; opacity: .20;filter:Alpha(Opacity=20); -moz-border-radius: 5px; -webkit-border-radius: 5px; border-radius: 5px; }/* - * jQuery UI Resizable 1.8.7 - * - * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Resizable#theming - */ -.ui-resizable { position: relative;} -.ui-resizable-handle { position: absolute;font-size: 0.1px;z-index: 99999; display: block;} -.ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; } -.ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0; } -.ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0; } -.ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0; height: 100%; } -.ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0; height: 100%; } -.ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; } -.ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; } -.ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; } -.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;}/* - * jQuery UI Selectable 1.8.7 - * - * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Selectable#theming - */ -.ui-selectable-helper { position: absolute; z-index: 100; border:1px dotted black; } -/* - * jQuery UI Accordion 1.8.7 - * - * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Accordion#theming - */ -/* IE/Win - Fix animation bug - #4615 */ -.ui-accordion { width: 100%; } -.ui-accordion .ui-accordion-header { cursor: pointer; position: relative; margin-top: 1px; zoom: 1; } -.ui-accordion .ui-accordion-li-fix { display: inline; } -.ui-accordion .ui-accordion-header-active { border-bottom: 0 !important; } -.ui-accordion .ui-accordion-header a { display: block; font-size: 1em; padding: .5em .5em .5em .7em; } -.ui-accordion-icons .ui-accordion-header a { padding-left: 2.2em; } -.ui-accordion .ui-accordion-header .ui-icon { position: absolute; left: .5em; top: 50%; margin-top: -8px; } -.ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; margin-top: -2px; position: relative; top: 1px; margin-bottom: 2px; overflow: auto; display: none; zoom: 1; } -.ui-accordion .ui-accordion-content-active { display: block; }/* - * jQuery UI Autocomplete 1.8.7 - * - * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Autocomplete#theming - */ -.ui-autocomplete { position: absolute; cursor: default; } - -/* workarounds */ -* html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */ - -/* - * jQuery UI Menu 1.8.7 - * - * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Menu#theming - */ -.ui-menu { - list-style:none; - padding: 2px; - margin: 0; - display:block; - float: left; -} -.ui-menu .ui-menu { - margin-top: -3px; -} -.ui-menu .ui-menu-item { - margin:0; - padding: 0; - zoom: 1; - float: left; - clear: left; - width: 100%; -} -.ui-menu .ui-menu-item a { - text-decoration:none; - display:block; - padding:.2em .4em; - line-height:1.5; - zoom:1; -} -.ui-menu .ui-menu-item a.ui-state-hover, -.ui-menu .ui-menu-item a.ui-state-active { - font-weight: normal; - margin: -1px; -} -/* - * jQuery UI Button 1.8.7 - * - * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Button#theming - */ -.ui-button { display: inline-block; position: relative; padding: 0; margin-right: .1em; text-decoration: none !important; cursor: pointer; text-align: center; zoom: 1; overflow: visible; } /* the overflow property removes extra width in IE */ -.ui-button-icon-only { width: 2.2em; } /* to make room for the icon, a width needs to be set here */ -button.ui-button-icon-only { width: 2.4em; } /* button elements seem to need a little more width */ -.ui-button-icons-only { width: 3.4em; } -button.ui-button-icons-only { width: 3.7em; } - -/*button text element */ -.ui-button .ui-button-text { display: block; line-height: 1.4; } -.ui-button-text-only .ui-button-text { padding: .4em 1em; } -.ui-button-icon-only .ui-button-text, .ui-button-icons-only .ui-button-text { padding: .4em; text-indent: -9999999px; } -.ui-button-text-icon-primary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 1em .4em 2.1em; } -.ui-button-text-icon-secondary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 2.1em .4em 1em; } -.ui-button-text-icons .ui-button-text { padding-left: 2.1em; padding-right: 2.1em; } -/* no icon support for input elements, provide padding by default */ -input.ui-button { padding: .4em 1em; } - -/*button icon element(s) */ -.ui-button-icon-only .ui-icon, .ui-button-text-icon-primary .ui-icon, .ui-button-text-icon-secondary .ui-icon, .ui-button-text-icons .ui-icon, .ui-button-icons-only .ui-icon { position: absolute; top: 50%; margin-top: -8px; } -.ui-button-icon-only .ui-icon { left: 50%; margin-left: -8px; } -.ui-button-text-icon-primary .ui-button-icon-primary, .ui-button-text-icons .ui-button-icon-primary, .ui-button-icons-only .ui-button-icon-primary { left: .5em; } -.ui-button-text-icon-secondary .ui-button-icon-secondary, .ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; } -.ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; } - -/*button sets*/ -.ui-buttonset { margin-right: 7px; } -.ui-buttonset .ui-button { margin-left: 0; margin-right: -.3em; } - -/* workarounds */ -button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra padding in Firefox */ -/* - * jQuery UI Dialog 1.8.7 - * - * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Dialog#theming - */ -.ui-dialog { position: absolute; padding: .2em; width: 300px; overflow: hidden; } -.ui-dialog .ui-dialog-titlebar { padding: .5em 1em .3em; position: relative; } -.ui-dialog .ui-dialog-title { float: left; margin: .1em 16px .2em 0; } -.ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .3em; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; } -.ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; } -.ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; } -.ui-dialog .ui-dialog-content { position: relative; border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; } -.ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; } -.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { float: right; } -.ui-dialog .ui-dialog-buttonpane button { margin: .5em .4em .5em 0; cursor: pointer; } -.ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; } -.ui-draggable .ui-dialog-titlebar { cursor: move; } -/* - * jQuery UI Slider 1.8.7 - * - * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Slider#theming - */ -.ui-slider { position: relative; text-align: left; } -.ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 1.2em; height: 1.2em; cursor: default; } -.ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; background-position: 0 0; } - -.ui-slider-horizontal { height: .8em; } -.ui-slider-horizontal .ui-slider-handle { top: -.3em; margin-left: -.6em; } -.ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; } -.ui-slider-horizontal .ui-slider-range-min { left: 0; } -.ui-slider-horizontal .ui-slider-range-max { right: 0; } - -.ui-slider-vertical { width: .8em; height: 100px; } -.ui-slider-vertical .ui-slider-handle { left: -.3em; margin-left: 0; margin-bottom: -.6em; } -.ui-slider-vertical .ui-slider-range { left: 0; width: 100%; } -.ui-slider-vertical .ui-slider-range-min { bottom: 0; } -.ui-slider-vertical .ui-slider-range-max { top: 0; }/* - * jQuery UI Tabs 1.8.7 - * - * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Tabs#theming - */ -.ui-tabs { position: relative; padding: .2em; zoom: 1; } /* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */ -.ui-tabs .ui-tabs-nav { margin: 0; padding: .2em .2em 0; } -.ui-tabs .ui-tabs-nav li { list-style: none; float: left; position: relative; top: 1px; margin: 0 .2em 1px 0; border-bottom: 0 !important; padding: 0; white-space: nowrap; } -.ui-tabs .ui-tabs-nav li a { float: left; padding: .5em 1em; text-decoration: none; } -.ui-tabs .ui-tabs-nav li.ui-tabs-selected { margin-bottom: 0; padding-bottom: 1px; } -.ui-tabs .ui-tabs-nav li.ui-tabs-selected a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-state-processing a { cursor: text; } -.ui-tabs .ui-tabs-nav li a, .ui-tabs.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-selected a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */ -.ui-tabs .ui-tabs-panel { display: block; border-width: 0; padding: 1em 1.4em; background: none; } -.ui-tabs .ui-tabs-hide { display: none !important; } -/* - * jQuery UI Datepicker 1.8.7 - * - * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Datepicker#theming - */ -.ui-datepicker { width: 17em; padding: .2em .2em 0; display: none; } -.ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; } -.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; } -.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; } -.ui-datepicker .ui-datepicker-prev { left:2px; } -.ui-datepicker .ui-datepicker-next { right:2px; } -.ui-datepicker .ui-datepicker-prev-hover { left:1px; } -.ui-datepicker .ui-datepicker-next-hover { right:1px; } -.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px; } -.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; } -.ui-datepicker .ui-datepicker-title select { font-size:1em; margin:1px 0; } -.ui-datepicker select.ui-datepicker-month-year {width: 100%;} -.ui-datepicker select.ui-datepicker-month, -.ui-datepicker select.ui-datepicker-year { width: 49%;} -.ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; } -.ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0; } -.ui-datepicker td { border: 0; padding: 1px; } -.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; } -.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; } -.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; } -.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; } - -/* with multiple calendars */ -.ui-datepicker.ui-datepicker-multi { width:auto; } -.ui-datepicker-multi .ui-datepicker-group { float:left; } -.ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; } -.ui-datepicker-multi-2 .ui-datepicker-group { width:50%; } -.ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; } -.ui-datepicker-multi-4 .ui-datepicker-group { width:25%; } -.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; } -.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; } -.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; } -.ui-datepicker-row-break { clear:both; width:100%; } - -/* RTL support */ -.ui-datepicker-rtl { direction: rtl; } -.ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; } -.ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; } -.ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; } -.ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; } -.ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; } -.ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; } -.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; } -.ui-datepicker-rtl .ui-datepicker-group { float:right; } -.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; } -.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; } - -/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */ -.ui-datepicker-cover { - display: none; /*sorry for IE5*/ - display/**/: block; /*sorry for IE5*/ - position: absolute; /*must have*/ - z-index: -1; /*must have*/ - filter: mask(); /*must have*/ - top: -4px; /*must have*/ - left: -4px; /*must have*/ - width: 200px; /*must have*/ - height: 200px; /*must have*/ -}/* - * jQuery UI Progressbar 1.8.7 - * - * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Progressbar#theming - */ -.ui-progressbar { height:2em; text-align: left; } -.ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; } \ No newline at end of file Index: tool/src/webapp/content/css/evaluation_base.css =================================================================== --- tool/src/webapp/content/css/evaluation_base.css (revision 81089) +++ tool/src/webapp/content/css/evaluation_base.css (working copy) @@ -19,958 +19,1393 @@ /*PART 1 - reorderer*/ /*Styles for the drag and drop as in template item reorderer*/ /*outer container of a sortable list*/ -DIV#itemTable{ - border: 1px solid #DFDFDF; - margin: .5em 0; - padding: 0 .5em; - background-color: #EEEEEE; +DIV#itemTable { + border: 1px solid #DFDFDF; + margin: .5em 0; + padding: 0 .5em; + background-color: #EEEEEE; } + /*outer container of a block sortable list*/ -DIV#itemTableBlock{ - border: 1px solid #DFDFDF; - margin: .5em 0; - padding: 0 .5em; - background-color: #EEEEEE; +DIV#itemTableBlock { + border: 1px solid #DFDFDF; + margin: .5em 0; + padding: 0 .5em; + background-color: #EEEEEE; } + /*inner container of a sortable list*/ -DIV.itemList{ - list-style-type: none; - marker-offset: 0; - margin: 0; - padding: 0 +DIV.itemList { + list-style-type: none; + marker-offset: 0; + margin: 0; + padding: 0; } + /*a sortable item*/ -DIV.itemRow{ - width: 100%; - padding: 0; - margin: .3em 0; - cursor: move; - background: #fff; - border: 1px solid #FFDD77; +DIV.itemRow { + width: 100%; + padding: 0; + margin: .3em 0; + cursor: move; + background: #fff; + border: 1px solid #FFDD77; } + /*a sortable block item*/ -DIV.itemRowBlock{ - width: 100%; - padding: 0; - margin: .3em 0; - cursor: move; - background: #fff; - border: 1px solid #FFDD77; +DIV.itemRowBlock { + width: 100%; + padding: 0; + margin: .3em 0; + cursor: move; + background: #fff; + border: 1px solid #FFDD77; } + /*all rows of an item*/ -.itemRow div{ padding: .2em; vertical-align: middle } +.itemRow div { + padding: .2em; + vertical-align: middle; +} + /*all rows of a block item*/ -.itemRowBlock div{ padding: .2em; vertical-align: middle } -.itemRowBlock .text {padding-right:80px;} +.itemRowBlock div { + padding: .2em; + vertical-align: middle; +} + +.itemRowBlock .text { + padding-right: 80px; +} + /*first line in a sortable item,item type and links*/ -div.itemLine{ - clear: left; - border-bottom: 1px solid #aaa; - background: #eee +div.itemLine { + clear: left; + border-bottom: 1px solid #aaa; + background: #eeeeee; } + /*itemCheckbox,itemType,itemRight are the 3 children of itemLine*/ -.itemCheckbox{ - cursor: default; - float: left; - padding: 0 1em 0 0; - margin-top: -0.04em; +.itemCheckbox { + cursor: default; + float: left; + padding: 0 1em 0 0; + margin-top: -0.04em; } -.itemCheckbox input{ margin: 0 } -span.itemType{ float: left; padding: 0 } -span.itemRight{ - font-size: 0.9em; - float: right; - white-space: nowrap; - padding-right: 0.4em; - padding-bottom: 0; - padding-left: 0.4em; - /*margin-top: -1.7em;*/ + +.itemCheckbox input { + margin: 0; } + +span.itemType { + float: left; + padding: 0; +} + +span.itemRight { + font-size: 0.9em; + float: right; + white-space: nowrap; + padding-right: 0.4em; + padding-bottom: 0; + padding-left: 0.4em; + /*margin-top: -1.7em;*/ +} + /*selectReorder,itemText,scaleDesc are the 3 children of the 2nd row*/ -select.selectReorder{ font-weight: bold; float: left } -h4.itemText{ - display: inline; - float: left; - padding: 0 0 0 0.3em; - overflow: hidden; - margin: 0.2em; - font-weight: normal; - position: static; +select.selectReorder { + font-weight: bold; + float: left; } + +h4.itemText { + display: inline; + float: left; + padding: 0 0 0 0.3em; + overflow: hidden; + margin: 0.2em; + font-weight: normal; + position: static; +} + /*lines created with the rteditor are rendered as

- so flatten out a tad for alignment. */ -.itemText p{ margin-top: 0 } -div.scaleDesc{ - float: right; - text-align: right; - white-space: nowrap +.itemText p { + margin-top: 0; } + +div.scaleDesc { + float: right; + text-align: right; + white-space: nowrap; +} + /*third line in a sortable item - an ol with sub items listed*/ -.itemLine3{ - clear: both; - margin: .5em .5em .5em 9.5em; - list-style-position: outside; - padding: 0; - line-height: 150%; - font-size: 0.95em; - cursor:default +.itemLine3 { + clear: both; + margin: .5em .5em .5em 9.5em; + list-style-position: outside; + padding: 0; + line-height: 150%; + font-size: 0.95em; + cursor: default; } + /*next 3 classes added/substracted script to Revert Order/Save Order and Group button bar after order has changed*/ -.orderChanged{ background-color: #ffc; border: 1px solid #fd7 } -.itemOperations{ - border: 1px solid #ffa; - background: #ffe; - padding: .3em +.orderChanged { + background-color: #ffc; + border: 1px solid #fd7; } -.itemOperationsEnabled{ - border: 1px solid #fd7; - background: #ffc; - padding: .3em + +.itemOperations { + border: 1px solid #ffa; + background: #ffe; + padding: 0.3em; } + +.itemOperationsEnabled { + border: 1px solid #fd7; + background: #ffc; + padding: 0.3em; +} + /*some items in edit template list will not have checkboxes - such as text items,headers - so reserve that space since this is not a table*/ -.checkPlaceholder{ - float: left; - cursor: default; - margin: 0; - visibility: hidden; - padding: 0 2.1em 0 0; +.checkPlaceholder { + float: left; + cursor: default; + margin: 0; + visibility: hidden; + padding: 0 2.1em 0 0; } + /*next "selectable" collection added/susbstracted via script to give hints while grouping template items*/ -.selectable{ - float: left; - cursor: default; - margin-top: -0.04em; - padding: 0 1em 0 0; - background: url(../images/asterisk_orange.gif) 1.3em 50% no-repeat +.selectable { + float: left; + cursor: default; + margin-top: -0.04em; + padding: 0 1em 0 0; + background: url(../images/asterisk_orange.gif) 1.3em 50% no-repeat; } -.selectable input{ margin: 0 } -.notselectable{ - float: left; - cursor: default; - margin-top: -0.04em; - padding: 0 1em 0 0; + +.selectable input { + margin: 0; } -.notselectable input{ margin: 0 } -.notselectable *{ - filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=50),progid:DXImageTransform.Microsoft.BasicImage(grayscale=1) !important; - -moz-opacity: .50 !important + +.notselectable { + float: left; + cursor: default; + margin-top: -0.04em; + padding: 0 1em 0 0; } + +.notselectable input { + margin: 0; +} + +.notselectable * { + filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=50), progid:DXImageTransform.Microsoft.BasicImage(grayscale=1) !important; + -moz-opacity: 0.5 !important; +} + /*PART 1 end*/ /*PART 2 - navigation, breadcrumbs*/ -.breadCrumb{ - font-size: .9em; - padding: .5em 0; - background: #ffe; - margin: 1em 0 +.breadCrumb { + font-size: .9em; + padding: .5em 0; + background: #ffe; + margin: 1em 0; } -.navIntraTool .breadCrumb{ margin: 0; float: left; } -.breadCrumb li{ - display: inline; - background: #ffe url(../images/breadSep.gif) center right no-repeat; - padding: 0 1.2em 0 .5em; - margin: 0 + +.navIntraTool .breadCrumb { + margin: 0; + float: left; } -.breadCrumb li:first-child{ padding-left: 3px } -.breadCrumb li.lastCrumb{ display: inline; background-image: none } + +.breadCrumb li { + display: inline; + background: #ffffee url(../images/breadSep.gif) center right no-repeat; + padding: 0 1.2em 0 .5em; + margin: 0; +} + +.breadCrumb li:first-child { + padding-left: 3px; +} + +.breadCrumb li.lastCrumb { + display: inline; + background-image: none; +} + /*sub-breadcrumb for wizards deep inside of a workflow*/ -.messageStepGraphic{ height: 100%; overflow: hidden; margin: 1em 0 } -.messageStepGraphic div{ width: 100px; float: left } -.messageStepGraphic a{ text-decoration: none !important; font-size: 1em } -.messageStepGraphic a:hover{ text-decoration: none !important } -.messageStepGraphic div span{ - margin-top: 2em; - font-size: 90%; - text-align: center; - color: #aaa; - display: block +.messageStepGraphic { + height: 100%; + overflow: hidden; + margin: 1em 0; } -.first-cur-step span,.med-cur-step span,.last-cur-step span{ color: #666 !important } -.messageStepGraphic .first-noncur-step{ - background: #fff url(../images/first-noncur-step.gif) top left no-repeat + +.messageStepGraphic div { + width: 100px; + float: left; } -.messageStepGraphic .first-cur-step{ - background: #fff url(../images/first-cur-step.gif) top left no-repeat + +.messageStepGraphic a { + text-decoration: none !important; + font-size: 1em; } -.messageStepGraphic .med-noncur-step{ - background: #fff url(../images/med-noncur-step.gif) top left no-repeat + +.messageStepGraphic a:hover { + text-decoration: none !important; } -.messageStepGraphic .med-cur-step{ - background: #fff url(../images/med-cur-step.gif) top left no-repeat + +.messageStepGraphic div span { + margin-top: 2em; + font-size: 90%; + text-align: center; + color: #aaa; + display: block; } -.messageStepGraphic .last-noncur-step{ - background: #fff url(../images/last-noncur-step.gif) top left no-repeat + +.first-cur-step span, .med-cur-step span, .last-cur-step span { + color: #666 !important; } -.messageStepGraphic .last-cur-step{ - background: #fff url(../images/last-cur-step.gif) top left no-repeat + +.messageStepGraphic .first-noncur-step { + background: white url(../images/first-noncur-step.gif) top left no-repeat; } + +.messageStepGraphic .first-cur-step { + background: white url(../images/first-cur-step.gif) top left no-repeat; +} + +.messageStepGraphic .med-noncur-step { + background: white url(../images/med-noncur-step.gif) top left no-repeat; +} + +.messageStepGraphic .med-cur-step { + background: white url(../images/med-cur-step.gif) top left no-repeat; +} + +.messageStepGraphic .last-noncur-step { + background: white url(../images/last-noncur-step.gif) top left no-repeat; +} + +.messageStepGraphic .last-cur-step { + background: white url(../images/last-cur-step.gif) top left no-repeat; +} + /*PART 2 end*/ /*PART 3 - summary page layout definitions*/ -.summaryBox{ border: 1px solid #aaa; margin: 0 0 1em 0 } -.summaryBox .innerPanel{ padding: .5em } -.summaryTable h4{ - background: #ddd !important; - margin-top: 0; - padding: .5em; - border-bottom: 1px solid #aaa +.summaryBox { + border: 1px solid #aaa; + margin: 0 0 1em 0; + padding: 1em; } -.summaryBox table th{ background: #eee; border: none } -ol.summaryEvaluateList{ margin: 0px; padding-left: 2em } + +.summaryBox .innerPanel { + padding: 0 10px; +} + +.summaryBox .innerPanel table { + margin-bottom: 1em; +} + +.summaryBox .innerPanel .sub-heading { + font-size: 1.3em; + color: #444; + font-weight: bold; +} + +.summaryBox .innerPanel .triangle-open, +.summaryBox .innerPanel .triangle-closed { + margin-left: -16px; + cursor: pointer; +} + +.summaryBox .innerPanel .triangle-closed:before { + content: "\25B6"; +} + +.summaryBox .innerPanel .triangle-open:before { + content: "\25BC"; +} + +.innerPanel table th { + position: relative; + padding: 8px 10px; +} + +.innerPanel table tbody td { + color: #555; + padding-left: 10px; +} + +.summaryTable h4 { + background: #ddd !important; + margin-top: 0; + padding: .5em; + border-bottom: 1px solid #aaaaaa; +} + +.summaryBox table th { + background-color: #eee; + border: none; +} + +ol.summaryEvaluateList { + margin: 0px; + padding-left: 2em; +} + /*PART 3 end*/ /*PART 4 - list of lists in item scales*/ -.scaleOuterList{ - width: 60%; - padding: 0; - margin: 1em 0; - list-style: decimal +.scaleOuterList { + width: 60%; + padding: 0; + margin: 1em 0; + list-style: decimal; } -.scaleInnerList{ - list-style: none; - background: #fff; - padding: 0 2em; - margin: 0 0 1em 0 + +.scaleInnerList { + list-style: none; + background: #fff; + padding: 0 2em; + margin: 0 0 1em 0; } -.scaleInnerList li{ padding-left: 1em; list-style-position: inside } -.scaleTitleLine{ - height: 1.5em; - overflow: hidden; - background: #eee; - padding: .3em + +.scaleInnerList li { + padding-left: 1em; + list-style-position: inside; } -.scaleTitleLineNum{ font-weight: bold; color: #333; float: left } -.scaleTitle{ - font-weight: bold; - color: #333; - width: 60%; - float: left; - padding-left: 1em + +.scaleTitleLine { + height: 1.5em; + overflow: hidden; + background: #eee; + padding: 0.3em; } -.scaleTitleLine .itemAction{ text-align: right; padding: 0 } -.idealScalePoint{ clear: both; padding: 0; text-align: right } + +.scaleTitleLineNum { + font-weight: bold; + color: #333; + float: left; +} + +.scaleTitle { + font-weight: bold; + color: #333; + width: 60%; + float: left; + padding-left: 1em; +} + +.scaleTitleLine .itemAction { + text-align: right; + padding: 0; +} + +.idealScalePoint { + clear: both; + padding: 0; + text-align: right; +} + /*PART 4 end*/ /*PART 5 - listing of evaluation items, in evaluations, eval previews, template previews, from outermost to innermost*/ -.itemListNew{ - width: 95%; - border-color: #eee; - border-style: solid; - border-width: 2px; - padding: .5em; - list-style: none +.itemListNew { + list-style: none; } -.itemListNew legend{ - padding: .3em .7em; - color: orange; - font-size: 110%; - margin-left: 1em + +.itemListNew legend { + padding: .3em .7em; + color: orange; + font-size: 110%; + margin-left: 1em; } -.itemListNew ol{ padding: 0; margin: 13px 0 0 } -.itemListNew li{ padding: .3em; margin: .3em; border: 1px solid #eee } -.itemListNew li:hover .itemScalePanel{ border: 1px solid #aaa; background: #fff } -.itemListEval li{ list-style: none; padding: .5em !important; margin: .2em} -.itemScalePanelNACell{background:#fff !important} +.itemListNew ol { + padding: 0; + margin: 13px 0 0; +} + +.itemListNew li { + border: 1px solid #eee; +} + +.itemListNew li:hover .itemScalePanel { + border: 1px solid #aaa; + background: #fff; +} + +.itemListEval li { + list-style: none; +} + +.itemScalePanelNACell { + background: #fff !important; +} + /*since these list items can contain list items,minimize inheritance*/ -.itemListEval li ul li,.itemListEval li ol li{ - list-style: disc; - list-style-position: inside; - border: none; - padding: .2em +.itemListEval li ul li, .itemListEval li ol li { + list-style: disc; + list-style-position: inside; + border: none; + margin-bottom: 3px; + margin-right: 3px; } -.itemListEval li ol li{ - list-style: decimal; - list-style-position: inside; - border: none; - padding: .2em + +.itemListEval li ol li { + list-style: decimal; + list-style-position: inside; + border: none; } -.itemListNew .itemListEval h4{ display: inline; color: #333 } -.itemListNew .itemListEval li:hover h4{ color: #000 } -.itemListEval label{ color: #333 } -.itemListEval label:hover{ color: #000 } -.itemScalePanel{ height: 31px; border: 1px solid #E1E1E1 } -.itemScalePanel:hover{ border: 1px solid #aaa } -.itemScalePanel td{ padding: .3em .5em } -.itemScalePanel .compactDisplayStart{ background: #FF8BA0 } -.itemScalePanel .compactDisplayEnd{ background: #8BE8A2 } -.itemScalePanel td.idealScale{ padding: 0 !important; vertical-align: top;} -.itemScalePanel td.idealScale div{ margin: 0 } -.itemScalePanel td.idealScale label{ - -moz-border-radius:.5em; - -webkit-border-radius:.5em; - text-align:center; - display:inline-block; - width:28px; - border:none - } +.itemListNew .itemListEval h4 { + display: inline; + color: #333; +} -.itemScalePanel td.idealScale label input{margin:3px 0px !important;} -.itemScalePanel td.idealScale .scaleChoiceColored label:hover{ - background: #fff; +.itemListNew .itemListEval li:hover h4 { + color: #000; } -.itemScalePanel td.idealScale .scaleChoiceNotColored label:hover{ - background: #eee; + +.itemListEval label { + color: #333; } -.scaleChoiceColored{width:100%;display:block;position:absolute;z-index:6;background-color:transparent;padding-top:1px} -.scaleChoiceNotColored{padding-top:2px;} -.scaleChoiceNotColored .scaleItemLabelSelected{background:#ccc;} -.scaleChoiceColored .scaleItemLabelSelected{background:#fff;} -.itemScalePanelNACell{background:transparent !important} -.idealScaleBack{ - width: 100%; - display: block; - position: absolute; - z-index: 5 +.itemListEval label:hover { + color: #000; } -.idealScaleBack img{ width: 100%; height: 29px; overflow: hidden } -.fullVertical ol li{ - margin: 0; - padding: .3em; - border: none; - list-style: none !important + +.itemScalePanel { + height: 31px; + border: 1px solid #E1E1E1; } + +.itemScalePanel:hover { + border: 1px solid #aaa; +} + +.itemScalePanel td { + padding: .3em .5em; +} + +.itemScalePanel .compactDisplayPositive { + background: #8BE8A2; +} + +.itemScalePanel .compactDisplayNegative { + background: #FF8BA0; +} + +.itemScalePanel td.idealScale { + padding: 0 !important; + vertical-align: top; +} + +.itemScalePanel td.idealScale div { + margin: 0; +} + +.itemScalePanel td.idealScale label { + -moz-border-radius: .5em; + -webkit-border-radius: .5em; + text-align: center; + display: inline-block; + width: 28px; + border: none; +} + +.itemScalePanel td.idealScale label input { + margin: 3px 0px !important; +} + +.itemScalePanel td.idealScale .scaleChoiceColored label:hover { + background: #fff; +} + +.itemScalePanel td.idealScale .scaleChoiceNotColored label:hover { + background: #eee; +} + +.scaleChoiceColored { + width: 100%; + display: block; + position: absolute; + z-index: 6; + background-color: transparent; + padding-top: 1px; +} + +.scaleChoiceNotColored { + padding-top: 2px; +} + +.scaleChoiceNotColored .scaleItemLabelSelected { + background: #ccc; +} + +.scaleChoiceColored .scaleItemLabelSelected { + background: #fff; +} + +.itemScalePanelNACell { + background: transparent !important; +} + +.idealScaleBack { + width: 100%; + display: block; + position: absolute; + z-index: 5; +} + +.idealScaleBack img { + width: 100%; + height: 29px; + overflow: hidden; +} + +.fullVertical ol li { + margin: 0; + padding: .3em; + border: none; + list-style: none !important; +} + td.fullDisplayHorizontalColoredWrapper { - padding-top:1em; + padding: 0 40px; } -.fullDisplayHorizontalColored{ - margin-top:0 !important; + +.fullDisplayHorizontalColored { + margin-top: 0 !important; } -.fullDisplayHorizontalScale{ - height:28px; + +.fullDisplayHorizontalScale { + height: 28px; } + .fullDisplayHorizontalScale td { - padding: 5px; - vertical-align:middle; - text-align:center; - white-space:nowrap; + padding: 8px !important; + vertical-align: middle; + text-align: center; + white-space: nowrap; } -.fullDisplayHorizontal label{ - font-weight:bold; - } -.fullDisplayHorizontalScale span{ - font-weight:bold; - padding-left:2em !important; - padding-right:2em !important; - -moz-border-radius:.5em; - -webkit-border-radius:.5em; + +.fullDisplayHorizontal label { + font-weight: bold; } -.fullDisplayHorizontalScale span:hover{ - background-color:#eee +.fullDisplayHorizontalScale span { + font-weight: bold; + padding-left: 2em !important; + padding-right: 2em !important; + -moz-border-radius: .5em; + -webkit-border-radius: .5em; } -.fullDisplayHorizontalScale .labelSelected{ - background-color:#eee + +.fullDisplayHorizontalScale span:hover { + background-color: #eeeeee; } + +.fullDisplayHorizontalScale .labelSelected { + background-color: #eeeeee; +} + .itemsListOddLine .fullDisplayHorizontalScale .labelSelected, .fullDisplayHorizontalColored .labelSelected, -.itemsListOddLine .fullDisplayHorizontalScale span:hover, .fullDisplayHorizontalColored span:hover{ - background-color:#fff; +.itemsListOddLine .fullDisplayHorizontalScale span:hover, .fullDisplayHorizontalColored span:hover { + background-color: #fff; } -.fullDisplayHorizontalScale .labelSelected, .fullDisplayHorizontalColored .labelSelected{ - background-image:url(../images/tick.png); - background-position: .5em; - background-repeat: no-repeat; - - padding:.5em; - } +.fullDisplayHorizontalScale .labelSelected, .fullDisplayHorizontalColored .labelSelected { + background-image: url(../images/tick.png); + background-position: .5em; + background-repeat: no-repeat; + padding: .5em; +} -.fullDisplayHorizontal td input{ -} .fullVertical, .fullDisplayHorizontal { - clear:both; - /* height:100%; EVALSYS-952*/ - overflow:hidden; - margin:1em 0; - padding:0 + clear: both; + /* height:100%; EVALSYS-952*/ + overflow: hidden; + padding: 0; } -.fullVertical li, .fullDisplayHorizontal li{ - border:1px solid #ccc !important; - float:left; - height:4em; - list-style-image:none !important; - list-style-position:outside !important; - list-style-type:none !important; - margin:0.3em; - padding:0 !important; - width:15em; - background: #fff; - -moz-border-radius:.5em; - -webkit-border-radius:.5em; - overflow:hidden; + +div.fullVertical { + margin-left: 40px; } -.fullVertical li label, .fullDisplayHorizontal li label{ - display:block; - margin:0; - font-weight:normal; - text-indent:-2em; - padding:0.5em 0.5em 0.5em 2.5em!important; - height:100%; - } + +.fullVertical li, .fullDisplayHorizontal li { + border: 1px solid #ccc !important; + float: left; + height: 4em; + list-style-image: none !important; + list-style-position: outside !important; + list-style-type: none !important; + background: #fff; + -moz-border-radius: .5em; + -webkit-border-radius: .5em; + overflow: hidden; + width: 15em; +} + +.fullVertical li label, .fullDisplayHorizontal li label { + display: block; + margin: 0; + font-weight: normal; + text-indent: -2em; + padding: 0.5em 0.5em 0.5em 2.5em!important; + height: 100%; +} + .fullVertical li:hover, .fullDisplayHorizontal li:hover { - background:#FDFFCC; - cursor:pointer; - } + background: #FDFFCC; + cursor: pointer; +} -.fullVertical li{ - margin:0.3em; - float:none; - width:50%; - height:auto; +.fullVertical li { + float: none; + width: 50%; + height: auto; } -.fullVertical li.checked, .fullDisplayHorizontal li.checked{ - background:#FDFFCC + +.fullVertical li.checked, .fullDisplayHorizontal li.checked { + background: #fdffcc; } -.fullVertical li.checkedNA, .fullDisplayHorizontal li.checkedNA{ - background:#ddd + +.fullVertical li.checkedNA, .fullDisplayHorizontal li.checkedNA { + background: #dddddd; } -.fullVertical li.na, .fullDisplayHorizontal li.na { - } -.fullVertical li.na{ - margin:1em 0 0 0.3em !important; - float:none; - width:50% !important; - text-align:left; - height:auto; + +.fullVertical li.na { + float: none; + width: 50% !important; + text-align: left; + height: auto; } + +.fullVertical li.na label, .fullDisplayHorizontal li.na { + border: 1px solid red !important; + -moz-border-radius: .5em; + -webkit-border-radius: .5em; + border-radius: .5em; +} + /*2nd toolbar item links*/ +.addItem { + padding-left: 2em; + background: transparent url(../images/add.png) center left no-repeat; +} -.addItem{ - padding-left: 2em; - background: transparent url(../images/add.png) center left no-repeat +.goToList { + padding-left: 2em; + background: transparent url(../images/application_view_list.png) center left no-repeat; } -.goToList{ - padding-left: 2em; - background: transparent url(../images/application_view_list.png) center left no-repeat + +.exportAction { + padding-left: 2em; + background: transparent url(../images/table_go.png) center left no-repeat; } -.exportAction{ - padding-left: 2em; - background: transparent url(../images/table_go.png) center left no-repeat + +.emailItem { + margin-left: 2em; + display: block; + height: 15px; + background: transparent url(../images/email-send.png) center left no-repeat; } -.emailItem{ - margin-left: 2em; - display: block; - height: 15px; - background: transparent url(../images/email-send.png) center left no-repeat + +/*see block items*/ +.steppedRowContainer { + border-collapse: collapse; } -/*see block items*/ -.steppedRowContainer{ border-collapse: collapse } -.steppedRowContainer tr:hover{ background: #eee } -.steppedRowContainer tr:hover td{ border-bottom: 1px solid #000; } -.steppedRowContainer tr:hover td.exclude{ border: none } - /* remove input width in template and use these instead */ -.scaleCell span {} -.scaleCell span img {} -.steppedRowContainer td.exclude span span{} -td.exclude input {padding:0px;margin:4px 10px 4px 4px;} -body:first-of-type td.exclude input {padding:0px;margin:4px 12px 4px 4px;} -span.topLabel {} +td.exclude input { + padding: 0px; + margin: 4px 10px 4px 4px; +} +body:first-of-type td.exclude input { + padding: 0px; + margin: 4px 12px 4px 4px; +} + /* remove input width in template and use these instead */ +.steppedRowContainer td td { + border: none; +} -.steppedRowContainer td{ - border-top: 1px solid #ccc; - border-bottom: 1px solid #ccc +.itemsListOddLine .steppedRowContainer td td { + border: none; } -.steppedRowContainer td td{ border: none } -.itemsListOddLine .steppedRowContainer tr:hover{ background: #fff } -.itemsListOddLine .steppedRowContainer td{ - border-top: 1px solid #fff; - border-bottom: 1px solid #fff + +#toolTip { + padding: 3px; + border: 1px solid #ccc; + position: absolute; + z-index: 10; + background: #ffe; + display: none; } -.itemsListOddLine .steppedRowContainer td td{ border: none } -#toolTip{padding:3px;border:1px solid #ccc;position:absolute;z-index:10;background:#ffe;display:none} -.questionCell{ - width:60% +.questionCell { + width: 60%; } -.answerCell{ +.NACell { + width: 75px !important; + padding-right: .5em; } -.NACell{ - width:28px !important;padding-right:.5em; + +.blockChoiceColored { + width: 100%; + display: block; + position: absolute; + z-index: 6; + background-color: transparent; } -.blockChoiceColored{ - width:100%;display:block;position:absolute;z-index:6;background-color:transparent; -} + .blockChoiceColored label.blockItemLabelSelected { - background:#fff; + background: #fff; } -.blockChoiceNotColored{ -} .blockChoiceNotColored label.blockItemLabelSelected { - background:#ccc; + background: #ccc; } -.blockItemLabelSelectedNA{ - background:#ccc; +.blockItemLabelSelectedNA { + background: #ccc; } -.blockChoiceColored label.blockItemLabel:hover{ - background:#fff; + +.blockChoiceColored label.blockItemLabel:hover { + background: #fff; } -.blockChoiceNotColored label.blockItemLabel:hover{ - background:#aaa; +.blockChoiceNotColored label.blockItemLabel:hover { + background: #aaa; } -.itemsListOddLine .blockChoiceNotColored label.blockItemLabel:hover{ - background:#eee; + +.itemsListOddLine .blockChoiceNotColored label.blockItemLabel:hover { + background: #eee; } -label.blockItemLabel, label.blockItemLabelNA{ - -moz-border-radius:.5em; - -webkit-border-radius:.5em; - text-align:center; - display:inline-block; - width:28px; +label.blockItemLabel, label.blockItemLabelNA { + -moz-border-radius: .5em; + -webkit-border-radius: .5em; + text-align: center; + display: inline-block; + width: 28px; } -label.blockItemLabel input, label.blockItemLabelNA input{margin:3px 0px !important;} -label.blockItemLabel:hover{ - background:#fff; + +label.blockItemLabel input, label.blockItemLabelNA input { + margin: 3px 0px !important; } -.itemDoneCheck{ + +label.blockItemLabel:hover { + background: #fff; } -.itemDoneCheckShow{ - background: url(../images/tick.png) center left no-repeat; + +.itemDoneCheckShow { + background: url(../images/tick.png) center left no-repeat; + display: inline-block; + height: 16px; + width: 16px; } -.blockItemHeaderHilite{ - color:#09C + +.blockItemHeaderHilite { + color: #0099cc; } /*PART 5 end*/ /*PART 6 - report view styling*/ -.itemListReport ol{ list-style: none; margin: 0; padding: 0 } -.itemListReport .showcomments,.itemListReport .showtextresponses{ margin: 1em; color: #666; margin-left: 3.5% } -.itemListReport .showcomments ol,.itemListReport .showtextresponses ol{ - list-style: lower-alpha; - list-style-position: outside; - line-height: 150% +.itemListReport ol { + list-style: none; + margin: 0; + padding: 0; } -.itemListReport .showcomments ol li,.itemListReport .showtextresponses ol li{ padding: .4em } -.itemListReport .showcomments li.itemsListOddLine,.itemListReport .showtextresponses li.itemsListOddLine{ background: #fff } + +.itemListReport .showcomments, .itemListReport .showtextresponses { + margin: 1em; + color: #666; + margin-left: 3.5%; +} + +.itemListReport .showcomments ol, .itemListReport .showtextresponses ol { + list-style: lower-alpha; + list-style-position: outside; + line-height: 150%; +} + +.itemListReport .showcomments ol li, .itemListReport .showtextresponses ol li { + padding: .4em; +} + +.itemListReport .showcomments li.itemsListOddLine, .itemListReport .showtextresponses li.itemsListOddLine { + background: #fff; +} + /*PART 6 end*/ /*PART 7 - messages*/ -.alertMessage ul{ padding: 0; margin: 0; list-style: none } -.alertMessage ul li{ padding: 0; margin: 0; list-style: none } +.alertMessage ul { + padding: 0; + margin: 0; + list-style: none; +} +.alertMessage ul li { + padding: 0; + margin: 0; + list-style: none; +} + /* .label {outline:1px solid lime !important;width:40%;} */ -.validFail{ /*class applied to the outermost parent of an element that has failed validation, can be styled, or children can be style as below*/} -.validFail .label{ color: #b11; font-weight: bold } -.validFail label{ color: #000 !important } -.validFailGlyph{ display:none; /* do not show if not child of .validFail */} -.validFail .validFailGlyph{ - display: inline; - color: #b11; - font-weight: bold; - font-size: 100%; - padding: 0 +.validFail { + /*class applied to the outermost parent of an element that has failed validation, can be styled, or children can be style as below*/ } -.compulsory{ /*class applied to the outermost parent of an element that has failed validation, can be styled, or children can be style as below*/} -.compulsory .label{ /* color: #b11; font-weight: bold */ } -.compulsory label{ /* color: #000 !important */ } -.compulsoryGlyph{ display:none; /* do not show if not child of .validFail */} -.compulsory .compulsoryGlyph{ - display: inline; - color: #b11; - font-weight: bold; - font-size: 100%; - padding: 0 +.validFail .label { + color: #b11; + font-weight: bold; } -.messageAlert{ - background: #FFEEEE url(../images/exclamation.gif) 5px 7px no-repeat; - border: 1px solid #FF5555; - color: #FF5555; - margin: .5em 0 +.validFail label { + color: #000 !important; } -.messageInformation{ - background: #ffe url(../images/asterisk_yellow.gif) 5px 7px no-repeat; - border: 1px solid #EEBB44; - color: #d93; - margin: .5em 0 + +.validFailGlyph { + display: none; + /* do not show if not child of .validFail */ } -.messageComfirm{ - background: #EEFFBB url(../images/accept.gif) 5px 7px no-repeat; - border: 1px solid #CCEE66; - color: #779900; - margin: .5em 0 + +.validFail .validFailGlyph { + display: inline; + color: #b11; + font-weight: bold; + font-size: 100%; + padding: 0; } -.messageAlert ul,.messageInformation ul,.messageComfirm ul{ list-style: none; padding: 3px; margin: 0 } -.messageAlert ul li,.messageInformation ul li,.messageComfirm ul li{ padding: 2px 0 2px 2em; margin: 0 } -.lighthighlight{ color: #000; padding-left: .5em } + +.compulsory { + /*class applied to the outermost parent of an element that has failed validation, can be styled, or children can be style as below*/ +} + +.compulsory .label { + /* color: #b11; font-weight: bold */ +} + +.compulsory label { + /* color: #000 !important */ +} + +.compulsoryGlyph { + display: none; + /* do not show if not child of .validFail */ +} + +.compulsory .compulsoryGlyph { + display: inline; + color: #b11; + font-weight: bold; + font-size: 100%; + padding: 0; +} + +.messageAlert { + background: #ffeeee url(../images/exclamation.gif) 5px 7px no-repeat; + border: 1px solid #FF5555; + color: #FF5555; + margin: 0.5em 0; +} + +.messageInformation { + background: #ffffee url(../images/asterisk_yellow.gif) 5px 7px no-repeat; + border: 1px solid #EEBB44; + color: #d93; + margin: 0.5em 0; +} + +.messageComfirm { + background: #eeffbb url(../images/accept.gif) 5px 7px no-repeat; + border: 1px solid #CCEE66; + color: #779900; + margin: 0.5em 0; +} + +.messageAlert ul, .messageInformation ul, .messageComfirm ul { + list-style: none; + padding: 3px; + margin: 0; +} + +.messageAlert ul li, .messageInformation ul li, .messageComfirm ul li { + padding: 2px 0 2px 2em; + margin: 0; +} + +.lighthighlight { + color: #000; + padding-left: .5em; +} + /*PART 7 end*/ /*PART 8 - utils and variants from sakai rendering*/ -.navIntraTool a.inactive{ text-decoration: none; font-weight: bold} -form{ margin: 0; display: inline } -.oddrow{ background-color: #E1E1E1 } +.navIntraTool a.inactive { + text-decoration: none; + font-weight: bold; +} + +form { + margin: 0; + display: inline; +} + +.oddrow { + background-color: #E1E1E1; +} + /*Special style to force divs to be able to work right when floating in all browsers*/ -.cleaner{ - clear: both; - height: 1px; - font-size: 1px; - border: none; - margin: 0; - padding: 0; - background: transparent +.cleaner { + clear: both; + height: 1px; + font-size: 1px; + border: none; + margin: 0; + padding: 0; + background: transparent; } -.toggler{ - /*the clickable target of a disclosure pair*/ - cursor:pointer; - color:#35b; - font-weight: bold; + +.toggler { + /*the clickable target of a disclosure pair*/ + cursor: pointer; + color: #35b; + font-weight: bold; } -.toggler:hover{ - color:#33f + +.toggler:hover { + color: #3333ff; } + /*a button masquerading as a link*/ -.makeLink{ - color: #27d; - padding: 0; - margin: 0; - background-color: transparent; - border: none; - text-decoration: underline; - cursor: pointer; /* keep IE 6 and 7 from creating h-padding proportionate to the length of the string */ - overflow: visible +.makeLink { + color: #27d; + padding: 0; + margin: 0; + background-color: transparent; + border: none; + text-decoration: underline; + cursor: pointer; + /* keep IE 6 and 7 from creating h-padding proportionate to the length of the string */ + overflow: visible; } -.makeLink:hover{ color: #33f; cursor: pointer } + +.makeLink:hover { + color: #33f; + cursor: pointer; + text-decoration: none; +} + /*cases of buttons masquerading as links in other locales*/ -.itemAction input.makeLink{ - font-family: verdana,arial; - font-size: 100%; - color: #27d; - padding: .2em .3em 1px 0; - white-space: nowrap +.itemAction input.makeLink { + font-family: verdana,arial; + font-size: 100%; + color: #27d; + padding: .2em .3em 1px 0; + white-space: nowrap; } -.navIntraTool input.makeLink{ - font-family: verdana,arial; - font-size: 100%; - color: #35b; - padding: 0; - white-space: nowrap + +.navIntraTool input.makeLink { + font-family: verdana,arial; + font-size: 100%; + color: #35b; + padding: 0; + white-space: nowrap; } -.navIntraTool input.makeLink:hover{ color: #33f } + +.navIntraTool input.makeLink:hover { + color: #33f; +} + /*generic odd line background*/ -.itemsListOddLine{ background-color: #eee } +.itemsListOddLine { + background-color: #eee; +} + /*sakai fieldsets are invisible,complex forms in this tool have the following class to organize themselves visually*/ -.visibleFS{ border: 1px solid #ccc; padding: 1em .5em } -.visibleFS legend{ padding: .2em; color: orange; margin-left: 1em } -label.block{ padding: 0 0 .3em 0 } -/*squeeze the default rteditor into a smaller space*/ -.evalEditorSmall{ width: 50em } -/*delete button*/ -.hideComment{ padding-left: 2em; background: transparent url(../images/cross.png) center left no-repeat} -.editComment { padding-left: 2em; background: transparent url(../images/pencil.png) center left no-repeat} +.visibleFS { + border: 1px solid #ccc; + padding: 1em .5em; +} +.visibleFS legend { + padding: .2em; + color: orange; + margin-left: 1em; +} +label.block { + padding: 0 0 .3em 0; +} -.actionArrow{ -background:#FFEEEE url(/library/image/sakai/collapse.gif) no-repeat scroll left 3px; -font-weight:bold; -padding:2px 5px 6px 13px; +/*squeeze the default rteditor into a smaller space*/ +.evalEditorSmall { + width: 50em; } +/*delete button*/ +.hideComment { + padding-left: 2em; + background: transparent url(../images/cross.png) center left no-repeat; +} + +.editComment { + padding-left: 2em; + background: transparent url(../images/pencil.png) center left no-repeat; +} + +.actionArrow { + background: #ffeeee url(/library/image/sakai/collapse.gif) no-repeat scroll left 3px; + font-weight: bold; + padding: 2px 5px 6px 13px; +} + .removeLink { - background:transparent url(/library/image/silk/delete.png) no-repeat scroll left center; - padding-left:1.6em; - text-indent: 110%; - overflow: hidden; - height: 25px; - width: 25px; + background: transparent url(/library/image/silk/delete.png) no-repeat scroll left center; + padding-left: 1.6em; + text-indent: 110%; + overflow: hidden; + height: 25px; + width: 25px; } + .editLink { -background:transparent url(/library/image/silk/pencil.png) no-repeat scroll left center; -padding-left:1.6em; + background: transparent url(/library/image/silk/pencil.png) no-repeat scroll left center; + padding-left: 1.6em; } + .preview { -/*background:transparent url(/library/image/silk/control_play.png) no-repeat scroll left center;*/ -padding-left:0.5em; + /*background:transparent url(/library/image/silk/control_play.png) no-repeat scroll left center;*/ + padding-left: 0.5em; } + a.more { -background-image: url(../images/collapsed.gif); -background-position:100% center; -background-repeat:no-repeat; -padding-left:10px; -padding-right:15px + background-image: url(../images/collapsed.gif); + background-position: 100% center; + background-repeat: no-repeat; + padding-left: 10px; + padding-right: 15px; } + a.less { -background-image: url(../images/expanded.gif); -background-position:100% center; -background-repeat:no-repeat; -padding-right:15px; -padding-left:10px; + background-image: url(../images/expanded.gif); + background-position: 100% center; + background-repeat: no-repeat; + padding-right: 15px; + padding-left: 10px; } + .removeArrow { - background-image: url(/library/image/sakai/expand-collapse.gif); - height: 7px; - width: 10px; - background-repeat: no-repeat; - margin-left: 97% + background-image: url(/library/image/sakai/expand-collapse.gif); + height: 7px; + width: 10px; + background-repeat: no-repeat; + margin-left: 97%; } + .removeDiv { - margin-top: -10px; - margin-left: 100% + margin-top: -10px; + margin-left: 100%; } -.removeFooter{ - background-color: #EEEEEE; - border-top-width: 2px; - border-top-style: solid; - border-top-color: #FFFFFF; +.removeFooter { + background-color: #EEEEEE; + border-top-width: 2px; + border-top-style: solid; + border-top-color: #FFFFFF; } -.removeBody{ - background-color: #EEEEEE; - margin-bottom: -5px; - margin-top: -5px; + +.removeBody { + background-color: #EEEEEE; + margin-bottom: -5px; + margin-top: -5px; } + .childControls { - color: #CCCCCC; - font-size: 10px; + color: #CCCCCC; + font-size: 10px; } + .childItem:hover { - background-color: #EEEEEE; + background-color: #EEEEEE; } + .childItemDrag { - cursor: move; - } + cursor: move; +} + /*************************************/ /* Inline Edit */ /* hover effect over editable element */ .inlineEdit-invitation { -border : 1px solid #999; - background : lightyellow; - cursor : pointer; - /*margin : -1px;*/ + border: 1px solid #999; + background: lightyellow; + cursor: pointer; + /*margin : -1px;*/ } + .inlineEdit-tooltip { - position : absolute; - background : #CCC; - border : 1px solid #999; - font : normal 75% sans-serif; - padding : 3px 5px; + position: absolute; + background: #CCC; + border: 1px solid #999; + font: normal 75% sans-serif; + padding: 3px 5px; } -.inlineEdit-field { -} /*Adapted from the SideBar Nav, this is for inlinePopups */ - -.popupMenu li.selectedTool span{ +.popupMenu li.selectedTool span { font-weight: bold; background-color: #E0E2E4; display: block; - padding-bottom : 2px; - padding-right : 10px !important; - padding-left : 10px; - padding-top : 2px; - margin-bottom : 0px; - margin-left : 0px; - margin-right : 0px; - margin-top : 0px; - background-position : center left !important; - background-repeat : no-repeat !important; + padding-bottom: 2px; + padding-right: 10px !important; + padding-left: 10px; + padding-top: 2px; + margin-bottom: 0px; + margin-left: 0px; + margin-right: 0px; + margin-top: 0px; + background-position: center left !important; + background-repeat: no-repeat !important; /*filter:alpha(opacity=50); opacity: 0.50; moz-opacity: 0.50;*/ } -.popupMenu li span{ -/*comment this line for a return to sanity -display:none*/ +.popupMenu li span { + /*comment this line for a return to sanity + display:none*/ } +.popupMenu li a:link, #toolMenu li a { + display: block; + text-decoration: none; + color: #333; + padding-bottom: 2px; + padding-left: 10px !important; + padding-right: 10px; + padding-top: 2px; + margin-bottom: 0px; + margin-left: 0px; + margin-right: 0px; + margin-top: 0px; + background-position: center left !important; + background-repeat: no-repeat !important; +} +.popupMenu li a:hover { + text-decoration: none; + color: #333; + background: #D2EAF0; +} -.popupMenu li a:link,#toolMenu li a{ -display: block; -text-decoration: none; -color: #333; -padding-bottom : 2px; -padding-left : 10px !important; -padding-right : 10px; -padding-top : 2px; -margin-bottom : 0px; -margin-left : 0px; -margin-right : 0px; -margin-top : 0px; -background-position : center left !important; -background-repeat : no-repeat !important; +.popupMenu li a.selected { + text-decoration: none; + color: #333; + cursor: text; +} +.popupMenu li a.selected:hover { + text-decoration: none; + color: #333; + cursor: text; } -.popupMenu li a:hover{ - text-decoration: none; - color: #333; - background: #D2EAF0; -} -.popupMenu li a.selected{ - text-decoration: none; - color: #333; - cursor: text; +.popupMenu { + width: 10.2em; + padding: 0; + margin: 0; + color: #333; + background: #F3F4F5; } -.popupMenu li a.selected:hover{ - text-decoration: none; - color: #333; - cursor: text; +.popupMenu ul { + width: auto; + list-style: none; + margin: 0; + padding-right: 0; + padding-left: 0; } -.popupMenu{ - width: 10.2em; - padding: 0; - margin: 0; - color: #333; - background: #F3F4F5; -} -.popupMenu ul{ - width:auto; - list-style: none; - margin: 0; - padding-right: 0; - padding-left: 0; +.popupMenu li { + margin: 0; + width: auto; + padding: 0; + border-bottom: 1px solid #fff; + text-align: left; } -.popupMenu li{ - - margin: 0; - width: auto; - padding: 0; - border-bottom: 1px solid #fff; - text-align: left; -} /* Overlay */ #overlay { + visibility: hidden; + position: absolute; + left: 0px; + top: 0px; + width: 100%; + height: 100%; + text-align: center; + z-index: 1000; +} - visibility: hidden; - - position: absolute; - - left: 0px; - - top: 0px; - - width:100%; - - height:100%; - - text-align:center; - - z-index: 1000; - +#overlay div { + width: 300px; + margin: 100px auto; + background-color: #fff; + border: 1px solid #000; + padding: 15px; + text-align: center; } -#overlay div { - width:300px; - - margin: 100px auto; - - background-color: #fff; - - border:1px solid #000; - - padding:15px; - - text-align:center; - -} /* Comment box warn */ .commentWarn { - color:#DD9933 + color: #dd9933; } + .previewEvalNote { - padding:5px; margin:10px; border: 1px solid rgb(255, 204, 0); background: rgb(255, 255, 204); width:97% + padding: 5px; + margin: 10px; + border: 1px solid #ffcc00; + background: #ffffcc; + width: 97%; } -.validFail{ - /* top parent of failed group - can have a border, for example, or just style children below - */ + +.validFail { + /* top parent of failed group + can have a border, for example, or just style children below + */ } -.validFail .label{ - color:#b11; - font-weight:bold; + +.validFail .label { + color: #b11; + font-weight: bold; } -.validFail label{ - color:#000 !important; - + +.validFail label { + color: #000 !important; } +.validFailGlyph { + display: none; + /* do not show if not child of .validFail */ +} -.validFailGlyph{ - display:none; /* do not show if not child of .validFail */ +.validFail .validFailGlyph { + display: inline; + color: #b11; + font-weight: bold; + font-size: 100%; + padding: 0; } -.validFail .validFailGlyph{ - display:inline; - color:#b11; - font-weight:bold; - font-size:100%; - padding:0; + +.infoItem { + padding-left: 2em; + background: transparent url(/library/image/sakai/information.png) center left no-repeat; } -.infoItem{ - padding-left: 2em; - background: transparent url(/library/image/sakai/information.png) center left no-repeat + +.itemListReport ol { + list-style: none; + margin: 0; + padding: 0; } +.itemListReport .showcomments, .itemListReport .showtextresponses { + margin: 1em; + color: #666; + margin-left: 3.5%; +} -.itemListReport ol{ - list-style: none; - margin:0; - padding:0 +.itemListReport .showcomments ol, .itemListReport .showtextresponses ol { + list-style: lower-alpha; + list-style-position: outside; + line-height: 150%; } -.itemListReport .showcomments, .itemListReport .showtextresponses{ - margin: 1em; - color:#666; - margin-left:3.5% + +.itemListReport .showcomments ol li, .itemListReport .showtextresponses ol li { + padding: 0.4em; } -.itemListReport .showcomments ol, .itemListReport .showtextresponses ol{ - list-style: lower-alpha; list-style-position: outside;line-height:150% + +.itemListReport .showcomments li.itemsListOddLine, .itemListReport .showtextresponses li.itemsListOddLine { + background: white; } -.itemListReport .showcomments ol li, .itemListReport .showtextresponses ol li{ - padding:.4em + +.messageAlert { + background: #ffeeee url(../images/exclamation.gif) 5px 7px no-repeat; + border: 1px solid #FF5555; + color: #FF5555; + margin: .5em 0; } -.itemListReport .showcomments li.itemsListOddLine, .itemListReport .showtextresponses li.itemsListOddLine{ - background:#fff + +.messageInformation { + background: #ffffee url(../images/asterisk_yellow.gif) 5px 7px no-repeat; + border: 1px solid #EEBB44; + color: #d93; + margin: .5em 0; } -.messageAlert{ - background: #FFEEEE url(../images/exclamation.gif) 5px 7px no-repeat; - border:1px solid #FF5555; - color:#FF5555; - margin:.5em 0; +.messageComfirm { + background: #eeffbb url(../images/accept.gif) 5px 7px no-repeat; + border: 1px solid #CCEE66; + color: #779900; + margin: .5em 0; } -.messageInformation{ - background: #ffe url(../images/asterisk_yellow.gif) 5px 7px no-repeat; - border:1px solid #EEBB44; - color:#d93; - margin:.5em 0; -} -.messageComfirm{ - background: #EEFFBB url(../images/accept.gif) 5px 7px no-repeat; - border:1px solid #CCEE66; - color:#779900; - margin:.5em 0; -} + .messageAlert ul, .messageInformation ul, .messageComfirm ul { - list-style: none; - padding:3px; - margin:0; + list-style: none; + padding: 3px; + margin: 0; } + .messageAlert ul li, .messageInformation ul li, .messageComfirm ul li { - padding:2px 0 2px 2em; - margin:0 + padding: 2px 0 2px 2em; + margin: 0; } -.listPager {color:#ccc;padding:0 3px;font-weight: bold;font-size:1.2em} -.listPager a {text-decoration:none !important;padding: 0 1em;border:1px solid #ccc;background:#eee url(../images/pager-back.png) repeat-x !important} -.listPager span {padding: 0 1em;border:1px solid #ccc;background:#fff} -.listPager a:hover {text-decoration:none !important;padding: 0 1em;border:1px solid #bbb;background:#eee url(../images/pager-back-hover.png) repeat-x !important} -.listPager span.listPagerCount{border:0;font-size:.8em} +.listPager { + color: #ccc; + padding: 0 3px; + font-weight: bold; + font-size: 1.2em; +} +.listPager a { + text-decoration: none !important; + padding: 0 1em; + border: 1px solid #ccc; + background: #eeeeee url(../images/pager-back.png) repeat-x !important; +} + +.listPager span { + padding: 0 1em; + border: 1px solid #ccc; + background: #fff; +} + +.listPager a:hover { + text-decoration: none !important; + padding: 0 1em; + border: 1px solid #bbb; + background: #eeeeee url(../images/pager-back-hover.png) repeat-x !important; +} + +.listPager span.listPagerCount { + border: 0; + font-size: .8em; +} + /* for fullDisplayHorizontal (adjustable) support - default sizes, styles of blocks that have heigth adjusted via jquery. Waiting on a opinions from Hattie see: http://bugs.sakaiproject.org/jira/browse/EVALSYS-426*/ @@ -1012,24 +1447,25 @@ .fullDisplayHorizontal .na{ margin:1em .2em; }*/ - /* Group template item - add existing item into group */ -.dropItem{ - padding-bottom:1px; - background: transparent url(/library/image/silk/page_white_put.png) center left no-repeat +.dropItem { + padding-bottom: 1px; + background: transparent url(/library/image/silk/page_white_put.png) center left no-repeat; } -.JSshow{ - padding-right: 5px; - text-decoration: none; +.JSshow { + padding-right: 5px; + text-decoration: none; } /* fake-fieldset to fix EVALSYS-551 */ .fake-fieldset .fieldset { - border: solid 2px #eee; margin-top: 20px; position: relative; - } + padding: 8px; + padding-top: 16px; + border: 1px solid #ccc; +} .fake-fieldset .legend { left: 0.5em; @@ -1037,96 +1473,614 @@ background: white; position: absolute; font-weight: bold; - color:orange; - font-size:110%; - margin-left:1em; - padding:0.3em 0.7em; - } - -.elementAlertBack{ - background: transparent url(/library/image/silk/error.png) no-repeat scroll right 0; - padding-right: 20px + color: orange; + font-size: 110%; + margin-left: 32px; + padding: 6px 10px; } -.elementAlertFront{ - background: transparent url(/library/image/silk/error.png) no-repeat scroll left 0; - padding-left: 20px +.elementAlertBack { + background: transparent url(/library/image/silk/error.png) no-repeat scroll right 0; + padding-right: 20px; } +.elementAlertFront { + background: transparent url(/library/image/silk/error.png) no-repeat scroll left 0; + padding-left: 20px; +} + /* style selection controls fieldset */ -.selectionsItemListNew{ - width: 95%; - border-color: #eee; - border-style: solid; - border-width: 2px; - padding: .5em; - list-style: none +.selectionsItemListNew { + width: 95%; + border-color: #eee; + border-style: solid; + border-width: 2px; + padding: .5em; + list-style: none; } -.selectionsItemListNew legend{ - padding: .3em .7em; - color: orange; - font-size: 110%; - margin-left: 1em + +.selectionsItemListNew legend { + padding: .3em .7em; + color: orange; + font-size: 110%; + margin-left: 1em; } .evalAdminTable { - border: 1px solid #eee; - margin-top: 20px; + border: 1px solid #eee; + margin-top: 20px; } .evalAdminTable thead tr { - background: #ccc; + background: #ccc; } .evalAdminTable td { - padding: 0 20px; + padding: 0 20px; } +.column { + width: 25%; +} + /* hierarchy node perms page */ - table#user-perms-table { - margin: 15px 0; - border: 1px solid #ccc; + margin: 15px 0; + border: 1px solid #ccc; } table#user-perms-table thead { - background: #aaa; + background: #aaa; } table#user-perms-table tr { - padding: 10px 0; + padding: 10px 0; } table#user-perms-table tbody tr:nth-child(2n) { - background: #eee; + background: #eee; } table#user-perms-table td { - padding: 10px; + padding: 10px; } table#user-perms-table td.userInfo { - text-align: center; + text-align: center; } table#user-perms-table td.actions { - text-align: center; + text-align: center; } table#user-perms-table td.userPerms > span:nth-child(2n+1) { - clear: left; - float: left; - width: 140px; + clear: left; + float: left; + width: 140px; } table#user-perms-table td.userPerms > span:nth-child(2n) { - float: left; + float: left; } +/* tablesorter - mostly on the dashboard */ +table.tablesorter th.header { + cursor: pointer; + background-repeat: no-repeat; + background-position: center left; +} + +table.tablesorter th.header.headerSortUp { + background-image: url(../images/tipsy-north.gif); + font-weight: bold; + padding-left: 14px !important; +} + +table.tablesorter th.header.headerSortDown { + background-image: url(../images/tipsy-south.gif); + font-weight: bold; + padding-left: 14px !important; +} + +/* admin checkbox alignment - EVALSYS-1250 */ +.administrate-form .cbxmultlftalgn label { + padding-left: 1.7em; +} + +.administrate-form .cbxmultlftalgn input.cbx { + float: left; + position: absolute; +} + .matrixHeader { - float: right; - overflow: hidden; - width: 28px; - font-weight: bold; - text-align: center; -} \ No newline at end of file + float: right; + overflow: hidden; + width: 28px; + font-weight: bold; + text-align: center; +} + +.evaluation .itemListEval { + margin-top: 0; +} +.evaluation .itemListEval .evalItemTop { + margin: 16px 0 !important; + padding-top: 16px; + padding-bottom: 16px; + padding-right: 16px; +} +.evaluation .itemListEval .evalItemTop:first-child { + margin-top: 0 !important; +} +.evaluation .item.multiple-choice .content, .evaluation .item.multiple-answer .content { + margin-left: 40px; +} +.evaluation .item .title { + position: relative; + margin-top: 0; + margin-bottom: 16px; + padding: 0; +} +.evaluation .item .title span { + display: inline-block; +} +.evaluation .item .title .number { + position: absolute; + width: 26px; + text-align: right; +} +.evaluation .item .title .delineator, .evaluation .item .title .required { + position: absolute; +} +.evaluation .item .title .delineator { + left: 26px; +} +.evaluation .item .title .delineator .paren { + display: none; +} +.evaluation .item .title .delineator .dot { + display: inline-block; +} +.evaluation .item .title .required { + left: 2.5em; + display: none; +} +.evaluation .item .title .label { + margin-left: 40px; +} +.evaluation .item .compulsory .title .required { + display: inline-block; +} +.evaluation .item .numberWrapper { + text-align: right; + display: -moz-inline-box; + -moz-box-orient: vertical; + display: inline-block; + vertical-align: middle; + *vertical-align: auto; + width: 30px; + padding-right: 6px; + font-weight: bold; + vertical-align: top; +} +.evaluation .item .numberWrapper { + *display: inline; +} +.evaluation .item .steppedLabel { + font-weight: bold; + display: -moz-inline-box; + -moz-box-orient: vertical; + display: inline-block; + vertical-align: middle; + *vertical-align: auto; + width: 80%; +} +.evaluation .item .steppedLabel { + *display: inline; +} +.evaluation .item.blockItemGroup { + font-size: 13px; +} +.evaluation .item.blockItemGroup .groupHeader { + padding-left: 42px; + padding-bottom: 24px; + font-weight: bold; + font-family: Arial, sans-serif; + color: #000; +} +.evaluation .item.blockItemGroup .steppedLabel { + font-weight: normal; +} +.evaluation .item.blockItemGroup .questionCell { + padding: 0.2em; + height: 24px; + padding-bottom: 14px; +} +.evaluation .item.blockItemGroup .answerCell table { + margin-right: 2px; +} +.evaluation .item.blockItemGroup .blockItemLabel { + margin-left: 0; + font-weight: normal; +} +.evaluation .item.blockItemGroup .actualHeader { + display: -moz-inline-box; + -moz-box-orient: vertical; + display: inline-block; + vertical-align: middle; + *vertical-align: auto; + padding-top: 4px; +} +.evaluation .item.blockItemGroup .actualHeader { + *display: inline; +} +.evaluation .item.text .content { + position: relative; +} +.evaluation .item.text .content textarea { + width: 90%; + min-width: 600px; + padding: 0; + margin: 0; + margin-left: 40px; +} +.evaluation .item.text .content .na { + position: absolute; + top: 0; + right: 0; + padding: 4px; + border: 1px solid red; + -webkit-border-radius: .5em; + -moz-border-radius: .5em; + border-radius: .5em; +} +.evaluation .matrix { + min-width: 800px; +} +.evaluation .matrix .title { + min-width: 40%; +} +.evaluation .matrix fieldset { + margin: 0; + padding: 0; + border: none; +} +.evaluation .matrix fieldset legend { + padding: 0; + position: absolute; + right: 0; + width: 100%; + text-align: center; +} +.evaluation .matrix fieldset legend .response-type, .evaluation .matrix fieldset legend .response-scale-delineator { + border: 0; + clip: rect(0 0 0 0); + height: 1px; + margin: -1px; + overflow: hidden; + padding: 0; + position: absolute; + width: 1px; +} +.evaluation .matrix fieldset legend .response-scale-end { + position: absolute; + top: 0; + right: 10px; +} +.evaluation .matrix fieldset legend .response-scale-start { + position: absolute; + top: 0; +} +.evaluation .matrix fieldset legend .response-scale-start { + left: 70px; +} +.evaluation .matrix fieldset legend .response-scale-middle { + position: relative; + left: 32px; +} +.evaluation .scale .matrix { + position: relative; + zoom: 1; +} +.evaluation .scale .matrix:before, .evaluation .scale .matrix:after { + content: "\0020"; + display: block; + height: 0; + overflow: hidden; +} +.evaluation .scale .matrix:after { + clear: both; +} +.evaluation .scale .matrix .title { + float: left; +} +.evaluation .scale .matrix label span, .evaluation .scale .matrix label input, .evaluation .scale .matrix legend .response-scale-label { + font-family: sans-serif !important; + font-size: 12px !important; +} +.evaluation .scale .matrix .content { + margin: 0; + padding: 0; + text-align: right; + float: right; +} +.evaluation .scale .matrix .content ol, .evaluation .scale .matrix .content ul, .evaluation .scale .matrix .content li { + margin: 0; + padding: 0; +} +.evaluation .scale .matrix .content li { + list-style-type: none; + display: inline-block; +} +.evaluation .scale .matrix .content fieldset { + position: relative; +} +.evaluation .scale .matrix .content .response-list { + padding-top: 16px; +} +.evaluation .scale .matrix .content .response-list li { + margin: 0; + padding: 0 !important; +} +.evaluation .scale .matrix .content .response-list li.na { + margin-right: 5px; + padding-right: 5px !important; + border-right: 1px solid #CCCCCC; +} +.evaluation .scale .matrix .content label { + display: inline-block; + margin: 0; + padding: 5px 15px; + font-family: sans-serif !important; + font-size: 12px !important; + line-height: 100%; + text-align: center; + text-decoration: none !important; + cursor: pointer !important; + -webkit-border-radius: 4px 4px; + -moz-border-radius: 4px / 4px; + -ms-border-radius: 4px / 4px; + -o-border-radius: 4px / 4px; + border-radius: 4px / 4px; +} +.evaluation .scale .matrix .content label span { + display: block; + margin-bottom: 5px; +} +.evaluation .scale .matrix .matrixRadioItems-2 { + min-width: 180px; +} +.evaluation .scale .matrix .matrixRadioItems-3 { + min-width: 120px; +} +.evaluation .scale .matrix .matrixRadioItems-4 { + min-width: 80px; +} +.evaluation .scale .matrix .matrixRadioItems-5 { + min-width: 60px; +} +.evaluation .scale .compact .title { + float: left; + width: auto !important; + margin-top: 6px; +} +.evaluation .scale .compact .content { + overflow: hidden; +} +.evaluation .scale .compact .content table { + float: right; +} +.evaluation .item-group { + position: relative; + zoom: 1; +} +.evaluation .item-group:before, .evaluation .item-group:after { + content: "\0020"; + display: block; + height: 0; + overflow: hidden; +} +.evaluation .item-group:after { + clear: both; +} +.evaluation .item-group > .title { + float: left; + margin: 0; + margin-bottom: 16px; + margin-left: 42px; +} +.evaluation .item-group > .content { + display: inline-block; + width: 100%; +} +.evaluation .item-group > .content > fieldset { + display: inline-block; + width: 100%; +} +.evaluation .item-group > .content > fieldset legend { + position: absolute; + top: 0px; + right: 0px; +} +.evaluation .item-group > .content .item { + margin-bottom: 0; +} +.evaluation .item-group .item { + display: block; + margin: 0; +} +.evaluation .item-group .item .title .label { + padding-left: 2px; +} +.evaluation .item-group .item legend { + display: none; +} +.evaluation .item-group .item .content .response-list span { + border: 0; + clip: rect(0 0 0 0); + height: 1px; + margin: -1px; + overflow: hidden; + padding: 0; + position: absolute; + width: 1px; +} +.evaluation .item-group .response-scale-container { + height: 1em; + display: block; +} +.evaluation .item-group .response-group-labels { + display: block; + margin-top: 0.75em; + text-align: right !important; + white-space: nowrap; +} +.evaluation .item-group .response-scale-label { + display: inline-block; + padding: 0 19px; + width: 13px; + font-family: sans-serif !important; + font-size: 12px !important; + line-height: 100%; + text-align: center; + padding: 0 18px\9; + width: 15px\9; +} +.evaluation .item-group .response-scale-na { + margin-right: 11px; + width: 24px; + padding: 0 17px 0 13px; +} +.evaluation .item-group .item .matrix { + padding-top: 8px; +} +.evaluation .item-group .item .matrix .title { + padding: 4px 0; + margin-bottom: 0; +} +.evaluation .item-group .item .matrix .response-list { + padding-top: 0 !important; +} +.evaluation .steppedItemGroup { + font-size: 13px; +} +.evaluation .steppedItemGroup .choiceGroup { + padding-right: 0.2em; +} +.evaluation .steppedItemGroup .blockItemLabel { + margin-left: 0; +} +.evaluation .steppedItemGroup img, +.evaluation .steppedItemGroup table td { + vertical-align: middle; +} +.evaluation .matrix .response-scale-na, .evaluation .matrix .na { + visibility: hidden !important; +} +.evaluation .use-na .matrix .response-scale-na, .evaluation .use-na .matrix .na { + visibility: visible !important; +} +.evaluation .JSevalComment { + margin: 0 0 15px 55px; +} + +@-moz-document url-prefix() { + .evaluation .item-group .response-group-labels { + padding-right: 10px; + } + + .evaluation .item-group .response-group-labels span { + padding-left: 34px; + width: 0; + } + + .evaluation .item-group .response-group-labels .response-scale-na { + padding-left: 0 !important; + margin-right: 26px; + } +} + +.portletBody .left-separator { + border-left: 1px solid #aaa; + padding-left: 5px !important; + margin-left: 2px; +} +.portletBody table.listHier .itemAction a:hover { + border-bottom: none !important; +} +.portletBody .summaryBox h4 { + font-size: 1.5em; + margin: 0.3em 0 0.7em 10px; + padding: 0.1em 0 0 0; +} +.portletBody .title { + font-size: 100%; + font-weight: bold; + color: #000; +} +.portletBody .title .required { + color: red; +} +.portletBody .matrix legend { + font-weight: normal; + font-size: 0.85em; + color: #000; +} +.portletBody .item-group .item .title .label { + font-weight: normal; +} + +.urgentStyle { + color: red; + font-weight: bold; +} + +.evaluation .content .response-list label { + font-family: verdana, sans-serif; + font-size: 11px; + color: #000000; + text-shadow: none; + background: #ffffff; + border: 1px solid #ffffff; +} +.evaluation .content .response-list label:hover, .evaluation .content .response-list label:focus { + color: #000000; + background: #ee4444; + background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #ffffff), color-stop(100%, #ffa500)); + background-image: -webkit-linear-gradient(#ffffff, #ffa500); + background-image: -moz-linear-gradient(#ffffff, #ffa500); + background-image: -o-linear-gradient(#ffffff, #ffa500); + background-image: -ms-linear-gradient(#ffffff, #ffa500); + background-image: linear-gradient(#ffffff, #ffa500); + border-color: #ffa500; +} +.evaluation .content .response-list .selected { + color: #ffffff; + text-shadow: none; + background: #264c83; + background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #3163ab), color-stop(100%, #1b355b)); + background-image: -webkit-linear-gradient(#3163ab, #1b355b); + background-image: -moz-linear-gradient(#3163ab, #1b355b); + background-image: -o-linear-gradient(#3163ab, #1b355b); + background-image: -ms-linear-gradient(#3163ab, #1b355b); + background-image: linear-gradient(#3163ab, #1b355b); + border: 1px solid #0f1e34; +} +.evaluation .content .response-list .selected span { + color: #ffffff; +} +.evaluation .content .response-list .selected:hover, .evaluation .content .response-list .selected:focus { + color: #ffffff; + text-shadow: none; + background: #264c83; + background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #3163ab), color-stop(100%, #1b355b)); + background-image: -webkit-linear-gradient(#3163ab, #1b355b); + background-image: -moz-linear-gradient(#3163ab, #1b355b); + background-image: -o-linear-gradient(#3163ab, #1b355b); + background-image: -ms-linear-gradient(#3163ab, #1b355b); + background-image: linear-gradient(#3163ab, #1b355b); + border: 1px solid #0f1e34; +} +.evaluation .content .response-list .selected:hover span, .evaluation .content .response-list .selected:focus span { + color: #ffffff; +} Property changes on: tool/src/webapp/content/css/evaluation_base.css ___________________________________________________________________ Modified: svn:mergeinfo Merged /evaluation/branches/unicon-ucb/tool/src/webapp/content/css/evaluation_base.css:r78148-81089 Index: tool/src/webapp/content/js/jquery/jquery.js =================================================================== --- tool/src/webapp/content/js/jquery/jquery.js (revision 81089) +++ tool/src/webapp/content/js/jquery/jquery.js (working copy) @@ -1,3549 +0,0 @@ -(function(){ -/* - * jQuery 1.2.6 - New Wave Javascript - * - * Copyright (c) 2008 John Resig (jquery.com) - * Dual licensed under the MIT (MIT-LICENSE.txt) - * and GPL (GPL-LICENSE.txt) licenses. - * - * $Date$ - * $Rev$ - */ - -// Map over jQuery in case of overwrite -var _jQuery = window.jQuery, -// Map over the $ in case of overwrite - _$ = window.$; - -var jQuery = window.jQuery = window.$ = function( selector, context ) { - // The jQuery object is actually just the init constructor 'enhanced' - return new jQuery.fn.init( selector, context ); -}; - -// A simple way to check for HTML strings or ID strings -// (both of which we optimize for) -var quickExpr = /^[^<]*(<(.|\s)+>)[^>]*$|^#(\w+)$/, - -// Is it a simple selector - isSimple = /^.[^:#\[\.]*$/, - -// Will speed up references to undefined, and allows munging its name. - undefined; - -jQuery.fn = jQuery.prototype = { - init: function( selector, context ) { - // Make sure that a selection was provided - selector = selector || document; - - // Handle $(DOMElement) - if ( selector.nodeType ) { - this[0] = selector; - this.length = 1; - return this; - } - // Handle HTML strings - if ( typeof selector == "string" ) { - // Are we dealing with HTML string or an ID? - var match = quickExpr.exec( selector ); - - // Verify a match, and that no context was specified for #id - if ( match && (match[1] || !context) ) { - - // HANDLE: $(html) -> $(array) - if ( match[1] ) - selector = jQuery.clean( [ match[1] ], context ); - - // HANDLE: $("#id") - else { - var elem = document.getElementById( match[3] ); - - // Make sure an element was located - if ( elem ){ - // Handle the case where IE and Opera return items - // by name instead of ID - if ( elem.id != match[3] ) - return jQuery().find( selector ); - - // Otherwise, we inject the element directly into the jQuery object - return jQuery( elem ); - } - selector = []; - } - - // HANDLE: $(expr, [context]) - // (which is just equivalent to: $(content).find(expr) - } else - return jQuery( context ).find( selector ); - - // HANDLE: $(function) - // Shortcut for document ready - } else if ( jQuery.isFunction( selector ) ) - return jQuery( document )[ jQuery.fn.ready ? "ready" : "load" ]( selector ); - - return this.setArray(jQuery.makeArray(selector)); - }, - - // The current version of jQuery being used - jquery: "1.2.6", - - // The number of elements contained in the matched element set - size: function() { - return this.length; - }, - - // The number of elements contained in the matched element set - length: 0, - - // Get the Nth element in the matched element set OR - // Get the whole matched element set as a clean array - get: function( num ) { - return num == undefined ? - - // Return a 'clean' array - jQuery.makeArray( this ) : - - // Return just the object - this[ num ]; - }, - - // Take an array of elements and push it onto the stack - // (returning the new matched element set) - pushStack: function( elems ) { - // Build a new jQuery matched element set - var ret = jQuery( elems ); - - // Add the old object onto the stack (as a reference) - ret.prevObject = this; - - // Return the newly-formed element set - return ret; - }, - - // Force the current matched set of elements to become - // the specified array of elements (destroying the stack in the process) - // You should use pushStack() in order to do this, but maintain the stack - setArray: function( elems ) { - // Resetting the length to 0, then using the native Array push - // is a super-fast way to populate an object with array-like properties - this.length = 0; - Array.prototype.push.apply( this, elems ); - - return this; - }, - - // Execute a callback for every element in the matched set. - // (You can seed the arguments with an array of args, but this is - // only used internally.) - each: function( callback, args ) { - return jQuery.each( this, callback, args ); - }, - - // Determine the position of an element within - // the matched set of elements - index: function( elem ) { - var ret = -1; - - // Locate the position of the desired element - return jQuery.inArray( - // If it receives a jQuery object, the first element is used - elem && elem.jquery ? elem[0] : elem - , this ); - }, - - attr: function( name, value, type ) { - var options = name; - - // Look for the case where we're accessing a style value - if ( name.constructor == String ) - if ( value === undefined ) - return this[0] && jQuery[ type || "attr" ]( this[0], name ); - - else { - options = {}; - options[ name ] = value; - } - - // Check to see if we're setting style values - return this.each(function(i){ - // Set all the styles - for ( name in options ) - jQuery.attr( - type ? - this.style : - this, - name, jQuery.prop( this, options[ name ], type, i, name ) - ); - }); - }, - - css: function( key, value ) { - // ignore negative width and height values - if ( (key == 'width' || key == 'height') && parseFloat(value) < 0 ) - value = undefined; - return this.attr( key, value, "curCSS" ); - }, - - text: function( text ) { - if ( typeof text != "object" && text != null ) - return this.empty().append( (this[0] && this[0].ownerDocument || document).createTextNode( text ) ); - - var ret = ""; - - jQuery.each( text || this, function(){ - jQuery.each( this.childNodes, function(){ - if ( this.nodeType != 8 ) - ret += this.nodeType != 1 ? - this.nodeValue : - jQuery.fn.text( [ this ] ); - }); - }); - - return ret; - }, - - 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, false, function(elem){ - if (this.nodeType == 1) - this.appendChild( elem ); - }); - }, - - prepend: function() { - return this.domManip(arguments, true, true, function(elem){ - if (this.nodeType == 1) - this.insertBefore( elem, this.firstChild ); - }); - }, - - before: function() { - return this.domManip(arguments, false, false, function(elem){ - this.parentNode.insertBefore( elem, this ); - }); - }, - - after: function() { - return this.domManip(arguments, false, true, function(elem){ - this.parentNode.insertBefore( elem, this.nextSibling ); - }); - }, - - end: function() { - return this.prevObject || jQuery( [] ); - }, - - find: function( selector ) { - var elems = jQuery.map(this, function(elem){ - return jQuery.find( selector, elem ); - }); - - return this.pushStack( /[^+>] [^+>]/.test( selector ) || selector.indexOf("..") > -1 ? - jQuery.unique( elems ) : - elems ); - }, - - clone: function( events ) { - // Do the clone - var ret = this.map(function(){ - if ( jQuery.browser.msie && !jQuery.isXMLDoc(this) ) { - // IE copies events bound via attachEvent when - // using cloneNode. Calling detachEvent on the - // clone will also remove the events from the orignal - // In order to get around this, we use innerHTML. - // Unfortunately, this means some modifications to - // attributes in IE that are actually only stored - // as properties will not be copied (such as the - // the name attribute on an input). - var clone = this.cloneNode(true), - container = document.createElement("div"); - container.appendChild(clone); - return jQuery.clean([container.innerHTML])[0]; - } else - return 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){ - if (this.nodeType == 3) - return; - 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( selector ) { - return this.pushStack( - jQuery.isFunction( selector ) && - jQuery.grep(this, function(elem, i){ - return selector.call( elem, i ); - }) || - - jQuery.multiFilter( selector, this ) ); - }, - - not: function( selector ) { - if ( selector.constructor == String ) - // test special case where just one selector is passed in - if ( isSimple.test( selector ) ) - return this.pushStack( jQuery.multiFilter( selector, this, true ) ); - else - selector = jQuery.multiFilter( selector, this ); - - var isArrayLike = selector.length && selector[selector.length - 1] !== undefined && !selector.nodeType; - return this.filter(function() { - return isArrayLike ? jQuery.inArray( this, selector ) < 0 : this != selector; - }); - }, - - add: function( selector ) { - return this.pushStack( jQuery.unique( jQuery.merge( - this.get(), - typeof selector == 'string' ? - jQuery( selector ) : - jQuery.makeArray( selector ) - ))); - }, - - is: function( selector ) { - return !!selector && jQuery.multiFilter( selector, this ).length > 0; - }, - - hasClass: function( selector ) { - return this.is( "." + selector ); - }, - - val: function( value ) { - if ( value == undefined ) { - - if ( this.length ) { - var elem = this[0]; - - // We need to handle select boxes special - if ( jQuery.nodeName( elem, "select" ) ) { - var index = elem.selectedIndex, - values = [], - 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 - value = jQuery.browser.msie && !option.attributes.value.specified ? option.text : option.value; - - // We don't need an array for one selects - if ( one ) - return value; - - // Multi-Selects return an array - values.push( value ); - } - } - - return values; - - // Everything else, we just grab the value - } else - return (this[0].value || "").replace(/\r/g, ""); - - } - - return undefined; - } - - if( value.constructor == Number ) - value += ''; - - return this.each(function(){ - if ( this.nodeType != 1 ) - return; - - if ( value.constructor == Array && /radio|checkbox/.test( this.type ) ) - this.checked = (jQuery.inArray(this.value, value) >= 0 || - jQuery.inArray(this.name, value) >= 0); - - else if ( jQuery.nodeName( this, "select" ) ) { - var values = jQuery.makeArray(value); - - jQuery( "option", this ).each(function(){ - this.selected = (jQuery.inArray( this.value, values ) >= 0 || - jQuery.inArray( this.text, values ) >= 0); - }); - - if ( !values.length ) - this.selectedIndex = -1; - - } else - this.value = value; - }); - }, - - html: function( value ) { - return value == undefined ? - (this[0] ? - this[0].innerHTML : - null) : - this.empty().append( value ); - }, - - replaceWith: function( value ) { - return this.after( value ).remove(); - }, - - eq: function( i ) { - return this.slice( i, i + 1 ); - }, - - slice: function() { - return this.pushStack( Array.prototype.slice.apply( this, arguments ) ); - }, - - map: function( callback ) { - return this.pushStack( jQuery.map(this, function(elem, i){ - return callback.call( elem, i, elem ); - })); - }, - - andSelf: function() { - return this.add( this.prevObject ); - }, - - data: function( key, value ){ - var parts = key.split("."); - parts[1] = parts[1] ? "." + parts[1] : ""; - - if ( value === undefined ) { - var data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]); - - if ( data === undefined && this.length ) - data = jQuery.data( this[0], key ); - - return data === undefined && parts[1] ? - this.data( parts[0] ) : - data; - } else - return this.trigger("setData" + parts[1] + "!", [parts[0], value]).each(function(){ - jQuery.data( this, key, value ); - }); - }, - - removeData: function( key ){ - return this.each(function(){ - jQuery.removeData( this, key ); - }); - }, - - domManip: function( args, table, reverse, callback ) { - var clone = this.length > 1, elems; - - return this.each(function(){ - if ( !elems ) { - elems = jQuery.clean( args, this.ownerDocument ); - - if ( reverse ) - elems.reverse(); - } - - var obj = this; - - if ( table && jQuery.nodeName( this, "table" ) && jQuery.nodeName( elems[0], "tr" ) ) - obj = this.getElementsByTagName("tbody")[0] || this.appendChild( this.ownerDocument.createElement("tbody") ); - - var scripts = jQuery( [] ); - - jQuery.each(elems, function(){ - var elem = clone ? - jQuery( this ).clone( true )[0] : - this; - - // execute all scripts after the elements have been injected - if ( jQuery.nodeName( elem, "script" ) ) - scripts = scripts.add( elem ); - else { - // Remove any inner scripts for later evaluation - if ( elem.nodeType == 1 ) - scripts = scripts.add( jQuery( "script", elem ).remove() ); - - // Inject the elements into the document - callback.call( obj, elem ); - } - }); - - scripts.each( evalScript ); - }); - } -}; - -// Give the init function the jQuery prototype for later instantiation -jQuery.fn.init.prototype = jQuery.fn; - -function evalScript( i, elem ) { - 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 ); -} - -function now(){ - return +new Date; -} - -jQuery.extend = jQuery.fn.extend = function() { - // copy reference to target object - var target = arguments[0] || {}, i = 1, length = arguments.length, deep = false, options; - - // Handle a deep copy situation - if ( target.constructor == Boolean ) { - deep = target; - target = arguments[1] || {}; - // skip the boolean and the target - i = 2; - } - - // Handle case when target is a string or something (possible in deep copy) - if ( typeof target != "object" && typeof target != "function" ) - target = {}; - - // extend jQuery itself if only one argument is passed - if ( length == i ) { - target = this; - --i; - } - - for ( ; i < length; i++ ) - // Only deal with non-null/undefined values - if ( (options = arguments[ i ]) != null ) - // Extend the base object - for ( var name in options ) { - var src = target[ name ], copy = options[ name ]; - - // Prevent never-ending loop - if ( target === copy ) - continue; - - // Recurse if we're merging object values - if ( deep && copy && typeof copy == "object" && !copy.nodeType ) - target[ name ] = jQuery.extend( deep, - // Never move original objects, clone them - src || ( copy.length != null ? [ ] : { } ) - , copy ); - - // Don't bring in undefined values - else if ( copy !== undefined ) - target[ name ] = copy; - - } - - // Return the modified object - return target; -}; - -var expando = "jQuery" + now(), uuid = 0, windowData = {}, - // exclude the following css properties to add px - exclude = /z-?index|font-?weight|opacity|zoom|line-?height/i, - // cache defaultView - defaultView = document.defaultView || {}; - -jQuery.extend({ - noConflict: function( deep ) { - window.$ = _$; - - if ( deep ) - window.jQuery = _jQuery; - - return jQuery; - }, - - // See test/unit/core.js for details concerning this function. - isFunction: function( fn ) { - return !!fn && typeof fn != "string" && !fn.nodeName && - fn.constructor != Array && /^[\s[]?function/.test( fn + "" ); - }, - - // check if an element is in a (or is an) XML document - isXMLDoc: function( elem ) { - return elem.documentElement && !elem.body || - elem.tagName && elem.ownerDocument && !elem.ownerDocument.body; - }, - - // Evalulates a script in a global context - globalEval: function( data ) { - data = jQuery.trim( data ); - - if ( data ) { - // Inspired by code by Andrea Giammarchi - // http://webreflection.blogspot.com/2007/08/global-scope-evaluation-and-dom.html - var head = document.getElementsByTagName("head")[0] || document.documentElement, - script = document.createElement("script"); - - script.type = "text/javascript"; - if ( jQuery.browser.msie ) - script.text = data; - else - script.appendChild( document.createTextNode( data ) ); - - // Use insertBefore instead of appendChild to circumvent an IE6 bug. - // This arises when a base node is used (#2709). - head.insertBefore( script, head.firstChild ); - head.removeChild( script ); - } - }, - - nodeName: function( elem, name ) { - return elem.nodeName && elem.nodeName.toUpperCase() == name.toUpperCase(); - }, - - cache: {}, - - data: function( elem, name, data ) { - elem = elem == window ? - windowData : - 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 ? - windowData : - 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( object, callback, args ) { - var name, i = 0, length = object.length; - - if ( args ) { - if ( length == undefined ) { - for ( name in object ) - if ( callback.apply( object[ name ], args ) === false ) - break; - } else - for ( ; i < length; ) - if ( callback.apply( object[ i++ ], args ) === false ) - break; - - // A special, fast, case for the most common use of each - } else { - if ( length == undefined ) { - for ( name in object ) - if ( callback.call( object[ name ], name, object[ name ] ) === false ) - break; - } else - for ( var value = object[0]; - i < length && callback.call( value, i, value ) !== false; value = object[++i] ){} - } - - return object; - }, - - prop: function( elem, value, type, i, name ) { - // Handle executable functions - if ( jQuery.isFunction( value ) ) - value = value.call( elem, i ); - - // Handle passing in a number to a CSS property - return value && value.constructor == Number && type == "curCSS" && !exclude.test( name ) ? - value + "px" : - value; - }, - - className: { - // internal only, use addClass("class") - add: function( elem, classNames ) { - jQuery.each((classNames || "").split(/\s+/), function(i, className){ - if ( elem.nodeType == 1 && !jQuery.className.has( elem.className, className ) ) - elem.className += (elem.className ? " " : "") + className; - }); - }, - - // internal only, use removeClass("class") - remove: function( elem, classNames ) { - if (elem.nodeType == 1) - elem.className = classNames != undefined ? - jQuery.grep(elem.className.split(/\s+/), function(className){ - return !jQuery.className.has( classNames, className ); - }).join(" ") : - ""; - }, - - // internal only, use hasClass("class") - has: function( elem, className ) { - return jQuery.inArray( className, (elem.className || elem).toString().split(/\s+/) ) > -1; - } - }, - - // A method for quickly swapping in/out CSS properties to get correct calculations - swap: function( elem, options, callback ) { - var old = {}; - // Remember the old values, and insert the new ones - for ( var name in options ) { - old[ name ] = elem.style[ name ]; - elem.style[ name ] = options[ name ]; - } - - callback.call( elem ); - - // Revert the old values - for ( var name in options ) - elem.style[ name ] = old[ name ]; - }, - - css: function( elem, name, force ) { - if ( name == "width" || name == "height" ) { - var val, props = { position: "absolute", visibility: "hidden", display:"block" }, which = name == "width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ]; - - function getWH() { - val = name == "width" ? elem.offsetWidth : elem.offsetHeight; - var padding = 0, border = 0; - jQuery.each( which, function() { - padding += parseFloat(jQuery.curCSS( elem, "padding" + this, true)) || 0; - border += parseFloat(jQuery.curCSS( elem, "border" + this + "Width", true)) || 0; - }); - val -= Math.round(padding + border); - } - - if ( jQuery(elem).is(":visible") ) - getWH(); - else - jQuery.swap( elem, props, getWH ); - - return Math.max(0, val); - } - - return jQuery.curCSS( elem, name, force ); - }, - - curCSS: function( elem, name, force ) { - var ret, style = elem.style; - - // A helper method for determining if an element's values are broken - function color( elem ) { - if ( !jQuery.browser.safari ) - return false; - - // defaultView is cached - var ret = defaultView.getComputedStyle( elem, null ); - return !ret || ret.getPropertyValue("color") == ""; - } - - // We need to handle opacity special in IE - if ( name == "opacity" && jQuery.browser.msie ) { - ret = jQuery.attr( style, "opacity" ); - - return ret == "" ? - "1" : - ret; - } - // Opera sometimes will give the wrong display answer, this fixes it, see #2037 - if ( jQuery.browser.opera && name == "display" ) { - var save = style.outline; - style.outline = "0 solid black"; - style.outline = save; - } - - // Make sure we're using the right name for getting the float value - if ( name.match( /float/i ) ) - name = styleFloat; - - if ( !force && style && style[ name ] ) - ret = style[ name ]; - - else if ( defaultView.getComputedStyle ) { - - // Only "float" is needed here - if ( name.match( /float/i ) ) - name = "float"; - - name = name.replace( /([A-Z])/g, "-$1" ).toLowerCase(); - - var computedStyle = defaultView.getComputedStyle( elem, null ); - - if ( computedStyle && !color( elem ) ) - ret = computedStyle.getPropertyValue( name ); - - // If the element isn't reporting its values properly in Safari - // then some display: none elements are involved - else { - var swap = [], stack = [], a = elem, i = 0; - - // Locate all of the parent display: none elements - for ( ; 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 ( ; i < stack.length; i++ ) - if ( color( stack[ i ] ) ) { - swap[ i ] = stack[ i ].style.display; - stack[ i ].style.display = "block"; - } - - // Since we flip the display style, we have to handle that - // one special, otherwise get the value - ret = name == "display" && swap[ stack.length - 1 ] != null ? - "none" : - ( computedStyle && computedStyle.getPropertyValue( name ) ) || ""; - - // Finally, revert the display styles back - for ( i = 0; i < swap.length; i++ ) - if ( swap[ i ] != null ) - stack[ i ].style.display = swap[ i ]; - } - - // We should always get a number back from opacity - if ( name == "opacity" && ret == "" ) - ret = "1"; - - } else if ( elem.currentStyle ) { - var camelCase = name.replace(/\-(\w)/g, function(all, letter){ - return letter.toUpperCase(); - }); - - ret = elem.currentStyle[ name ] || elem.currentStyle[ camelCase ]; - - // 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 ) ) { - // Remember the original values - var left = style.left, rsLeft = elem.runtimeStyle.left; - - // Put in the new values to get a computed value out - elem.runtimeStyle.left = elem.currentStyle.left; - style.left = ret || 0; - ret = style.pixelLeft + "px"; - - // Revert the changed values - style.left = left; - elem.runtimeStyle.left = rsLeft; - } - } - - return ret; - }, - - clean: function( elems, context ) { - var ret = []; - context = context || document; - // !context.createElement fails in IE with an error but returns typeof 'object' - if (typeof context.createElement == 'undefined') - context = context.ownerDocument || context[0] && context[0].ownerDocument || document; - - jQuery.each(elems, function(i, elem){ - if ( !elem ) - return; - - if ( elem.constructor == Number ) - elem += ''; - - // Convert html string into DOM nodes - if ( typeof elem == "string" ) { - // Fix "XHTML"-style tags in all browsers - elem = elem.replace(/(<(\w+)[^>]*?)\/>/g, function(all, front, tag){ - return tag.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i) ? - all : - front + ">"; - }); - - // Trim whitespace, otherwise indexOf won't work as expected - var tags = jQuery.trim( elem ).toLowerCase(), div = context.createElement("div"); - - var wrap = - // option or optgroup - !tags.indexOf("", "" ] || - - !tags.indexOf("", "" ] || - - tags.match(/^<(thead|tbody|tfoot|colg|cap)/) && - [ 1, "", "
" ] || - - !tags.indexOf("", "" ] || - - // matched above - (!tags.indexOf("", "" ] || - - !tags.indexOf("", "" ] || - - // IE can't serialize and + + + + + @@ -83,7 +88,7 @@

- +

Index: tool/src/webapp/content/templates/control_items.html =================================================================== --- tool/src/webapp/content/templates/control_items.html (revision 81089) +++ tool/src/webapp/content/templates/control_items.html (working copy) @@ -26,10 +26,11 @@ - - + + + + - @@ -40,9 +41,10 @@ - + + Index: tool/src/webapp/content/templates/modify_template_items.html =================================================================== --- tool/src/webapp/content/templates/modify_template_items.html (revision 81089) +++ tool/src/webapp/content/templates/modify_template_items.html (working copy) @@ -18,7 +18,6 @@ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> - Edit Template @@ -27,9 +26,10 @@ + + + - - @@ -48,6 +48,7 @@ + @@ -71,7 +72,7 @@
Template description goes here, this would be notes for other admins or yourself, Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Vivamus in pede in ligula bibendum tincidunt. Quisque in dui a tellus ultricies posuere. Donec consectetuer, nunc quis luctus dignissim, velit purus consequat eros, eu euismod nibh justo ac purus. Ut sed justo. Cras aliquet massa ut lacus. Vestibulum feugiat vehicula pede. Morbi rhoncus quam in elit. Etiam egestas, metus a volutpat lobortis, erat dui laoreet libero, nec pulvinar sem mi ac felis.
+

- This evaluation is assigned to at least one currently unpublished site. Publish these sites for students to be notified via email and given access to complete this evaluation. -

-
+ This evaluation is assigned to at least one currently unpublished site. Publish these sites for students to be notified via email and given access to complete this evaluation. +

+ +

Partial Evaluations

Your Evaluations which you started creating but did not complete @@ -60,14 +62,15 @@ - - + - @@ -75,17 +78,18 @@ + -
+ Evaluation Title + + Settings + Created On -
Evaluation title + Continue + Delete + 20/03/2007 - Continue - | Delete -

+

In-Queue Evaluations

Your Evaluations in queue that have not started yet @@ -94,15 +98,12 @@ - - - @@ -123,11 +124,9 @@ - Index: tool/src/webapp/content/templates/control_eval_admin.html =================================================================== --- tool/src/webapp/content/templates/control_eval_admin.html (revision 81089) +++ tool/src/webapp/content/templates/control_eval_admin.html (working copy) @@ -25,7 +25,7 @@ - + Property changes on: tool/src/webapp/content/templates/control_eval_admin.html ___________________________________________________________________ Added: svn:keywords + Date Revision Author URL Id Index: tool/src/webapp/content/templates/modify_hierarchy_node_perms.html =================================================================== --- tool/src/webapp/content/templates/modify_hierarchy_node_perms.html (revision 81089) +++ tool/src/webapp/content/templates/modify_hierarchy_node_perms.html (working copy) @@ -25,7 +25,7 @@ - + Property changes on: tool/src/webapp/content/templates/modify_hierarchy_node_perms.html ___________________________________________________________________ Modified: svn:keywords - Date Revision Author HeadURL Id + Date Revision Author URL Id Index: tool/src/webapp/content/templates/modify_block.html =================================================================== --- tool/src/webapp/content/templates/modify_block.html (revision 81089) +++ tool/src/webapp/content/templates/modify_block.html (working copy) @@ -76,11 +76,6 @@

-

- - Use Ideal Coloring: -

-

Index: tool/src/webapp/content/templates/modify_adhoc_group.html =================================================================== --- tool/src/webapp/content/templates/modify_adhoc_group.html (revision 81089) +++ tool/src/webapp/content/templates/modify_adhoc_group.html (working copy) @@ -26,7 +26,7 @@ - + Property changes on: tool/src/webapp/content/templates/modify_adhoc_group.html ___________________________________________________________________ Modified: svn:keywords - Date Revision Author HeadURL Id + Date Revision Author URL Id Property changes on: tool/src/webapp/content/templates/remove_expert_item.html ___________________________________________________________________ Added: svn:keywords + Date Revision Author URL Id Index: tool/src/webapp/content/templates/report_view.html =================================================================== --- tool/src/webapp/content/templates/report_view.html (revision 81089) +++ tool/src/webapp/content/templates/report_view.html (working copy) @@ -28,7 +28,7 @@ - + Property changes on: tool/src/webapp/content/templates/messages.html ___________________________________________________________________ Added: svn:keywords + Date Revision Author URL Id Index: tool/src/webapp/content/templates/control_expert_items.html =================================================================== --- tool/src/webapp/content/templates/control_expert_items.html (revision 81089) +++ tool/src/webapp/content/templates/control_expert_items.html (working copy) @@ -26,9 +26,9 @@ - - - + + + Property changes on: tool/src/webapp/content/templates/control_expert_items.html ___________________________________________________________________ Added: svn:keywords + Date Revision Author URL Id Index: tool/src/webapp/content/templates/evaluation_responders.html =================================================================== --- tool/src/webapp/content/templates/evaluation_responders.html (revision 81089) +++ tool/src/webapp/content/templates/evaluation_responders.html (working copy) @@ -46,7 +46,7 @@

Responses for Evaluation Title (Start - Due) 10/100 - Send email message to participants + Send email message to participants
Property changes on: tool/src/webapp/content/templates/evaluation_responders.html ___________________________________________________________________ Modified: svn:keywords - Date Revision Author HeadURL Id + Date Revision Author URL Id Property changes on: tool/src/webapp/content/templates/evaluation_assignments.html ___________________________________________________________________ Modified: svn:keywords - Date Revision Author HeadURL Id + Date Revision Author URL Id Index: tool/src/webapp/content/templates/modify_template.html =================================================================== --- tool/src/webapp/content/templates/modify_template.html (revision 81089) +++ tool/src/webapp/content/templates/modify_template.html (working copy) @@ -75,7 +75,7 @@

- +

Index: tool/src/webapp/content/templates/evaluation_settings.html =================================================================== --- tool/src/webapp/content/templates/evaluation_settings.html (revision 81089) +++ tool/src/webapp/content/templates/evaluation_settings.html (working copy) @@ -26,7 +26,7 @@ - + @@ -85,13 +85,13 @@
- +
+ Evaluation Title + Settings - Reminders - Assigned Edit - | Delete + Delete + Send Email - ­ - Course 1010 @@ -145,6 +144,7 @@

No evaluations in-queue

+

Active Evaluations

Your Evaluations currently active for users to take @@ -153,22 +153,13 @@ - - - - - + + @@ -186,34 +183,33 @@ (link)[category] - - - - - + +
+ Evaluation Title - Responses - - Report - Settings - Reminders - + Assigned @@ -177,6 +168,12 @@ Due Date + Response Rate + + Report +
- 10/100 - - - View Report - - Edit - | Delete - - | + Delete + Send Email + + - ­ - 12 - 15/03/2007 + + 15/03/2007 - 20/03/2007 + + 20/03/2007 + 2 of 39 + + + + results + respondents +
@@ -221,6 +217,7 @@

No active evaluations

+

Closed Evaluations

Your Evaluations which have been completed @@ -229,24 +226,27 @@ - - - - + + @@ -257,26 +257,30 @@ [category] - - + +
+ Evaluation Title - Report + Settings - Reminders - + Assigned - Response Rate + + Start Date Due Date + Response Rate + + Report +
- Report - - | Edit - | Delete - | Reopen + Edit + Delete + Send Email + Reopen - ­ - Course 1010 - 40/50 - 80% - + + 15/03/2007 20/03/2007 + 2 of 39 + + + + results + respondents +
Property changes on: tool/src/webapp/content/templates/modify_expert_item.html ___________________________________________________________________ Added: svn:keywords + Date Revision Author URL Id Index: tool/src/webapp/content/templates/summary.html =================================================================== --- tool/src/webapp/content/templates/summary.html (revision 81089) +++ tool/src/webapp/content/templates/summary.html (working copy) @@ -14,199 +14,224 @@ permissions and limitations under the License. --> - + - Summary - - - - - - - - +Summary + + + + + + + + + + + + + + + -

-
 OwnerUsername View preview View preview

Template: template title -   (View preview) +   (View preview)   [Modify]
@@ -222,7 +222,7 @@
- +

This setting allows all roles to take the survey

@@ -244,7 +244,7 @@ This setting allows you to give the instructor control over whether to use the evaluation (or simply require them to).

- + - + +

@@ -327,7 +327,7 @@ Note about how the default email templates are made for course evals

- +

@@ -359,7 +359,7 @@

-

+

Index: tool/src/webapp/content/templates/modify_hierarchy_node_groups.html =================================================================== --- tool/src/webapp/content/templates/modify_hierarchy_node_groups.html (revision 81089) +++ tool/src/webapp/content/templates/modify_hierarchy_node_groups.html (working copy) @@ -26,7 +26,7 @@ - + Index: tool/src/webapp/content/templates/evaluation_create.html =================================================================== --- tool/src/webapp/content/templates/evaluation_create.html (revision 81089) +++ tool/src/webapp/content/templates/evaluation_create.html (working copy) @@ -77,13 +77,13 @@  OwnerUsername -  View preview +  View preview
Template: template title -   (View preview) +   (View preview)

Index: tool/src/webapp/content/templates/administrate_provider_sync.html =================================================================== --- tool/src/webapp/content/templates/administrate_provider_sync.html (revision 81089) +++ tool/src/webapp/content/templates/administrate_provider_sync.html (working copy) @@ -26,11 +26,11 @@ - - - + + + - + Property changes on: tool/src/webapp/content/templates/administrate_provider_sync.html ___________________________________________________________________ Added: svn:keywords + Date Revision Author URL Id Index: tool/src/webapp/content/templates/administrate_email.html =================================================================== --- tool/src/webapp/content/templates/administrate_email.html (revision 81089) +++ tool/src/webapp/content/templates/administrate_email.html (working copy) @@ -26,9 +26,11 @@ - - + + + + @@ -48,8 +50,8 @@

-

This will @@ -121,7 +123,6 @@
The single email per student implementation uses a daily Quartz job to process email. This job must be running when evaluations begin.

-
@@ -129,9 +130,17 @@

+ value="true" type="checkbox" disabled="disabled" />

+

+ + +

+

+ + +

@@ -147,12 +156,12 @@ -

-

- - - -

+

+

+ + + +

@@ -163,24 +172,23 @@ Evaluation ends on this date, no more responses after this date
-

- - -

-

- - -

-

- - -

- +

+ + +

+

+ + +

+

+ + +


@@ -207,13 +215,14 @@ - +

- + +

- +

Property changes on: tool/src/webapp/content/templates/administrate_email.html ___________________________________________________________________ Added: svn:keywords + Date Revision Author URL Id Index: tool/src/webapp/content/templates/take_eval.html =================================================================== --- tool/src/webapp/content/templates/take_eval.html (revision 81089) +++ tool/src/webapp/content/templates/take_eval.html (working copy) @@ -18,21 +18,25 @@ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> - Take Evaluation + Take Evaluation - + - - - - - + + + + + + + + + @@ -40,31 +44,15 @@ -
+
+ +
- - -

Evaluation: @@ -104,92 +92,96 @@ Evaluation instructions would go here if any have been specified. This block may be up to 4000 chars.

-
+
Note:
Additional instructional note to the user here
-
+
-
+
+ + - - - - - - - + + - - - - + + -
-
- Group Items: -
    -
  1. -

    Top Level or something like Biology Dept

    -
  2. -
  3. - -
    Items get rendered here
    -
  4. -
+
+
+ Group Items: +
    +
  1. +

    Top Level or something like Biology Dept

    +
  2. +
  3. + +
    Items get rendered here
    +
  4. +
Evaluation has been Saved but not Submitted
- + - -
- -
+ + +

Remove Scale

Scale

-
+
@@ -94,7 +101,7 @@
-
+
@@ -111,24 +118,17 @@

- - + + + Preview + Cancel

- + \ No newline at end of file Index: tool/src/webapp/content/templates/preview_item.html =================================================================== --- tool/src/webapp/content/templates/preview_item.html (revision 81089) +++ tool/src/webapp/content/templates/preview_item.html (working copy) @@ -1,3 +1,4 @@ + - - - - Preview item - - - - -
-
- -
- - - - - - - - - - - -
- 0.  - - - -
- -
-
  - -
-
- - -
- - - +
+
+
+ + + + + + + + + + + +
+ 0.  + + + +
+ + +
+
  + +
+
+
+ +
Property changes on: tool/src/webapp/content/templates/evaluation_notifications.html ___________________________________________________________________ Modified: svn:keywords - Date Revision Author HeadURL Id + Date Revision Author URL Id Property changes on: tool/src/webapp/content/templates/control_email_templates.html ___________________________________________________________________ Modified: svn:keywords - Date Revision Author HeadURL Id + Date Revision Author URL Id Index: tool/src/webapp/content/templates/modify_item.html =================================================================== --- tool/src/webapp/content/templates/modify_item.html (revision 81089) +++ tool/src/webapp/content/templates/modify_item.html (working copy) @@ -18,218 +18,213 @@ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> - Add/Modify Item - - +Add/Modify Item + + -
-
-
    -
  • Message for user here
  • -
-
+
+
+
    +
  • Message for user here
  • +
+
- +
- +

+ Item Text: (this is the question or + statement that the evaluator will respond to) +

+
+ +
-

- Item Text: - - (this is the question or statement that the evaluator will respond to) -

-
- -
+
+ + + - - - - + + + + + + - - - - - - + + + + + +
- - - - - -
+
+

Choices:

+
+
+ + +  
+
+
+ +  
+
+
-
-

Choices:

-
-
- - - - -   - -
-
-
- - - - -   - -
-
-
- - - - - - - -
-
+ + + + + + +
+
-
- - -
+
+ + +
-
-
- - - indicates that this item was authored by an expert -
-

- Expert Description: - this text describes the appropriate usage of this item for template authors -

-
-
- -
- - Expert Item Group: - -
- -
- -
-

- Result Sharing : - - - - - -

+
+
+ + + indicates that this item was authored by an expert
- - -
+

+ Expert Description: + this text describes the appropriate usage of this item for template authors +

+
-

Hierarchy Assignment :

- +
+ + Expert Item Group: +
+ +
-
- Display Setting Hints -
-
these optional settings allow the item author to provide hints as to how this item should be displayed
+
+

+ Result Sharing : + + + + + +

+
-

- - -

+ +
+
+

+ Hierarchy Assignment : +

+ +
+
-

- - -

+
+ Display Setting Hints +
+
these optional settings allow the item author to provide hints as to + how this item should be displayed
-

- - -

+

+ + +

-

- - -

-
- - -

- - -

-
-
- Category: +

+ + +

- - - - - - - - - -
-
+

+ + +

-
 
-
-
- - -
- -
+

+ + +

+
+ + +

+ + +

+
+
+ Category: + + + + + + + + + +
+
+ +
 
+ +
+ + +
+ +
\ No newline at end of file Index: tool/src/webapp/content/templates/administrate_search.html =================================================================== --- tool/src/webapp/content/templates/administrate_search.html (revision 81089) +++ tool/src/webapp/content/templates/administrate_search.html (working copy) @@ -26,10 +26,10 @@ - - - - + + + + Property changes on: tool/src/webapp/content/templates/administrate_search.html ___________________________________________________________________ Modified: svn:keywords - Date Revision Author HeadURL Id + Date Revision Author URL Id Property changes on: tool/src/webapp/content/templates/preview_expert_items.html ___________________________________________________________________ Added: svn:keywords + Date Revision Author URL Id Property changes on: tool/src/webapp/content/templates/evaluation_assign_select.html ___________________________________________________________________ Added: svn:keywords + Date Revision Author URL Id Index: tool/src/webapp/content/templates/control_scales.html =================================================================== --- tool/src/webapp/content/templates/control_scales.html (revision 81089) +++ tool/src/webapp/content/templates/control_scales.html (working copy) @@ -24,6 +24,15 @@ + + + + + + + + + @@ -60,6 +69,7 @@ Modify | Remove | + Preview |
@@ -73,5 +83,8 @@
+ + + \ No newline at end of file Index: tool/src/webapp/content/templates/evaluation_assign.html =================================================================== --- tool/src/webapp/content/templates/evaluation_assign.html (revision 81089) +++ tool/src/webapp/content/templates/evaluation_assign.html (working copy) @@ -26,7 +26,7 @@ - + Index: tool/src/webapp/component-templates/render_text_item.html =================================================================== --- tool/src/webapp/component-templates/render_text_item.html (revision 81089) +++ tool/src/webapp/component-templates/render_text_item.html (working copy) @@ -24,15 +24,29 @@ -
+
+
+ 0 + + ) + . + + * + Item text label. + + +
+
+ + + + + +
+
\ No newline at end of file Index: tool/src/webapp/component-templates/render_hierarchy_node_selector.html =================================================================== --- tool/src/webapp/component-templates/render_hierarchy_node_selector.html (revision 81089) +++ tool/src/webapp/component-templates/render_hierarchy_node_selector.html (working copy) @@ -24,8 +24,8 @@ -
-

Hierarchy Assignment :

+
+ - vertical label + + vertical label
  • - -
  • + + +
    -
    -
      -
    • +
    • + +
    • - -
    • -
    + + + -
    -
    + +
    +
    + + + + Add a comment + +
    + +
    + +
    +
    - -
    -
    - - - - Add a comment - -
    - -
    - -
    -
    +
    +
    + - - Index: tool/src/webapp/component-templates/render_block_item.html =================================================================== --- tool/src/webapp/component-templates/render_block_item.html (revision 81089) +++ tool/src/webapp/component-templates/render_block_item.html (working copy) @@ -26,6 +26,81 @@
    +
    +
    +
    + +
    +
    + Text heading for an item group. +
    +
    + +
    + + + Scale Response: + Not at all + - + Sometimes + - + Very + + + N/A1 + + +
    +
    +
    +
    + 1 + + ) + . + + * + This is UCB's new scale display. +
    +
    +
    +
    +
    +
      +
    1. + +
    2. +
    3. + +
    4. +
    +
    +
    +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    + + + +
    - +
    - - - - -
    - Label -
    + Block parent header text here
    this is really long block
    @@ -101,9 +170,12 @@
    -
    - ** 1. - Child item text here + + ** +
    + 1. +
    + Child item text here
    @@ -140,8 +212,11 @@
    - ** 1. - Child item text here + ** +
    + 1. +
    + Child item text here
    Index: tool/src/webapp/component-templates/render_multipleanswer_item.html =================================================================== --- tool/src/webapp/component-templates/render_multipleanswer_item.html (revision 81089) +++ tool/src/webapp/component-templates/render_multipleanswer_item.html (working copy) @@ -24,119 +24,120 @@ -
    +
    - ** - # -
    Full or vertical display text here
    +
    + 0 + + ) + . + + * + Item text label. -
    + +
    +
    +
    -
    - - -
      -
    • - - -
    • -
    • - - +
      + + +
        +
      • + + +
      • +
      • + + +
      • +
      • + +
      • +
      • + + + +
      • +
      +
      -
    • +
        + + +
      • + +
      • +
      • + +
      • +
      • + + +
      • +
      • + + + +
      • +
      +
    + +
    +
    + + + + Add a comment + +
    + +
    + +
    +
    +
    +
    -
  • - -
  • +
    - - - -
  • - - - -
  • - -
    - -
      - - -
    • - - -
    • -
    • - -
    • -
    • - - -
    • -
    • - - - - -
    • - -
    - -
    - - - -
    -
    - - - - Add a comment - -
    - -
    - -
    -
    - - - Index: tool/src/webapp/component-templates/render_scaled_item.html =================================================================== --- tool/src/webapp/component-templates/render_scaled_item.html (revision 81089) +++ tool/src/webapp/component-templates/render_scaled_item.html (working copy) @@ -24,61 +24,102 @@ -
    -
    - -
    - ** - # - Item text for compact items goes here -
    -
    - - - - + + +
    - - - compactDisplayStart - -
    -
    -
    - ideal scale coloring - -
    +
    - -
    - - - -
    -
    + +
    + +
    + 0 + + ) + . + + * + Item text label. - + +
    +
    -
    - - - + + + + + + - - -
    + + + compactDisplayStart + +
    +
    +
    + ideal scale coloring + +
    + + +
    + + + +
    -
    - compactDisplayEnd -
    + + +
    + + + +
    + +
    + compactDisplayEnd +
          
    - + + + +
    + -

    +

    + 0 + + ) + . + + * + Item text label. + + +
    @@ -198,8 +239,61 @@
    - + +
    + +
    +
    + 1 + + ) + . + + * + This is UCB's new scale display. +
    +
    +
    + + Scale Response: + Not at all + - + Sometimes + - + Very + +
    +
    +
      +
    1. + +
    2. +
    3. + +
    4. +
    +
    +
    +
    +
    +
    +
    + -
    +
    @@ -318,6 +415,7 @@
    -
    + +
    Index: tool/pom.xml =================================================================== --- tool/pom.xml (revision 81089) +++ tool/pom.xml (working copy) @@ -142,7 +142,6 @@ sakai2.7 sakai2.7 - true 2.2.x @@ -193,6 +192,7 @@ sakai2.8 sakai2.8 + true 2.2.x @@ -293,7 +293,7 @@ org.springframework spring-webmvc - compile + compile