Index: lams_learning/conf/language/lams/ApplicationResources.properties =================================================================== RCS file: /usr/local/cvsroot/lams_learning/conf/language/lams/ApplicationResources.properties,v diff -u -r1.51 -r1.52 --- lams_learning/conf/language/lams/ApplicationResources.properties 30 Oct 2012 22:52:13 -0000 1.51 +++ lams_learning/conf/language/lams/ApplicationResources.properties 20 Nov 2012 14:47:03 -0000 1.52 @@ -114,6 +114,15 @@ label.learner.progress.open.tooltip =Hide lesson progress label.learner.progress.closed =>> label.learner.progress.closed.tooltip =Show lesson progress +label.learner.progress.activity.current.tooltip =This is the current activity +label.learner.progress.activity.completed.tooltip =Double click to review this completed activity +label.learner.progress.activity.attempted.tooltip =You have attempted but not yet finished this activity +label.learner.progress.activity.tostart.tooltip =You need to complete the activities before this activity to access it +label.learner.progress.activity.support.tooltip =Double click to participate in this support activity +button.exit =Exit +button.export =Export +button.save =Save +label.learner.progress.notebook =Notebook +label.learner.progress.support =Support Activities - #======= End labels: Exported 108 labels for en AU ===== Index: lams_learning/src/java/org/lamsfoundation/lams/learning/web/action/LearnerAction.java =================================================================== RCS file: /usr/local/cvsroot/lams_learning/src/java/org/lamsfoundation/lams/learning/web/action/LearnerAction.java,v diff -u -r1.46 -r1.47 --- lams_learning/src/java/org/lamsfoundation/lams/learning/web/action/LearnerAction.java 19 Mar 2012 19:40:53 -0000 1.46 +++ lams_learning/src/java/org/lamsfoundation/lams/learning/web/action/LearnerAction.java 20 Nov 2012 14:47:03 -0000 1.47 @@ -26,6 +26,7 @@ import java.io.IOException; import java.io.PrintWriter; +import java.util.List; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; @@ -35,8 +36,11 @@ import org.apache.struts.action.ActionForm; import org.apache.struts.action.ActionForward; import org.apache.struts.action.ActionMapping; +import org.apache.tomcat.util.json.JSONException; +import org.apache.tomcat.util.json.JSONObject; import org.lamsfoundation.lams.learning.service.ICoreLearnerService; import org.lamsfoundation.lams.learning.service.LearnerServiceProxy; +import org.lamsfoundation.lams.learning.web.bean.ActivityURL; import org.lamsfoundation.lams.learning.web.util.ActivityMapping; import org.lamsfoundation.lams.learning.web.util.LearningWebUtil; import org.lamsfoundation.lams.learningdesign.Activity; @@ -522,7 +526,44 @@ return mapping.findForward("displayProgress"); } + + @SuppressWarnings("unchecked") + public ActionForward displayProgressJSON(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) throws JSONException, IOException { + Integer learnerId = LearningWebUtil.getUserId(); + Long lessonId = WebUtil.readLongParam(request, AttributeNames.PARAM_LESSON_ID); + ICoreLearnerService learnerService = LearnerServiceProxy.getLearnerService(getServlet().getServletContext()); + Object[] ret = learnerService.getStructuredActivityURLs(learnerId, lessonId); + + JSONObject responseJSON = new JSONObject(); + responseJSON.put("currentActivityId", ret[1]); + for (ActivityURL activity : (List) ret[0]) { + if (activity.getFloating()) { + // these are support activities + for (ActivityURL childActivity : activity.getChildActivities()) { + responseJSON.append("support", activityToJSON(childActivity)); + } + } else { + responseJSON.append("activities", activityToJSON(activity)); + } + } + + response.setContentType("application/x-json;charset=utf-8"); + response.getWriter().print(responseJSON.toString()); + + return null; + } + + private JSONObject activityToJSON(ActivityURL activity) throws JSONException { + JSONObject activityJSON = new JSONObject(); + activityJSON.put("id", activity.getActivityId()); + activityJSON.put("name", activity.getTitle()); + activityJSON.put("status", activity.getStatus()); + activityJSON.put("url", activity.getUrl()); + return activityJSON; + } + /** * Forces a move to a destination Activity in the learning sequence, returning a WDDX packet * Index: lams_learning/src/java/org/lamsfoundation/lams/learning/web/action/NotebookAction.java =================================================================== RCS file: /usr/local/cvsroot/lams_learning/src/java/org/lamsfoundation/lams/learning/web/action/NotebookAction.java,v diff -u -r1.6 -r1.7 --- lams_learning/src/java/org/lamsfoundation/lams/learning/web/action/NotebookAction.java 2 Jul 2009 08:19:32 -0000 1.6 +++ lams_learning/src/java/org/lamsfoundation/lams/learning/web/action/NotebookAction.java 20 Nov 2012 14:47:03 -0000 1.7 @@ -250,8 +250,8 @@ notebookService.createNotebookEntry(id, CoreNotebookConstants.SCRATCH_PAD, signature, userID, title, entry); - return viewAll(mapping, actionForm, request, response); - + boolean skipViewAll = WebUtil.readBooleanParam(request, "skipViewAll", false); + return skipViewAll ? null : viewAll(mapping, actionForm, request, response); } /** Fisheye: Tag 1.21 refers to a dead (removed) revision in file `lams_learning/web/main.jsp'. Fisheye: No comparison available. Pass `N' to diff? Index: lams_learning/web/css/main.css =================================================================== RCS file: /usr/local/cvsroot/lams_learning/web/css/main.css,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ lams_learning/web/css/main.css 20 Nov 2012 14:47:03 -0000 1.1 @@ -0,0 +1,153 @@ +body.stripes { + margin: 0px; +} + +div#controlFrame { + position: absolute; + width: 160px; + height:100%; + top: 0px; + left: 0px; +} + +#progressBarDiv * { + margin: auto; +} + +#contentFrame { + border: none; + margin-left: 160px; + overflow: auto; +} + +table#logoTable { + height: 20px; + table-layout: fixed; +} + +#logoImage { + width: 105px; +} + +.progressButton { + margin: 0px; + width: 50px; + padding: 1px !important; + cursor: pointer; + font-size: 9px !important; +} + +td#exitButtonCell { + padding: 4px 2px 2px 0px; + width: 50px; +} + +td#exportButtonCell { + padding: 3px 2px 5px 0px; +} + +div#lessonTitleRow { + overflow: hidden; + text-overflow:ellipsis; + white-space:nowrap; + padding: 0px 3px 0px 3px; +} + +div#progressBarDiv { + background-color: rgb(219,230,252); + overflow: auto; + text-align: center; +} + +.separatorRow { + height: 15px; + background-color: rgb(197,212,251); + border-top: 4px solid #DDDDDD; + border-bottom: 4px solid #DDDDDD; + text-align: center; + padding: 0px; + margin: 0px; + font-size: 10px; +} + +div#supportSeparatorRow { + display: none; + cursor: pointer; + padding-top: 2px; +} + +.togglerCell { + text-align: right; + padding-right: 3px; + float: right; +} + +div#supportPart { + display: none; + background-color: rgb(219,230,252); + padding: 0px; +} +div#notebookSeparatorRow { + cursor: pointer; + padding-top: 2px +} + +table#notebookPart { + display: none; + table-layout:fixed; + height: 135px; + background-color: rgb(219,230,252); +} + +td#notebookTitleCell { + width: 20px; + font-size: 9px; + padding: 4px 10px 0px 4px; +} + +.notebookInput { + width: 93%; +} + +#entry { + padding-left: 4px; +} + +td#viewAllButtonCell { + padding: 0px 0px 4px 4px; +} + +td#saveButtonCell { + text-align: right; + padding: 0px 4px 4px 0px +} + +div#tooltip { + display: none; + position : absolute; + border : 1px solid gray; + background-color : rgb(246,238,191); + padding : 3px; + z-index: 5; + width: 100px; + font-size: 9px; +} + +.ui-layout-pane { + padding: 0px !important; +} + +.ui-layout-toggler-west { + background-color: #2B95E9 !important; +} + +.ui-layout-toggler-west-hover { + background-color: #B8E335 !important; +} + +.ui-layout-toggler-west-open .content, .ui-layout-toggler-west-closed .content { + font-size: 10px; + text-align: center; + font-weight: bold; + word-wrap: break-word; +} \ No newline at end of file Index: lams_learning/web/includes/javascript/main.js =================================================================== RCS file: /usr/local/cvsroot/lams_learning/web/includes/javascript/main.js,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ lams_learning/web/includes/javascript/main.js 20 Nov 2012 14:47:03 -0000 1.1 @@ -0,0 +1,345 @@ +var isInternetExplorer = navigator.appName.indexOf("Microsoft") != -1; + +// ----- WINDOW MANIPULATION ----- + +function openPopUp(args, title, h, w, status) { + window.open(args, title, "HEIGHT=" + h + ",WIDTH=" + w + + ",resizable=yes,scrollbars=yes,status=" + + status + ",menubar=no, toolbar=no"); +} + +function exportPortfolio(){ + openPopUp(APP_URL + "exportWaitingPage.jsp?mode=learner&lessonID=" + lessonId, + "ExportPortfolioLearner", + 410,640, + "no"); +} + +function openActivity(url) { + openPopUp(url, + "LearnerActivity", + 600,800, + "yes"); +} + +function viewNotebookEntries(){ + openPopUp(APP_URL + "notebook.do?method=viewAll&lessonID=" + lessonId, + "Notebook", + 570,796, + "no"); +} + +function closeWindow() { + // refresh the parent window + if (parentURL != "") { + if (window.parent.opener == null + || '${param.noopener}' == 'true' + || parentURL.indexOf('noopener=true') >= 0) { + window.location.href = parentURL; + } else { + window.parent.opener.location.href = parentURL; + } + return true; + } + + top.window.close(); +} + + +function resizeElements() { + var width = $(window).width() - 160; + var height = $(window).height(); + $('#contentFrame').css({ + 'width' : width + "px", + 'height' : height + "px", + 'position' : 'fixed' + }); + + if (progressPanelEnabled) { + if (!controlFramePadding) { + // calculate only once + // there can be miscalculations when trying to repeat this in the middle of resizing + controlFramePadding = $('#controlFrame').outerHeight(true) - $('#controlFrame').height(); + } + + // calculate immutable chunks and what is left goes for progress bar + var progressBarHeight = height - controlFramePadding; + $('.progressStaticHeight').each(function(){ + var elem = $(this); + if (elem.is(':visible')) { + progressBarHeight -= elem.outerHeight(true); + } + }); + + $('#progressBarDiv').height(progressBarHeight); + } + + if (presenceEnabled){ + resizeChat(); + } +} + +// open/clos Notebook or Support frames +function toggleBarPart(name) { + var part = $('#' + name + 'Part'); + var togglerCell = $('#' + name + 'TogglerCell'); + if (part.is(':visible')) { + part.hide(); + togglerCell.html('â–˛'); + } else { + part.show(); + togglerCell.html('â–Ľ'); + } + resizeElements(); +} + +function validateNotebookForm(fields) { + var formFilled = false; + $.each(fields,function(index, field){ + if ((field.name == 'title' || field.name == 'entry') + && field.value) { + formFilled = true; + return false; + } + }); + return formFilled; +} + +//------------- RAPHAEL -------------- +var PATH_CURRENT_ACTIVITY = " v16 h16 v-16 z"; +var PATH_COMPLETED_ACTIVITY = " m -8 0 a 8 8 0 1 0 16 0 a 8 8 0 1 0 -16 0"; +var PATH_ATTEMPTED_ACTIVITY = " v16 h16 v-16 z m6 0 10 10"; +var PATH_TOSTART_ACTIVITY = " l8 16 l8 -16 z"; + +var COLOR_CURRENT_ACTIVITY = "rgb(187,0,0)"; +var COLOR_COMPLETED_ACTIVITY = "rgb(0,0,153)"; +var COLOR_ATTEMPTED_ACTIVITY = "rgb(187,0,0)"; +var COLOR_TOSTART_ACTIVITY = "rgb(0,153,0)"; + +var paper = null; +var controlFramePadding = null; +var currentActivityId = null; +var activities = []; + +function Activity(index, name, id, status, url) { + this.index = index; + this.name = name; + this.id = id; + this.status = status; + this.url = url; + + // 20 is the first line segment and following activities take 60 px each + this.y = 20 + 60*index; + + if (id == currentActivityId) { + // red square + this.path = "M62 " + this.y + PATH_CURRENT_ACTIVITY; + this.fill = COLOR_CURRENT_ACTIVITY; + this.statusTooltip = LABEL_CURRENT_ACTIVITY; + } else if (status == 1) { + // blue circle + this.path = "M70 " + (this.y + 8) + PATH_COMPLETED_ACTIVITY; + this.fill = COLOR_COMPLETED_ACTIVITY; + this.statusTooltip = LABEL_COMPLETED_ACTIVITY; + } else if (status == 2) { + // red square with green edge + this.path = "M62 " + this.y + PATH_ATTEMPTED_ACTIVITY; + this.fill = COLOR_ATTEMPTED_ACTIVITY; + this.stroke = COLOR_TOSTART_ACTIVITY; + this.statusTooltip = LABEL_ATTEMPTED_ACTIVITY; + } else if (status == 3) { + // green triangle + this.path = "M62 " + this.y + PATH_TOSTART_ACTIVITY; + this.fill = COLOR_TOSTART_ACTIVITY; + this.statusTooltip = LABEL_TOSTART_ACTIVITY; + } + + this.transform = function(targetActivity) { + this.path = targetActivity.path; + this.fill = targetActivity.fill; + this.stroke = targetActivity.stroke; + this.status = targetActivity.status; + this.statusTooltip = targetActivity.statusTooltip; + + var thisActivity = this; + + this.shape.animate(getShapeAttributes(thisActivity), 2000, "linear", function() { + addEffects(thisActivity); + }); + } +} + +function SupportActivity(index, name, id, status, url) { + this.index = index; + this.name = name; + this.id = id; + this.status = status; + this.url = url; + + this.y = 17 + 33*index; + this.statusTooltip = LABEL_SUPPORT_ACTIVITY; + + if (status <= 2) { + this.path = "M16 " + this.y + PATH_ATTEMPTED_ACTIVITY; + this.fill = COLOR_ATTEMPTED_ACTIVITY; + this.stroke = COLOR_TOSTART_ACTIVITY; + } else if (status == 3) { + this.path = "M16 " + this.y + PATH_TOSTART_ACTIVITY; + this.fill = COLOR_TOSTART_ACTIVITY; + } + + this.accessTransform = function(){ + this.path = "M16 " + this.y + PATH_ATTEMPTED_ACTIVITY; + this.fill = COLOR_ATTEMPTED_ACTIVITY; + this.stroke = COLOR_TOSTART_ACTIVITY; + + var thisActivity = this; + + this.shape.animate(getShapeAttributes(thisActivity), 2000, "linear", function() { + addEffects(thisActivity, true); + }); + } +} + +function getShapeAttributes(activity) { + return { + 'path' : activity.path, + 'fill' : activity.fill, + 'stroke' : activity.stroke ? activity.stroke : "#000000", + 'stroke-width' : activity.stroke ? 2 : 1, + 'cursor' : 'pointer' + } +} + + +// refresh progress bar on first/next activity load +function fillProgressBar() { + $.ajax({ + url : APP_URL + 'learner.do', + data : { + 'method' : 'displayProgressJSON', + 'lessonID' : lessonId + }, + cache : false, + dataType : 'json', + success : function(result) { + // if nothing changed, don't do any calculations + if (!currentActivityId || result.currentActivityId != currentActivityId) { + currentActivityId = result.currentActivityId; + + if (!paper) { + // create paper only the first time + paper = Raphael('progressBarDiv', 140, 60*result.activities.length); + // first line on the top + paper.path("M70 0 v20"); + } + + // we need this to scroll to the current activity + var currentActivityIndex = 0; + + $.each(result.activities, function(activityIndex, activityData) { + var activity = new Activity(activityIndex, activityData.name, + activityData.id, activityData.status, activityData.url); + if (activity.id == currentActivityId) { + currentActivityIndex = activityIndex; + } + + var existingActivity = activities[activityIndex]; + if (existingActivity) { + // we are refreshing existing bar, so animate if needed + if (activity.status != existingActivity.status) { + existingActivity.transform(activity); + } + } else { + // we are drawing bar from the scratch + activities[activityIndex] = activity; + activity.shape = paper.path(activity.path); + activity.shape.attr(getShapeAttributes(activity)); + addEffects(activity); + // label underneath the shape + paper.text(70, 43 + 60 * activityIndex, activity.name); + if (activityIndex < result.activities.length - 1) { + // line between activities + paper.path("M70 " + (50 + 60 * activityIndex) + " v30"); + } + } + }); + + // draw support activities if they exist + if (result.support && !supportSeparatorRow.is(':visible')) { + supportSeparatorRow.show(); + supportPart.height(17 + 33 * result.support.length).show(); + + var supportPaper = Raphael('supportPart'); + + jQuery.each(result.support, function(activityIndex, activityData) { + var activity = new SupportActivity(activityIndex, activityData.name, + activityData.id, activityData.status, activityData.url); + activity.shape = supportPaper.path(activity.path); + activity.shape.attr(getShapeAttributes(activity)); + addEffects(activity, true); + supportPaper.text(90, 24 + 33 * activityIndex, activity.name); + }); + } + + resizeElements(); + // scroll to the current activity + $('#progressBarDiv').scrollTop(Math.max((currentActivityIndex-1)*60, 0)); + } + } + }); +} + +// adds handlers to activity for mouse interactions +function addEffects(activity, isSupportActivity) { + // remove any existing handlers + if (activity.shape.glowRef) { + activity.shape.glowRef.remove(); + activity.shape.glowRef = null; + } + if (activity.shape.glowOn) { + activity.shape.unmouseover(activity.shape.glowOn); + } + if (activity.shape.glowOff) { + activity.shape.unmouseout(activity.shape.glowOff); + } + if (activity.shape.doubleclick) { + activity.shape.undblclick(activity.shape.doubleclick); + } + + activity.shape.glowOn = function(e, x, y) { + // add glowing effect on hover + this.glowRef = this.glow({ + color : this.attr('fill') + }); + + // add tooltip + var tooltipText = '' + activity.name + '
' + activity.statusTooltip; + tooltipDiv.stop(true, true).css("left", 30).css("top", y + 20) + .html(tooltipText) + .delay(1000).fadeIn(); + } + + activity.shape.glowOff = function() { + if (activity.shape.glowRef) { + this.glowRef.remove(); + this.glowRef = null; + } + + tooltipDiv.stop(true, true).fadeOut(); + } + + activity.shape.hover(activity.shape.glowOn, activity.shape.glowOff); + + // open pop up if it is a support or completed activity + if (activity.url && (isSupportActivity || activity.status == 1 && activity.url)) { + activity.shape.doubleclick = function(){ + if (isSupportActivity) { + activity.accessTransform(); + } + openActivity(activity.url); + } + + activity.shape.dblclick(activity.shape.doubleclick); + } +} \ No newline at end of file