Index: lams_build/lib/lams/lams.jar =================================================================== diff -u -r40eb54374e84591563d8b6a679ac719dbc85c8f7 -rfe06d16b234341fc965d9b40494e6a2fb4cb9438 Binary files differ Index: lams_central/src/java/org/lamsfoundation/lams/authoring/ObjectExtractor.java =================================================================== diff -u -raa19ce90c4ed489336e8d4ab26ab432f2ef91501 -rfe06d16b234341fc965d9b40494e6a2fb4cb9438 --- lams_central/src/java/org/lamsfoundation/lams/authoring/ObjectExtractor.java (.../ObjectExtractor.java) (revision aa19ce90c4ed489336e8d4ab26ab432f2ef91501) +++ lams_central/src/java/org/lamsfoundation/lams/authoring/ObjectExtractor.java (.../ObjectExtractor.java) (revision fe06d16b234341fc965d9b40494e6a2fb4cb9438) @@ -63,6 +63,7 @@ import org.lamsfoundation.lams.learningdesign.LearningLibrary; import org.lamsfoundation.lams.learningdesign.License; import org.lamsfoundation.lams.learningdesign.OptionsActivity; +import org.lamsfoundation.lams.learningdesign.OptionsWithSequencesActivity; import org.lamsfoundation.lams.learningdesign.ParallelActivity; import org.lamsfoundation.lams.learningdesign.PermissionGateActivity; import org.lamsfoundation.lams.learningdesign.RandomGrouping; @@ -2021,8 +2022,9 @@ if (defaultActivityMapUIID != null) { defaultActivityMap.put(defaultActivityMapUIID, activity); } - - if (activity instanceof OptionsActivity) { + if (activity instanceof OptionsWithSequencesActivity) { + buildOptionsWithSequencesActivity((OptionsWithSequencesActivity) activity, activityDetails); + } else if (activity instanceof OptionsActivity) { buildOptionsActivity((OptionsActivity) activity, activityDetails); } else if (activity instanceof ParallelActivity) { buildParallelActivity((ParallelActivity) activity); @@ -2150,6 +2152,16 @@ AuthoringJsonTags.OPTIONS_INSTRUCTIONS)); } + private void buildOptionsWithSequencesActivity(OptionsWithSequencesActivity optionsActivity, + JSONObject activityDetails) throws JSONException { + buildOptionsActivity(optionsActivity, activityDetails); + + optionsActivity.setStartXcoord(getCoord(activityDetails, AuthoringJsonTags.START_XCOORD)); + optionsActivity.setStartYcoord(getCoord(activityDetails, AuthoringJsonTags.START_YCOORD)); + optionsActivity.setEndXcoord(getCoord(activityDetails, AuthoringJsonTags.END_XCOORD)); + optionsActivity.setEndYcoord(getCoord(activityDetails, AuthoringJsonTags.END_YCOORD)); + } + private void buildParallelActivity(ParallelActivity activity) { } @@ -2984,18 +2996,20 @@ conditionDetails.getInt(AuthoringJsonTags.ORDER_ID), conditionDetails.getString(AuthoringJsonTags.CONDITION_NAME), conditionDetails.getString(AuthoringJsonTags.CONDITION_DISPLAY_NAME), - conditionDetails.getString(AuthoringJsonTags.CONDITION_TYPE), - (String) JsonUtil.opt(conditionDetails, AuthoringJsonTags.CONDITION_START_VALUE), - (String) JsonUtil.opt(conditionDetails, AuthoringJsonTags.CONDITION_END_VALUE), - (String) JsonUtil.opt(conditionDetails, AuthoringJsonTags.CONDITION_EXACT_MATCH_VALUE)); + conditionDetails.getString(AuthoringJsonTags.CONDITION_TYPE), (String) JsonUtil.opt( + conditionDetails, AuthoringJsonTags.CONDITION_START_VALUE), (String) JsonUtil.opt( + conditionDetails, AuthoringJsonTags.CONDITION_END_VALUE), (String) JsonUtil.opt( + conditionDetails, AuthoringJsonTags.CONDITION_EXACT_MATCH_VALUE)); } else { condition.setConditionUIID(conditionUIID); condition.setDisplayName(conditionDetails.getString(AuthoringJsonTags.CONDITION_DISPLAY_NAME)); condition.setEndValue((String) JsonUtil.opt(conditionDetails, AuthoringJsonTags.CONDITION_END_VALUE)); - condition.setExactMatchValue((String) JsonUtil.opt(conditionDetails, AuthoringJsonTags.CONDITION_EXACT_MATCH_VALUE)); + condition.setExactMatchValue((String) JsonUtil.opt(conditionDetails, + AuthoringJsonTags.CONDITION_EXACT_MATCH_VALUE)); condition.setName(conditionDetails.getString(AuthoringJsonTags.CONDITION_NAME)); condition.setOrderId(conditionDetails.getInt(AuthoringJsonTags.ORDER_ID)); - condition.setStartValue((String) JsonUtil.opt(conditionDetails, AuthoringJsonTags.CONDITION_START_VALUE)); + condition.setStartValue((String) JsonUtil + .opt(conditionDetails, AuthoringJsonTags.CONDITION_START_VALUE)); condition.setType(conditionDetails.getString(AuthoringJsonTags.CONDITION_TYPE)); } } Index: lams_central/src/java/org/lamsfoundation/lams/authoring/service/AuthoringService.java =================================================================== diff -u -r10c87fd05c34bda4f1695bb872296803ab77faa0 -rfe06d16b234341fc965d9b40494e6a2fb4cb9438 --- lams_central/src/java/org/lamsfoundation/lams/authoring/service/AuthoringService.java (.../AuthoringService.java) (revision 10c87fd05c34bda4f1695bb872296803ab77faa0) +++ lams_central/src/java/org/lamsfoundation/lams/authoring/service/AuthoringService.java (.../AuthoringService.java) (revision fe06d16b234341fc965d9b40494e6a2fb4cb9438) @@ -23,6 +23,7 @@ /* $$Id$$ */ package org.lamsfoundation.lams.authoring.service; +import java.io.File; import java.io.IOException; import java.text.ParseException; import java.util.ArrayList; @@ -41,6 +42,7 @@ import javax.servlet.http.HttpSession; +import org.apache.commons.io.FileUtils; import org.apache.log4j.Logger; import org.apache.tomcat.util.json.JSONException; import org.apache.tomcat.util.json.JSONObject; @@ -495,8 +497,9 @@ learningDesignID).serializeMessage()); } - boolean learningDesignAvailable = design.getEditOverrideUser() == null || design.getEditOverrideLock() == null - || design.getEditOverrideUser().getUserId().equals(userID) || !design.getEditOverrideLock(); + boolean learningDesignAvailable = (design.getEditOverrideUser() == null) + || (design.getEditOverrideLock() == null) || design.getEditOverrideUser().getUserId().equals(userID) + || !design.getEditOverrideLock(); if (learningDesignAvailable) { if (design.getLessons().isEmpty()) { @@ -541,7 +544,7 @@ Activity lastReadOnlyActivity = processor.getLastReadOnlyActivity(); // check if system gate already exists - if (lastReadOnlyActivity == null || !lastReadOnlyActivity.isGateActivity() + if ((lastReadOnlyActivity == null) || !lastReadOnlyActivity.isGateActivity() || !((GateActivity) lastReadOnlyActivity).isSystemGate()) { // add new System Gate after last read-only Activity addSystemGateAfterActivity(lastReadOnlyActivity, design); @@ -920,6 +923,15 @@ updateEvaluations(newActivities); + try { + AuthoringService.copyLearningDesignImage(originalLearningDesign.getLearningDesignId(), + newLearningDesign.getLearningDesignId(), "svg"); + AuthoringService.copyLearningDesignImage(originalLearningDesign.getLearningDesignId(), + newLearningDesign.getLearningDesignId(), "png"); + } catch (IOException e) { + log.error("Error while copying Learning Design " + originalLearningDesign.getLearningDesignId() + " image", + e); + } return newLearningDesign; } @@ -2021,6 +2033,7 @@ return authorUrl; } + @Override public List getLearningDesignAccessByUser(Integer userId) { List accessList = learningDesignDAO.getAccessByUser(userId); for (LearningDesignAccess access : accessList) { @@ -2031,11 +2044,25 @@ return accessList; } + @Override public void storeLearningDesignAccess(Long learningDesignId, Integer userId) { LearningDesignAccess access = new LearningDesignAccess(); access.setLearningDesignId(learningDesignId); access.setUserId(userId); access.setAccessDate(new Date()); learningDesignDAO.insertOrUpdate(access); } + + /** + * Copies LD thumbnail, SVG or PNG. + */ + private static void copyLearningDesignImage(long originalLearningDesignID, long newLearningDesignID, + String extension) throws IOException { + String fullExtension = "." + extension; + File image = new File(IAuthoringService.LEARNING_DESIGN_IMAGES_FOLDER, originalLearningDesignID + fullExtension); + if (image.canRead()) { + FileUtils.copyFile(image, new File(IAuthoringService.LEARNING_DESIGN_IMAGES_FOLDER, newLearningDesignID + + fullExtension), false); + } + } } \ No newline at end of file Index: lams_central/src/java/org/lamsfoundation/lams/authoring/service/IAuthoringService.java =================================================================== diff -u -r10c87fd05c34bda4f1695bb872296803ab77faa0 -rfe06d16b234341fc965d9b40494e6a2fb4cb9438 --- lams_central/src/java/org/lamsfoundation/lams/authoring/service/IAuthoringService.java (.../IAuthoringService.java) (revision 10c87fd05c34bda4f1695bb872296803ab77faa0) +++ lams_central/src/java/org/lamsfoundation/lams/authoring/service/IAuthoringService.java (.../IAuthoringService.java) (revision fe06d16b234341fc965d9b40494e6a2fb4cb9438) @@ -25,15 +25,12 @@ import java.io.IOException; import java.text.ParseException; -import java.util.ArrayList; import java.util.List; import java.util.Vector; import org.apache.tomcat.util.json.JSONException; import org.apache.tomcat.util.json.JSONObject; import org.lamsfoundation.lams.authoring.ObjectExtractorException; -import org.lamsfoundation.lams.learningdesign.Activity; -import org.lamsfoundation.lams.learningdesign.GateActivity; import org.lamsfoundation.lams.learningdesign.Grouping; import org.lamsfoundation.lams.learningdesign.LearningDesign; import org.lamsfoundation.lams.learningdesign.LearningDesignAccess; @@ -45,6 +42,9 @@ import org.lamsfoundation.lams.usermanagement.WorkspaceFolder; import org.lamsfoundation.lams.usermanagement.exception.UserException; import org.lamsfoundation.lams.usermanagement.exception.WorkspaceFolderException; +import org.lamsfoundation.lams.util.Configuration; +import org.lamsfoundation.lams.util.ConfigurationKeys; +import org.lamsfoundation.lams.util.FileUtil; import org.lamsfoundation.lams.util.FileUtilException; import org.lamsfoundation.lams.util.MessageService; @@ -62,6 +62,9 @@ public static final String COPY_TOOL_CONTENT_MESSAGE_KEY = "copyMultipleToolContent"; + public static final String LEARNING_DESIGN_IMAGES_FOLDER = FileUtil.getFullPath( + Configuration.get(ConfigurationKeys.LAMS_EAR_DIR), "lams-www.war\\secure\\learning-design-images"); + /** * Returns a populated LearningDesign object corresponding to the given learningDesignID * Index: lams_central/src/java/org/lamsfoundation/lams/authoring/web/AuthoringAction.java =================================================================== diff -u -rb92a2c77d9fc93b3a4100d70f95d31a78c4b6792 -rfe06d16b234341fc965d9b40494e6a2fb4cb9438 --- lams_central/src/java/org/lamsfoundation/lams/authoring/web/AuthoringAction.java (.../AuthoringAction.java) (revision b92a2c77d9fc93b3a4100d70f95d31a78c4b6792) +++ lams_central/src/java/org/lamsfoundation/lams/authoring/web/AuthoringAction.java (.../AuthoringAction.java) (revision fe06d16b234341fc965d9b40494e6a2fb4cb9438) @@ -23,8 +23,12 @@ /* $$Id$$ */ package org.lamsfoundation.lams.authoring.web; +import java.io.File; +import java.io.FileOutputStream; import java.io.IOException; +import java.io.OutputStreamWriter; import java.io.PrintWriter; +import java.io.Writer; import java.text.ParseException; import java.util.LinkedList; import java.util.List; @@ -34,6 +38,7 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; +import javax.xml.bind.DatatypeConverter; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; @@ -66,6 +71,8 @@ import org.lamsfoundation.lams.usermanagement.exception.WorkspaceFolderException; import org.lamsfoundation.lams.usermanagement.service.IUserManagementService; import org.lamsfoundation.lams.util.CentralConstants; +import org.lamsfoundation.lams.util.Configuration; +import org.lamsfoundation.lams.util.ConfigurationKeys; import org.lamsfoundation.lams.util.FileUtil; import org.lamsfoundation.lams.util.FileUtilException; import org.lamsfoundation.lams.util.WebUtil; @@ -124,29 +131,13 @@ request.setAttribute("access", gson.toJson(accessList)); return mapping.findForward("openAutoring"); } - public ActionForward generateSVG(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws IOException { request.setAttribute("tools", getLearningDesignService().getToolDTOs(true, request.getRemoteUser())); return mapping.findForward("svgGenerator"); } - - public ActionForward exportSequence(ActionMapping mapping, ActionForm form, HttpServletRequest request, - HttpServletResponse response) throws IOException { - String type = request.getParameter("type"); - - if ("image".equalsIgnoreCase(type)){ - String image = request.getParameter("image"); - String name = request.getParameter("name"); - name = FileUtil.encodeFilenameForDownload(request, name); - response.setContentType("application/x-download"); - response.setHeader("Content-Disposition", "attachment;filename=" + name); - } - - return null; - } /** * Output the supplied WDDX packet. If the request parameter USE_JSP_OUTPUT is set, then it sets the session @@ -510,6 +501,9 @@ useCriticalError ? FlashMessage.CRITICAL_ERROR : FlashMessage.ERROR); } + /** + * Stores Learning Desing created in Flashless Authoring. + */ public ActionForward saveLearningDesign(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws JSONException, UserException, WorkspaceFolderException, IOException, ObjectExtractorException, ParseException { @@ -547,6 +541,9 @@ return null; } + /** + * Gets a list of recently used Learning Designs for currently logged in user. + */ public ActionForward getLearningDesignAccess(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws IOException { Integer userId = getUserId(); @@ -562,6 +559,68 @@ } /** + * Stores the binary code of an Learning Design thumbnail, created in Flashless Authoring. + */ + public ActionForward saveLearningDesignImage(ActionMapping mapping, ActionForm form, HttpServletRequest request, + HttpServletResponse response) { + Long learningDesignID = WebUtil.readLongParam(request, AttributeNames.PARAM_LEARNINGDESIGN_ID); + String extension = request.getParameter("extension"); + String image = request.getParameter("image"); + AuthoringAction.saveLearningDesignImage(learningDesignID, extension, image); + + return null; + } + + /** + * Stores the binary code of an Learning Design thumbnail, created in Flashless Authoring. + */ + private static void saveLearningDesignImage(long learningDesignID, String extension, String image) { + if (StringUtils.isBlank(image) || (!"SVG".equalsIgnoreCase(extension) && !"PNG".equalsIgnoreCase(extension))) { + return; + } + + // prepare the dir and the file + File thumbnailDirectory = new File(IAuthoringService.LEARNING_DESIGN_IMAGES_FOLDER); + if (!thumbnailDirectory.exists()) { + thumbnailDirectory.mkdirs(); + } + + String absoluteFilePath = FileUtil.getFullPath(IAuthoringService.LEARNING_DESIGN_IMAGES_FOLDER, + learningDesignID + "." + extension.toLowerCase()); + + // write out the content + FileOutputStream fos = null; + try { + fos = new FileOutputStream(absoluteFilePath); + if (extension.equalsIgnoreCase("png")) { + // if it comes from Flashless Authoring, it can have a prefix we need to remove + if (image.contains("base64")) { + image = image.substring(image.indexOf(",") + 1); + } + byte[] bytes = DatatypeConverter.parseBase64Binary(image); + fos.write(bytes); + } else { + // encoding is important, especially for Raphael-generated SVGs + Writer writer = new OutputStreamWriter(fos, "UTF8"); + writer.write(image); + writer.close(); + } + } catch (IOException e) { + AuthoringAction.log.error("Error while writing " + extension.toUpperCase() + " thumbnail of LD " + + learningDesignID + ".", e); + } finally { + if (fos != null) { + try { + fos.close(); + } catch (IOException e) { + AuthoringAction.log.error("Error while closing stream to " + extension.toUpperCase() + + " thumbnail of LD " + learningDesignID); + } + } + } + } + + /** * Get AuditService bean. * * @return Index: lams_central/src/java/org/lamsfoundation/lams/web/HomeAction.java =================================================================== diff -u -rcc37b8ce0ecd9bcd071502826ee0764b06f4f493 -rfe06d16b234341fc965d9b40494e6a2fb4cb9438 --- lams_central/src/java/org/lamsfoundation/lams/web/HomeAction.java (.../HomeAction.java) (revision cc37b8ce0ecd9bcd071502826ee0764b06f4f493) +++ lams_central/src/java/org/lamsfoundation/lams/web/HomeAction.java (.../HomeAction.java) (revision fe06d16b234341fc965d9b40494e6a2fb4cb9438) @@ -67,6 +67,7 @@ import org.lamsfoundation.lams.util.CentralConstants; import org.lamsfoundation.lams.util.Configuration; import org.lamsfoundation.lams.util.ConfigurationKeys; +import org.lamsfoundation.lams.util.FileUtil; import org.lamsfoundation.lams.util.WebUtil; import org.lamsfoundation.lams.util.svg.SVGGenerator; import org.lamsfoundation.lams.web.session.SessionManager; @@ -409,14 +410,25 @@ Integer format = WebUtil.readIntParam(req, CentralConstants.PARAM_SVG_FORMAT, true); format = format == null ? SVGGenerator.OUTPUT_FORMAT_PNG : format; Long branchingActivityId = WebUtil.readLongParam(req, "branchingActivityID", true); + boolean download = WebUtil.readBooleanParam(req, "download", false); String imagePath = null; if (branchingActivityId == null) { imagePath = getLearningDesignService().createLearningDesignSVG(learningDesignId, format); } else { imagePath = getLearningDesignService().createBranchingSVG(branchingActivityId, format); } - res.setContentType(format == SVGGenerator.OUTPUT_FORMAT_PNG ? "image/png" : "image/svg+xml"); + // should the image be downloaded or a part of page? + if (download) { + String name = getLearningDesignService().getLearningDesignDTO(learningDesignId, + getUser().getLocaleLanguage()).getTitle(); + name += "." + (format == SVGGenerator.OUTPUT_FORMAT_PNG ? "png" : "svg"); + name = FileUtil.encodeFilenameForDownload(req, name); + res.setContentType("application/x-download"); + res.setHeader("Content-Disposition", "attachment;filename=" + name); + } else { + res.setContentType(format == SVGGenerator.OUTPUT_FORMAT_PNG ? "image/png" : "image/svg+xml"); + } OutputStream output = res.getOutputStream(); FileInputStream input = new FileInputStream(imagePath); IOUtils.copy(input, output); Index: lams_central/web/authoring/authoring.jsp =================================================================== diff -u -r6a09e35ef826da53c8ac37cd4bf00918f7759d6c -rfe06d16b234341fc965d9b40494e6a2fb4cb9438 --- lams_central/web/authoring/authoring.jsp (.../authoring.jsp) (revision 6a09e35ef826da53c8ac37cd4bf00918f7759d6c) +++ lams_central/web/authoring/authoring.jsp (.../authoring.jsp) (revision fe06d16b234341fc965d9b40494e6a2fb4cb9438) @@ -70,7 +70,6 @@ SEQUENCE_NOT_VALID : 'The sequence is not valid.
It needs to be corrected before it can be used in lessons.', SEQUENCE_VALIDATION_ISSUES : 'While saving the sequence there were following validation issues:', SAVE_SUCCESSFUL : 'Congratulations! Your design is valid and has been saved.', - DOWNLOAD_NOT_SUPPORTED : 'Your browser does not support on the fly downloading.', NAVIGATE_AWAY_CONFIRM : 'Your design is not saved.\nAny changes you made since you last saved will be lost.', DELETE_NODE_CONFIRM : 'Are you sure you want to delete this ', SEQUENCE_OVERWRITE_CONFIRM : 'Are you sure you want to overwrite the existing sequence?', Index: lams_central/web/includes/javascript/authoring/authoringActivity.js =================================================================== diff -u -r6a09e35ef826da53c8ac37cd4bf00918f7759d6c -rfe06d16b234341fc965d9b40494e6a2fb4cb9438 --- lams_central/web/includes/javascript/authoring/authoringActivity.js (.../authoringActivity.js) (revision 6a09e35ef826da53c8ac37cd4bf00918f7759d6c) +++ lams_central/web/includes/javascript/authoring/authoringActivity.js (.../authoringActivity.js) (revision fe06d16b234341fc965d9b40494e6a2fb4cb9438) @@ -1,4 +1,4 @@ -/** +/** * This file contains methods for Activity definition and manipulation on canvas. */ @@ -359,12 +359,12 @@ // create activity SVG elements paper.setStart(); - var shape = paper.path(Raphael.format('M {0} {1} l-8 8 v14 l8 8 h14 l8 -8 v-14 l-8 -8 z', x + 8, y)) + var shape = paper.path(Raphael.format('M {0} {1} l-9 9 v16 l9 9 h16 l9 -9 v-16 l-9 -9 z', x + 9, y)) .attr({ 'fill' : layout.colors.gate }); - paper.text(x + 15, y + 14, LABELS.GATE_ACTIVITY_LABEL) + paper.text(x + 17, y + 16, LABELS.GATE_ACTIVITY_LABEL) .attr(layout.defaultTextAttributes) .attr('stroke', layout.colors.gateText); @@ -423,17 +423,17 @@ if (this.childActivityDefs && this.childActivityDefs.length > 0) { // draw one by one, vertically - var activityY = y + containerActivityPadding + 10, + var activityY = y + layout.conf.containerActivityPadding + 10, allElements = paper.set(), optionalActivity = this, box = this.items.shape.getBBox(); $.each(this.childActivityDefs, function(orderID){ this.parentActivity = optionalActivity; this.orderID = orderID + 1; var childBox = this.items.shape.getBBox(); - this.draw(x + Math.max(containerActivityPadding, (box.width - childBox.width)/2), activityY); + this.draw(x + Math.max(layout.conf.containerActivityPadding, (box.width - childBox.width)/2), activityY); childBox = this.items.shape.getBBox(); - activityY = childBox.y2 + containerActivityChildrenPadding; + activityY = childBox.y2 + layout.conf.containerActivityChildrenPadding; allElements.push(this.items.shape); }); // area containing all drawn child activities @@ -445,8 +445,8 @@ layout.colors.optionalActivity); } else { this.drawContainer(x, y, - x + containerActivityEmptyWidth, - y + containerActivityEmptyHeight, + x + layout.conf.containerActivityEmptyWidth, + y + layout.conf.containerActivityEmptyHeight, layout.colors.optionalActivity); } @@ -525,7 +525,6 @@ .attr({ 'fill' : layout.colors.activity[layout.toolMetadata[this.learningLibraryID].activityCategoryID] }); - this.items.shape = shape; this.items.push(shape); Index: lams_central/web/includes/javascript/authoring/authoringDecoration.js =================================================================== diff -u -rb92a2c77d9fc93b3a4100d70f95d31a78c4b6792 -rfe06d16b234341fc965d9b40494e6a2fb4cb9438 --- lams_central/web/includes/javascript/authoring/authoringDecoration.js (.../authoringDecoration.js) (revision b92a2c77d9fc93b3a4100d70f95d31a78c4b6792) +++ lams_central/web/includes/javascript/authoring/authoringDecoration.js (.../authoringDecoration.js) (revision fe06d16b234341fc965d9b40494e6a2fb4cb9438) @@ -92,7 +92,7 @@ } // the rectangle - this.items.shape = paper.path('M {0} {1} L {2} {1} L {2} {3} L {0} {3} z', x, y, x2, y2) + this.items.shape = paper.path('M {0} {1} H {2} V {3} H {0} z', x, y, x2, y2) .attr('fill', color) .toBack(); this.items.push(this.items.shape); Index: lams_central/web/includes/javascript/authoring/authoringGeneral.js =================================================================== diff -u -r6a09e35ef826da53c8ac37cd4bf00918f7759d6c -rfe06d16b234341fc965d9b40494e6a2fb4cb9438 --- lams_central/web/includes/javascript/authoring/authoringGeneral.js (.../authoringGeneral.js) (revision 6a09e35ef826da53c8ac37cd4bf00918f7759d6c) +++ lams_central/web/includes/javascript/authoring/authoringGeneral.js (.../authoringGeneral.js) (revision fe06d16b234341fc965d9b40494e6a2fb4cb9438) @@ -515,10 +515,10 @@ } }); } - }], + }]; // initalise Learning Design load/save dialog - ldStoreDialog = $('#ldStoreDialog').dialog({ + layout.ldStoreDialog = $('#ldStoreDialog').dialog({ 'autoOpen' : false, 'position' : { 'my' : 'left top', @@ -541,7 +541,8 @@ learningDesignID = ldNode ? ldNode.data.learningDesignId : null; if (!learningDesignID) { - learningDesignID = +$('#ldStoreDialogAccessCell > div.selected').attr('learningDesignId'); + learningDesignID = +$('#ldStoreDialogAccessCell > div.selected', this) + .attr('learningDesignId'); } // no LD was chosen @@ -585,7 +586,7 @@ folderID = folderNode.data.folderID; } else { // get data from "recently used sequences" list - var selectedAccess = $('#ldStoreDialogAccessCell > div.selected'); + var selectedAccess = $('#ldStoreDialogAccessCell > div.selected', this); // if title was altered, do not consider this an overwrite if (selectedAccess.length > 0 && title == selectedAccess.text()) { learningDesignID = +selectedAccess.attr('learningDesignId'); @@ -640,7 +641,7 @@ $('#leftDialogButtonContainer').remove(); var nameContainer = $('#ldStoreDialogNameContainer'), leftButtonContainer = $('
').attr('id','leftDialogButtonContainer'); - $('input', nameContainer).val(null); + $('input', nameContainer).val($(this).dialog('option', 'learningDesignTitle')); $(this).siblings('.ui-dialog-buttonpane').append(leftButtonContainer).append(nameContainer); $('#ldStoreDialogNameField', nameContainer).focus(); @@ -654,11 +655,11 @@ } }); - layout.dialogs.push(ldStoreDialog); + layout.dialogs.push(layout.ldStoreDialog); - $('#ldScreenshotAuthor', ldStoreDialog).load(function(){ + $('#ldScreenshotAuthor', layout.ldStoreDialog).load(function(){ // hide "loading" animation - $('#ldStoreDialog .ldChoiceDependentCanvasElement').css('display', 'none'); + $('.ldChoiceDependentCanvasElement', layout.ldStoreDialog).css('display', 'none'); // show the thumbnail $(this).css('display', 'inline'); }); @@ -667,7 +668,7 @@ YAHOO.widget.TreeView.FOCUS_CLASS_NAME = null; var tree = new YAHOO.widget.TreeView('ldStoreDialogTree'); // store the tree in the dialog's data - ldStoreDialog.dialog('option', 'ldTree', tree); + layout.ldStoreDialog.dialog('option', 'ldTree', tree); // make folder contents load dynamically on open tree.setDynamicLoad(function(node, callback){ // load subfolder contents @@ -684,8 +685,7 @@ }); tree.singleNodeHighlight = true; tree.subscribe('clickEvent', function(event){ - var dialog = $(this.getEl()).closest('.ui-dialog'), - isSaveDialog = dialog.hasClass('ldStoreDialogSave'); + var isSaveDialog = layout.ldStoreDialog.hasClass('ldStoreDialogSave'); $('.leftDialogButton') .attr('disabled', event.node.highlightState > 0 ? 'disabled' : null) @@ -1097,6 +1097,7 @@ // get LD details $.ajax({ cache : false, + async : false, url : LAMS_URL + "authoring/author.do", dataType : 'json', data : { @@ -1263,20 +1264,25 @@ case 11: var branchingType = branchingType || 'group'; case 12: var branchingType = branchingType || 'tool'; case 13: - // draw both edge points straight away and mark the whole canvas for auto reaarange - arrangeNeeded = true; + // draw both edge points straight away and mark the whole canvas for auto reaarange, + // re-arrange only if it is old SVG being converted into new one + arrangeNeeded |= activityData.xCoord && activityData.yCoord; var branchingType = branchingType || 'optional', branchingEdge = new ActivityDefs.BranchingEdgeActivity(activityData.activityID, activityData.activityUIID, - 0, 0, + arrangeNeeded ? 0 : activityData.startXCoord, + arrangeNeeded ? 0 : activityData.startYCoord, activityData.activityTitle, branchingType); layout.activities.push(branchingEdge); // for later reference activityData.activity = branchingEdge; branchingEdge = new ActivityDefs.BranchingEdgeActivity( - null, null, 0, 0, null, null, branchingEdge.branchingActivity); + null, null, + arrangeNeeded ? 0 : activityData.endXCoord, + arrangeNeeded ? 0 : activityData.endYCoord, + null, null, branchingEdge.branchingActivity); layout.activities.push(branchingEdge); branchingEdge.branchingActivity.defaultActivityUIID = activityData.defaultActivityUIID; @@ -1873,7 +1879,7 @@ x -= activityBox.x; y -= activityBox.y; } - + // add activity activities.push({ 'activityID' : activity.id, @@ -1891,6 +1897,14 @@ 'libraryActivityUIImage' : iconPath, 'xCoord' : x, 'yCoord' : y, + 'startXCoord' : activity instanceof ActivityDefs.BranchingActivity ? + parseInt(activity.start.items.shape.getBBox().x) : null, + 'startYCoord' : activity instanceof ActivityDefs.BranchingActivity ? + parseInt(activity.start.items.shape.getBBox().y) : null, + 'endXCoord' : activity instanceof ActivityDefs.BranchingActivity ? + parseInt(activity.end.items.shape.getBBox().x) : null, + 'endYCoord' : activity instanceof ActivityDefs.BranchingActivity ? + parseInt(activity.end.items.shape.getBBox().y) : null, 'activityTitle' : activity.title, 'description' : activity.description, 'activityCategoryID' : activityCategoryID, @@ -1901,8 +1915,8 @@ activity.offsetDay*24*60 + activity.offsetHour*60 + activity.offsetMinute : null, 'gateActivityCompletionBased' : activity.gateActivityCompletionBased, 'gateActivityLevelID' : activity instanceof ActivityDefs.GateActivity ? 1 : null, - 'minOptions' : activity.minOptions, - 'maxOptions' : activity.maxOptions, + 'minOptions' : activity.minOptions || null, + 'maxOptions' : activity.maxOptions || null, 'stopAfterActivity' : activity.stopAfterActivity ? true : false, 'toolActivityUIID' : activity.input ? activity.input.uiid : null, @@ -2095,6 +2109,8 @@ }); }); + GeneralLib.saveLearningDesignImages(); + if (response.validation.length == 0) { alert(LABELS.SAVE_SUCCESSFUL); } @@ -2113,6 +2129,33 @@ return result; }, + + /** + * Stores SVG and PNG LD thumbnails on server. + */ + saveLearningDesignImages : function() { + $.ajax({ + type : 'POST', + url : LAMS_URL + 'authoring/author.do', + data : { + 'method' : 'saveLearningDesignImage', + 'learningDesignID' : layout.ld.learningDesignID, + 'extension' : 'SVG', + 'image' : MenuLib.exportSVG() + } + }); + $.ajax({ + type : 'POST', + url : LAMS_URL + 'authoring/author.do', + data : { + 'method' : 'saveLearningDesignImage', + 'learningDesignID' : layout.ld.learningDesignID, + 'extension' : 'PNG', + 'image' : MenuLib.exportPNG() + } + }); + }, + /** * Tells that current sequence was modified and not saved. @@ -2139,7 +2182,9 @@ $('#ldDescriptionFieldModified').text('*'); } - if (layout.conf.supportsDownloadAttribute && activitiesExist) { + // if the browser does not support HTML5 "download" attribute, + // the image can only be received from the LD saved on the server + if ((!modified || layout.conf.supportsDownloadAttribute) && activitiesExist) { $('.exportImageButton').attr('disabled', null) .css('opacity', 1); enableExportButton = true; @@ -2166,10 +2211,9 @@ // display "loading" animation and finally LD thumbnail $('.ldChoiceDependentCanvasElement').css('display', 'none'); if (learningDesignID) { - var dialogContent = $('#ldStoreDialog'); - $('#ldScreenshotLoading', dialogContent).css('display', 'inline'); + $('#ldScreenshotLoading', layout.ldStoreDialog).css('display', 'inline'); // get the image of the chosen LD and prevent caching - $('#ldScreenshotAuthor', dialogContent) + $('#ldScreenshotAuthor', layout.ldStoreDialog) .attr('src', LD_THUMBNAIL_URL_BASE + learningDesignID + '&_=' + new Date().getTime()) .css({ 'width' : 'auto', @@ -2180,15 +2224,15 @@ $('#ldStoreDialogNameField').val(title).focus(); } - var tree = $('#ldStoreDialog').dialog('option', 'ldTree'), + var tree = layout.ldStoreDialog.dialog('option', 'ldTree'), ldNode = tree.getHighlightedNode(); // no LD was chosen if (ldNode && learningDesignID != ldNode.data.learningDesignId) { ldNode.unhighlight(true); } } - $('#ldStoreDialogAccessCell > div.access', dialogContent).each(function(){ + $('#ldStoreDialogAccessCell > div.access', layout.ldStoreDialog).each(function(){ var access = $(this); if (+access.attr('learningDesignId') == learningDesignID){ access.addClass('selected'); @@ -2232,7 +2276,7 @@ } if (access) { - var accessCell = $('#ldStoreDialogAccessCell'); + var accessCell = $('#ldStoreDialogAccessCell', layout.ldStoreDialog); accessCell.children('div.access').remove(); $.each(access, function(){ $('
').addClass('access') @@ -2248,8 +2292,7 @@ return; } - var dialog = accessEntry.closest('.ui-dialog'), - isSaveDialog = dialog.hasClass('ldStoreDialogSave'), + var isSaveDialog = layout.ldStoreDialog.hasClass('ldStoreDialogSave'), learningDesignID = +accessEntry.attr('learningDesignId'), title = isSaveDialog ? accessEntry.text() : null; Index: lams_central/web/includes/javascript/authoring/authoringMenu.js =================================================================== diff -u -r6a09e35ef826da53c8ac37cd4bf00918f7759d6c -rfe06d16b234341fc965d9b40494e6a2fb4cb9438 --- lams_central/web/includes/javascript/authoring/authoringMenu.js (.../authoringMenu.js) (revision 6a09e35ef826da53c8ac37cd4bf00918f7759d6c) +++ lams_central/web/includes/javascript/authoring/authoringMenu.js (.../authoringMenu.js) (revision fe06d16b234341fc965d9b40494e6a2fb4cb9438) @@ -96,11 +96,6 @@ layout.exportLDDialog.dialog('close'); }); layout.dialogs.push(layout.exportLDDialog); - - - if (!layout.conf.supportsDownloadAttribute) { - $('.exportImageButton').attr('title', LABELS.DOWNLOAD_NOT_SUPPORTED); - } }, @@ -347,26 +342,39 @@ * Creates a PNG image out of current SVG contents. */ exportPNG : function(download){ - var crop = MenuLib.getCanvasCrop(); - if (crop.x >= crop.x2) { - return; - } + ActivityLib.removeSelectEffect(); - var ctx = crop.workspace.getContext('2d'), - w = crop.x2 - crop.x, - h = crop.y2 - crop.y, - cut = ctx.getImageData(crop.x, crop.y, w, h); - - crop.workspace.width = w; - crop.workspace.height = h; - ctx.putImageData(cut, 0, 0); - - var imageCode = crop.workspace.toDataURL("image/png"); + var imageCode = null; + if (!download || layout.conf.supportsDownloadAttribute) { + var crop = MenuLib.getCanvasCrop(); + if (crop.x >= crop.x2) { + return; + } + + var ctx = crop.workspace.getContext('2d'), + w = crop.x2 - crop.x, + h = crop.y2 - crop.y, + cut = ctx.getImageData(crop.x, crop.y, w, h); + + crop.workspace.width = w; + crop.workspace.height = h; + ctx.putImageData(cut, 0, 0); + + imageCode = crop.workspace.toDataURL("image/png"); + } if (download) { - $('a', layout.exportImageDialog).attr({ - 'href' : imageCode, - 'download' : (layout.ld.title ? layout.ld.title : 'Untitled') + '.png' - }); + var anchor = $('a', layout.exportImageDialog); + if (layout.conf.supportsDownloadAttribute) { + anchor.attr({ + 'href' : imageCode, + 'download' : (layout.ld.title ? layout.ld.title : 'Untitled') + '.png' + }); + } else { + anchor.attr({ + 'href' : LD_THUMBNAIL_URL_BASE + layout.ld.learningDesignID + + '&svgFormat=2&download=true&_=' + new Date().getTime() + }); + } layout.exportImageDialog.dialog('open'); } else { return imageCode; @@ -378,62 +386,83 @@ * Creates a SVG image out of current SVG contents. */ exportSVG : function(download){ - var crop = MenuLib.getCanvasCrop(); - if (crop.x >= crop.x2) { - return; - } + ActivityLib.removeSelectEffect(); - // replace image links with PNG code - var iconLibrary = {}; - crop.canvasClone.find('image').each(function(){ - var attributeName = 'xlink:href', - iconLink = $(this).attr(attributeName); - if (!iconLink) { - attributeName = 'href', - iconLink = $(this).attr(attributeName); + var imageCode = null; + if (!download || layout.conf.supportsDownloadAttribute) { + var crop = MenuLib.getCanvasCrop(); + if (crop.x >= crop.x2) { + return; } - var iconCode = iconLibrary[iconLink]; - if (!iconCode) { - $.ajax({ - url : iconLink, - async: false, - dataType : 'text', - success : function(response) { - iconCode = iconLibrary[iconLink] = response; - } - }); - } - if (!iconCode) { - return true; - } + // replace image links with PNG code + var iconLibrary = {}; + crop.canvasClone.find('image').each(function(){ + var attributeName = 'xlink:href', + iconLink = $(this).attr(attributeName); + if (!iconLink) { + attributeName = 'href', + iconLink = $(this).attr(attributeName); + } + + var iconCode = iconLibrary[iconLink]; + if (!iconCode) { + $.ajax({ + url : iconLink, + async: false, + dataType : 'text', + success : function(response) { + iconCode = iconLibrary[iconLink] = response; + } + }); + } + if (!iconCode) { + return true; + } + + canvg(crop.workspace, iconCode); + $(this).attr(attributeName, crop.workspace.toDataURL("image/png")); + }); - canvg(crop.workspace, iconCode); - $(this).attr(attributeName, crop.workspace.toDataURL("image/png")); - }); + + + // set viewBox so content is nicely aligned + var width = crop.x2 - crop.x + 2, + height = crop.y2 - crop.y + 2, + svg = $('svg', crop.canvasClone).attr({ + 'width' : width, + 'height' : height + })[0]; + + // need to set attributes using pure JS as jQuery sets them with lower case, which is unacceptable in SVG + svg.setAttribute('viewBox', crop.x + ' ' + crop.y + ' ' + width + ' ' + height); + svg.setAttribute('preserveAspectRatio', 'xMinYMin slice'); + + // reset any cursor=pointer styles + $('*[style*="cursor"]', svg).css('cursor', 'default'); + + + imageCode = crop.canvasClone.html(); + // otherwise there will be syntax erros in IE11 + imageCode = imageCode.replace(/xmlns=\"http:\/\/www\.w3\.org\/2000\/svg\"/, ''); + imageCode = imageCode.replace(/xmlns:NS1=\"\"/, ''); + imageCode = imageCode.replace(/NS1:xmlns:xlink=\"http:\/\/www\.w3\.org\/1999\/xlink\"/, 'xmlns:xlink=\"http:\/\/www\.w3\.org\/1999\/xlink\"'); + imageCode = imageCode.replace(/xmlns:xlink=\"http:\/\/www\.w3\.org\/1999\/xlink\" xlink:href/g, 'xlink:href'); + } - - // set viewBox so content is nicely aligned - var width = crop.x2 - crop.x + 2, - height = crop.y2 - crop.y + 2, - svg = $('svg', crop.canvasClone).attr({ - 'width' : width, - 'height' : height - })[0]; - - // need to set attributes using pure JS as jQuery sets them with lower case, which is unacceptable in SVG - svg.setAttribute('viewBox', crop.x + ' ' + crop.y + ' ' + width + ' ' + height); - svg.setAttribute('preserveAspectRatio', 'xMinYMin slice'); - - // reset any cursor=pointer styles - $('*[style*="cursor"]', svg).css('cursor', 'default'); - - var imageCode = crop.canvasClone.html(); if (download) { - $('a', layout.exportImageDialog).attr({ - 'href' : 'data:image/svg+xml;charset=utf-8,' + encodeURIComponent(imageCode), - 'download' : (layout.ld.title ? layout.ld.title : 'Untitled') + '.svg' - }); + var anchor = $('a', layout.exportImageDialog); + if (layout.conf.supportsDownloadAttribute) { + anchor.attr({ + 'href' : 'data:image/svg+xml;charset=utf-8,' + encodeURIComponent(imageCode), + 'download' : (layout.ld.title ? layout.ld.title : 'Untitled') + '.svg' + }); + } else { + anchor.attr({ + 'href' : LD_THUMBNAIL_URL_BASE + layout.ld.learningDesignID + + '&svgFormat=1&download=true&_=' + new Date().getTime() + }); + } layout.exportImageDialog.dialog('open'); } else { return imageCode; @@ -557,11 +586,14 @@ } var body = $('body', importWindow.document).html(), match = regEx.exec(body); - // check if ID was found and it's not the same as previously + // check if ID was found and it's not the same as previously set if (match && match[1] != currentLearningDesignID) { currentLearningDesignID = match[1]; // load the imported LD GeneralLib.openLearningDesign(currentLearningDesignID); + + // generate images of the imported LD + GeneralLib.saveLearningDesignImages(); } }, 1000); }, @@ -571,8 +603,7 @@ * Loads Learning Design Tree from DB */ loadLearningDesignTree : function(){ - var dialog = $('#ldStoreDialog'), - tree = dialog.dialog('option', 'ldTree'), + var tree = layout.ldStoreDialog.dialog('option', 'ldTree'), rootNode = tree.getRoot(); // remove existing folders $.each(rootNode.children, function(){ @@ -593,13 +624,13 @@ * Opens "Open sequence" dialog where an user can choose a Learning Design to load. */ openLearningDesign : function(){ - var dialog = $('#ldStoreDialog'); // remove the directory tree, if it remained for last dialog opening - dialog.dialog('option', { - 'title' : LABELS.OPEN_DIALOG_TITLE, - 'buttons' : dialog.dialog('option', 'buttonsLoad'), + layout.ldStoreDialog.dialog('option', { + 'title' : LABELS.OPEN_DIALOG_TITLE, + 'learningDesignTitle' : null, + 'buttons' : layout.ldStoreDialog.dialog('option', 'buttonsLoad'), // it informs widgets that it is load dialog - 'dialogClass': 'ldStoreDialogLoad' + 'dialogClass' : 'ldStoreDialogLoad' }) .dialog('open'); @@ -715,13 +746,13 @@ return; } - var dialog = $('#ldStoreDialog'); // remove the directory tree, if it remained for last dialog opening - dialog.dialog('option', { - 'title' : LABELS.SAVE_DIALOG_TITLE, - 'buttons' : dialog.dialog('option', 'buttonsSave'), + layout.ldStoreDialog.dialog('option', { + 'title' : LABELS.SAVE_DIALOG_TITLE, + 'learningDesignTitle' : layout.ld.title, + 'buttons' : layout.ldStoreDialog.dialog('option', 'buttonsSave'), // it informs widgets that it is saved dialog - 'dialogClass': 'ldStoreDialogSave' + 'dialogClass' : 'ldStoreDialogSave' }) .dialog('open'); Index: lams_common/conf/hibernate/mappings/org/lamsfoundation/lams/learningdesign/Activity.hbm.xml =================================================================== diff -u -raead34144651a924f76d7bca8645327e6820d226 -rfe06d16b234341fc965d9b40494e6a2fb4cb9438 --- lams_common/conf/hibernate/mappings/org/lamsfoundation/lams/learningdesign/Activity.hbm.xml (.../Activity.hbm.xml) (revision aead34144651a924f76d7bca8645327e6820d226) +++ lams_common/conf/hibernate/mappings/org/lamsfoundation/lams/learningdesign/Activity.hbm.xml (.../Activity.hbm.xml) (revision fe06d16b234341fc965d9b40494e6a2fb4cb9438) @@ -312,6 +312,19 @@ @hibernate.class + + + @hibernate.property column="start_xcoord" length="11" + + + @hibernate.property column="start_ycoord" length="11" + + + @hibernate.property column="end_xcoord" length="11" + + + @hibernate.property column="end_ycoord" length="11" + Index: lams_common/src/java/org/lamsfoundation/lams/learningdesign/Activity.java =================================================================== diff -u -rc135649b64e98c9233da20bdcfb7689598116314 -rfe06d16b234341fc965d9b40494e6a2fb4cb9438 --- lams_common/src/java/org/lamsfoundation/lams/learningdesign/Activity.java (.../Activity.java) (revision c135649b64e98c9233da20bdcfb7689598116314) +++ lams_common/src/java/org/lamsfoundation/lams/learningdesign/Activity.java (.../Activity.java) (revision fe06d16b234341fc965d9b40494e6a2fb4cb9438) @@ -805,6 +805,10 @@ return getActivityTypeId().intValue() == Activity.OPTIONS_ACTIVITY_TYPE || getActivityTypeId().intValue() == Activity.OPTIONS_WITH_SEQUENCES_TYPE; } + + public boolean isOptionsWithSequencesActivity() { + return getActivityTypeId().intValue() == Activity.OPTIONS_WITH_SEQUENCES_TYPE; + } public boolean isComplexActivity() { return getActivityTypeId().intValue() == Activity.SEQUENCE_ACTIVITY_TYPE Index: lams_common/src/java/org/lamsfoundation/lams/learningdesign/LearningDesignProcessor.java =================================================================== diff -u -r2f21856ec2ab85b47c93cfcc3fa2c8769be65077 -rfe06d16b234341fc965d9b40494e6a2fb4cb9438 --- lams_common/src/java/org/lamsfoundation/lams/learningdesign/LearningDesignProcessor.java (.../LearningDesignProcessor.java) (revision 2f21856ec2ab85b47c93cfcc3fa2c8769be65077) +++ lams_common/src/java/org/lamsfoundation/lams/learningdesign/LearningDesignProcessor.java (.../LearningDesignProcessor.java) (revision fe06d16b234341fc965d9b40494e6a2fb4cb9438) @@ -86,8 +86,8 @@ .warn("Parsing activity method handleActivity got a null activity. Learning design was " + getDesign()); } else { - if (LearningDesignProcessor.log.isDebugEnabled()) { - LearningDesignProcessor.log.debug("Processing activity " + activity.getActivityId() + " " + if (LearningDesignProcessor.log.isTraceEnabled()) { + LearningDesignProcessor.log.trace("Processing activity " + activity.getActivityId() + " " + activity.getTitle()); } if (activity.isComplexActivity()) { Index: lams_common/src/java/org/lamsfoundation/lams/learningdesign/OptionsActivity.java =================================================================== diff -u -rc135649b64e98c9233da20bdcfb7689598116314 -rfe06d16b234341fc965d9b40494e6a2fb4cb9438 --- lams_common/src/java/org/lamsfoundation/lams/learningdesign/OptionsActivity.java (.../OptionsActivity.java) (revision c135649b64e98c9233da20bdcfb7689598116314) +++ lams_common/src/java/org/lamsfoundation/lams/learningdesign/OptionsActivity.java (.../OptionsActivity.java) (revision fe06d16b234341fc965d9b40494e6a2fb4cb9438) @@ -24,7 +24,6 @@ package org.lamsfoundation.lams.learningdesign; import java.io.Serializable; -import java.util.Date; import java.util.Set; import org.apache.commons.lang.builder.ToStringBuilder; @@ -45,24 +44,6 @@ /** nullable persistent field */ private String optionsInstructions; - /** full constructor */ - public OptionsActivity(Long activityId, Integer id, String description, String title, Integer xcoord, - Integer ycoord, Integer orderId, java.util.Date createDateTime, LearningLibrary learningLibrary, - Activity parentActivity, Activity libraryActivity, Integer parentUIID, LearningDesign learningDesign, - Grouping grouping, Integer activityTypeId, Transition transitionTo, Transition transitionFrom, - String languageFile, Boolean stopAfterActivity, Set inputActivities, Set activities, - Activity defaultActivity, Integer maxNumberOfOptions, Integer minNumberOfOptions, - String options_instructions, Set branchActivityEntries) { - super(activityId, id, description, title, xcoord, ycoord, orderId, createDateTime, learningLibrary, - parentActivity, libraryActivity, parentUIID, learningDesign, grouping, activityTypeId, transitionTo, - transitionFrom, languageFile, stopAfterActivity, inputActivities, activities, defaultActivity, - branchActivityEntries); - this.maxNumberOfOptions = maxNumberOfOptions; - this.minNumberOfOptions = minNumberOfOptions; - this.optionsInstructions = options_instructions; - super.activityStrategy = new OptionsActivityStrategy(this); - } - /** default constructor */ public OptionsActivity() { super.activityStrategy = new OptionsActivityStrategy(this); @@ -80,6 +61,7 @@ super.activityStrategy = new OptionsActivityStrategy(this); } + @Override public Activity createCopy(int uiidOffset) { OptionsActivity newOptionsActivity = new OptionsActivity(); copyToNewComplexActivity(newOptionsActivity, uiidOffset); @@ -92,9 +74,7 @@ return newOptionsActivity; } - /** - * @hibernate.property column="max_number_of_options" length="5" - */ + public Integer getMaxNumberOfOptions() { return this.maxNumberOfOptions; } @@ -111,9 +91,6 @@ this.maxNumberOfOptions = maxNumberOfOptions; } - /** - * @hibernate.property column="min_number_of_options" length="5" - */ public Integer getMinNumberOfOptions() { return this.minNumberOfOptions; } @@ -129,6 +106,7 @@ this.minNumberOfOptions = minNumberOfOptions; } + @Override public String toString() { return new ToStringBuilder(this).append("activityId", getActivityId()).toString(); } @@ -144,6 +122,7 @@ /** * @see org.lamsfoundation.lams.util.Nullable#isNull() */ + @Override public boolean isNull() { return false; } Index: lams_common/src/java/org/lamsfoundation/lams/learningdesign/OptionsWithSequencesActivity.java =================================================================== diff -u -rac99dd8a79daaa42b1e6cdbe9b1a5fd197107b83 -rfe06d16b234341fc965d9b40494e6a2fb4cb9438 --- lams_common/src/java/org/lamsfoundation/lams/learningdesign/OptionsWithSequencesActivity.java (.../OptionsWithSequencesActivity.java) (revision ac99dd8a79daaa42b1e6cdbe9b1a5fd197107b83) +++ lams_common/src/java/org/lamsfoundation/lams/learningdesign/OptionsWithSequencesActivity.java (.../OptionsWithSequencesActivity.java) (revision fe06d16b234341fc965d9b40494e6a2fb4cb9438) @@ -23,13 +23,58 @@ /* $Id$ */ package org.lamsfoundation.lams.learningdesign; -/** - * The OptionsWithSequencesActivity was created to allow Flash to know whether or - * not to expect sequences. The progress engine treads OptionsWithSequencesActivity - * and OptionsActivity exactly the same. - * - * @hibernate.class - */ + public class OptionsWithSequencesActivity extends OptionsActivity { + private Integer startXcoord; + private Integer startYcoord; + private Integer endXcoord; + private Integer endYcoord; + @Override + public Activity createCopy(int uiidOffset) { + OptionsWithSequencesActivity newOptionsActivity = new OptionsWithSequencesActivity(); + copyToNewComplexActivity(newOptionsActivity, uiidOffset); + + newOptionsActivity.setMaxNumberOfOptions(this.getMaxNumberOfOptions()); + newOptionsActivity.setMinNumberOfOptions(this.getMinNumberOfOptions()); + newOptionsActivity.setOptionsInstructions(this.getOptionsInstructions()); + newOptionsActivity.startXcoord = this.startXcoord; + newOptionsActivity.startYcoord = this.startYcoord; + newOptionsActivity.endXcoord = this.endXcoord; + newOptionsActivity.endYcoord = this.endYcoord; + + return newOptionsActivity; + } + + public Integer getEndXcoord() { + return endXcoord; + } + + public void setEndXcoord(Integer endXcoord) { + this.endXcoord = endXcoord; + } + + public Integer getEndYcoord() { + return endYcoord; + } + + public void setEndYcoord(Integer endYcoord) { + this.endYcoord = endYcoord; + } + + public Integer getStartXcoord() { + return startXcoord; + } + + public void setStartXcoord(Integer startXcoord) { + this.startXcoord = startXcoord; + } + + public Integer getStartYcoord() { + return startYcoord; + } + + public void setStartYcoord(Integer startYcoord) { + this.startYcoord = startYcoord; + } } Index: lams_common/src/java/org/lamsfoundation/lams/learningdesign/dto/AuthoringActivityDTO.java =================================================================== diff -u -r279ab8b6c6d02f80bb949e44011343f6c7150f6e -rfe06d16b234341fc965d9b40494e6a2fb4cb9438 --- lams_common/src/java/org/lamsfoundation/lams/learningdesign/dto/AuthoringActivityDTO.java (.../AuthoringActivityDTO.java) (revision 279ab8b6c6d02f80bb949e44011343f6c7150f6e) +++ lams_common/src/java/org/lamsfoundation/lams/learningdesign/dto/AuthoringActivityDTO.java (.../AuthoringActivityDTO.java) (revision fe06d16b234341fc965d9b40494e6a2fb4cb9438) @@ -40,6 +40,7 @@ import org.lamsfoundation.lams.learningdesign.Grouping; import org.lamsfoundation.lams.learningdesign.GroupingActivity; import org.lamsfoundation.lams.learningdesign.OptionsActivity; +import org.lamsfoundation.lams.learningdesign.OptionsWithSequencesActivity; import org.lamsfoundation.lams.learningdesign.ParallelActivity; import org.lamsfoundation.lams.learningdesign.PermissionGateActivity; import org.lamsfoundation.lams.learningdesign.ScheduleGateActivity; @@ -128,7 +129,7 @@ /** Maximum number of floating activities allow */ private Integer maxActivities; - + /** Minimum number of activities to be attempted */ private Integer minOptions; @@ -179,7 +180,7 @@ private Date gateStartDateTime; private Date gateEndDateTime; - + private Boolean gateActivityCompletionBased; private Boolean applyGrouping; @@ -238,12 +239,12 @@ * List of all the competence mappings for this activity, only applies to tool activities */ private ArrayList competenceMappingTitles; - + private PlannerActivityMetadataDTO plannerMetadataDTO; /** List of the UIIDs of the activities that are input activities for this activity */ private Integer toolActivityUIID; - + private ArrayList activityEvaluations; /** @@ -328,15 +329,17 @@ defaultActivityUIID = complex.getDefaultActivity().getActivityUIID(); } - if (activity.isOptionsActivity()) { + if (activity.isOptionsWithSequencesActivity()) { + addOptionsWithSequencesActivityAttributes((OptionsWithSequencesActivity) activity); + } else if (activity.isOptionsActivity()) { addOptionsActivityAttributes((OptionsActivity) activity); } else if (activity.isParallelActivity()) { addParallelActivityAttributes((ParallelActivity) activity); } else if (activity.isBranchingActivity()) { addBranchingActivityAttributes((BranchingActivity) activity); } else if (activity.isFloatingActivity()) { - addFloatingActivityAttributes((FloatingActivity) activity); - } else { + addFloatingActivityAttributes((FloatingActivity) activity); + } else { addSequenceActivityAttributes((SequenceActivity) activity, branchMappings); } @@ -358,6 +361,15 @@ optionsInstructions = optionsActivity.getOptionsInstructions(); } + private void addOptionsWithSequencesActivityAttributes(OptionsWithSequencesActivity optionsActivity) { + addOptionsActivityAttributes(optionsActivity); + + startXCoord = optionsActivity.getStartXcoord(); + startYCoord = optionsActivity.getStartYcoord(); + endXCoord = optionsActivity.getEndXcoord(); + endYCoord = optionsActivity.getEndYcoord(); + } + private void addParallelActivityAttributes(ParallelActivity activity) { } @@ -367,11 +379,11 @@ endXCoord = activity.getEndXcoord(); endYCoord = activity.getEndYcoord(); } - + private void addFloatingActivityAttributes(FloatingActivity floatingActivity) { - maxActivities = floatingActivity.getMaxNumberOfActivities(); + maxActivities = floatingActivity.getMaxNumberOfActivities(); } - + private void addSequenceActivityAttributes(SequenceActivity activity, ArrayList branchMappings) { @@ -411,7 +423,7 @@ competenceMappingTitles.add(competenceMappingTitle); } } - + activityEvaluations = new ArrayList(); if (toolActivity.getActivityEvaluations() != null) { for (ActivityEvaluation eval : toolActivity.getActivityEvaluations()) { @@ -569,11 +581,11 @@ } public Boolean getGateActivityCompletionBased() { - return gateActivityCompletionBased; + return gateActivityCompletionBased; } public void setGateActivityCompletionBased(Boolean gateActivityCompletionBased) { - this.gateActivityCompletionBased = gateActivityCompletionBased; + this.gateActivityCompletionBased = gateActivityCompletionBased; } /** @@ -631,7 +643,7 @@ public Integer getMaxActivities() { return maxActivities; } - + /** * @return Returns the maxOptions. */ @@ -827,7 +839,7 @@ ******************************************************************************************************************/ /** * @param activityCategoryID - * The activityCategoryID to set. + * The activityCategoryID to set. */ public void setActivityCategoryID(Integer activityCategoryID) { if (!activityCategoryID.equals(WDDXTAGS.NUMERIC_NULL_VALUE_INTEGER)) { @@ -837,7 +849,7 @@ /** * @param activityID - * The activityID to set. + * The activityID to set. */ public void setActivityID(Long activityId) { if (!activityId.equals(WDDXTAGS.NUMERIC_NULL_VALUE_LONG)) { @@ -847,7 +859,7 @@ /** * @param activityTypeID - * The activityTypeID to set. + * The activityTypeID to set. */ public void setActivityTypeID(Integer activityTypeId) { if (!activityTypeId.equals(WDDXTAGS.NUMERIC_NULL_VALUE_INTEGER)) { @@ -857,7 +869,7 @@ /** * @param activityUIID - * The activityUIID to set. + * The activityUIID to set. */ public void setActivityUIID(Integer activityUIID) { if (!activityUIID.equals(WDDXTAGS.NUMERIC_NULL_VALUE_INTEGER)) { @@ -867,7 +879,7 @@ /** * @param createDateTime - * The createDateTime to set. + * The createDateTime to set. */ public void setCreateDateTime(Date createDateTime) { if (!createDateTime.equals(WDDXTAGS.DATE_NULL_VALUE)) { @@ -877,7 +889,7 @@ /** * @param createGroupingID - * The createGroupingID to set. + * The createGroupingID to set. */ public void setCreateGroupingID(Long createGroupingID) { if (!createGroupingID.equals(WDDXTAGS.NUMERIC_NULL_VALUE_LONG)) { @@ -887,7 +899,7 @@ /** * @param createGroupingUIID - * The createGroupingUIID to set. + * The createGroupingUIID to set. */ public void setCreateGroupingUIID(Integer createGroupingUIID) { if (!createGroupingUIID.equals(WDDXTAGS.NUMERIC_NULL_VALUE_INTEGER)) { @@ -897,7 +909,7 @@ /** * @param description - * The description to set. + * The description to set. */ public void setDescription(String description) { if (!description.equals(WDDXTAGS.STRING_NULL_VALUE)) { @@ -907,7 +919,7 @@ /** * @param gateActivityLevelID - * The gateActivityLevelID to set. + * The gateActivityLevelID to set. */ public void setGateActivityLevelID(Integer gateActivityLevelID) { if (!gateActivityLevelID.equals(WDDXTAGS.NUMERIC_NULL_VALUE_INTEGER)) { @@ -917,7 +929,7 @@ /** * @param gateEndDateTime - * The gateEndDateTime to set. + * The gateEndDateTime to set. */ public void setGateEndDateTime(Date gateEndDateTime) { if (!gateEndDateTime.equals(WDDXTAGS.DATE_NULL_VALUE)) { @@ -927,7 +939,7 @@ /** * @param gateEndTimeOffset - * The gateEndTimeOffset to set. + * The gateEndTimeOffset to set. */ public void setGateEndTimeOffset(Long gateEndTimeOffset) { if (!gateEndTimeOffset.equals(WDDXTAGS.NUMERIC_NULL_VALUE_LONG)) { @@ -937,15 +949,15 @@ /** * @param gateOpen - * The gateOpen to set. + * The gateOpen to set. */ public void setGateOpen(Boolean gateOpen) { this.gateOpen = gateOpen; } /** * @param gateStartDateTime - * The gateStartDateTime to set. + * The gateStartDateTime to set. */ public void setGateStartDateTime(Date gateStartDateTime) { if (!gateStartDateTime.equals(WDDXTAGS.DATE_NULL_VALUE)) { @@ -955,7 +967,7 @@ /** * @param gateStartTimeOffset - * The gateStartTimeOffset to set. + * The gateStartTimeOffset to set. */ public void setGateStartTimeOffset(Long gateStartTimeOffset) { if (!gateStartTimeOffset.equals(WDDXTAGS.NUMERIC_NULL_VALUE_LONG)) { @@ -965,7 +977,7 @@ /** * @param groupingID - * The groupingID to set. + * The groupingID to set. */ public void setGroupingID(Long groupingID) { if (!WDDXTAGS.NUMERIC_NULL_VALUE_LONG.equals(groupingID)) { @@ -975,7 +987,7 @@ /** * @param groupingUIID - * The groupingUIID to set. + * The groupingUIID to set. */ public void setGroupingUIID(Integer groupingUIID) { if (!WDDXTAGS.NUMERIC_NULL_VALUE_LONG.equals(groupingUIID)) { @@ -985,7 +997,7 @@ /** * @param helpText - * The helpText to set. + * The helpText to set. */ public void setHelpText(String helpText) { if (!helpText.equals(WDDXTAGS.STRING_NULL_VALUE)) { @@ -995,7 +1007,7 @@ /** * @param learningDesignID - * The learningDesignID to set. + * The learningDesignID to set. */ public void setLearningDesignID(Long learningDesignID) { if (!learningDesignID.equals(WDDXTAGS.NUMERIC_NULL_VALUE_LONG)) { @@ -1005,7 +1017,7 @@ /** * @param learningLibraryID - * The learningLibraryID to set. + * The learningLibraryID to set. */ public void setLearningLibraryID(Long learningLibraryID) { if (!learningLibraryID.equals(WDDXTAGS.NUMERIC_NULL_VALUE_LONG)) { @@ -1015,7 +1027,7 @@ /** * @param libraryActivityID - * The libraryActivityID to set. + * The libraryActivityID to set. */ public void setLibraryActivityID(Long libraryActivityID) { if (!libraryActivityID.equals(WDDXTAGS.NUMERIC_NULL_VALUE_LONG)) { @@ -1025,7 +1037,7 @@ /** * @param libraryActivityUiImage - * The libraryActivityUiImage to set. + * The libraryActivityUiImage to set. */ public void setLibraryActivityUIImage(String libraryActivityUiImage) { if (!libraryActivityUiImage.equals(WDDXTAGS.STRING_NULL_VALUE)) { @@ -1035,17 +1047,17 @@ /** * @param maxActivities - * The maxActivities to set. + * The maxActivities to set. */ public void setMaxActivities(Integer maxActivities) { if (!maxActivities.equals(WDDXTAGS.NUMERIC_NULL_VALUE_INTEGER)) { this.maxActivities = maxActivities; } } - + /** * @param maxOptions - * The maxOptions to set. + * The maxOptions to set. */ public void setMaxOptions(Integer maxOptions) { if (!maxOptions.equals(WDDXTAGS.NUMERIC_NULL_VALUE_INTEGER)) { @@ -1055,7 +1067,7 @@ /** * @param minOptions - * The minOptions to set. + * The minOptions to set. */ public void setMinOptions(Integer minOptions) { if (!minOptions.equals(WDDXTAGS.NUMERIC_NULL_VALUE_INTEGER)) { @@ -1065,7 +1077,7 @@ /** * @param optionsInstructions - * The optionsInstructions to set. + * The optionsInstructions to set. */ public void setOptionsInstructions(String optionsInstructions) { if (!optionsInstructions.equals(WDDXTAGS.STRING_NULL_VALUE)) { @@ -1075,7 +1087,7 @@ /** * @param orderID - * The orderID to set. + * The orderID to set. */ public void setOrderID(Integer orderID) { if (!orderID.equals(WDDXTAGS.NUMERIC_NULL_VALUE_INTEGER)) { @@ -1085,7 +1097,7 @@ /** * @param parentActivityID - * The parentActivityID to set. + * The parentActivityID to set. */ public void setParentActivityID(Long parentActivityID) { if (!WDDXTAGS.NUMERIC_NULL_VALUE_LONG.equals(parentActivityID)) { @@ -1095,7 +1107,7 @@ /** * @param parentUIID - * The parentUIID to set. + * The parentUIID to set. */ public void setParentUIID(Integer parentUIID) { if (!parentUIID.equals(WDDXTAGS.NUMERIC_NULL_VALUE_INTEGER)) { @@ -1105,7 +1117,7 @@ /** * @param title - * The title to set. + * The title to set. */ public void setActivityTitle(String title) { if (!title.equals(WDDXTAGS.STRING_NULL_VALUE)) { @@ -1115,7 +1127,7 @@ /** * @param toolContentID - * The toolContentID to set. + * The toolContentID to set. */ public void setToolContentID(Long toolContentID) { if (!toolContentID.equals(WDDXTAGS.NUMERIC_NULL_VALUE_LONG)) { @@ -1125,7 +1137,7 @@ /** * @param toolID - * The toolID to set. + * The toolID to set. */ public void setToolID(Long toolID) { if (!toolID.equals(WDDXTAGS.NUMERIC_NULL_VALUE_LONG)) { @@ -1135,7 +1147,7 @@ /** * @param xcoord - * The xcoord to set. + * The xcoord to set. */ public void setxCoord(Integer xcoord) { if (!xcoord.equals(WDDXTAGS.NUMERIC_NULL_VALUE_INTEGER)) { @@ -1145,7 +1157,7 @@ /** * @param ycoord - * The ycoord to set. + * The ycoord to set. */ public void setyCoord(Integer ycoord) { if (!xCoord.equals(WDDXTAGS.NUMERIC_NULL_VALUE_INTEGER)) { @@ -1155,15 +1167,15 @@ /** * @param applyGrouping - * The applyGrouping to set. + * The applyGrouping to set. */ public void setApplyGrouping(Boolean applyGrouping) { this.applyGrouping = applyGrouping; } /** * @param groupingSupportType - * The groupingSupportType to set. + * The groupingSupportType to set. */ public void setGroupingSupportType(Integer groupingSupportType) { if (!groupingSupportType.equals(WDDXTAGS.NUMERIC_NULL_VALUE_INTEGER)) { @@ -1173,7 +1185,7 @@ /** * @param groupingType - * The groupingType to set. + * The groupingType to set. */ public void setGroupingType(Integer groupingType) { if (!groupingType.equals(WDDXTAGS.NUMERIC_NULL_VALUE_INTEGER)) { @@ -1184,7 +1196,7 @@ /** * * @param readOnly - * The readOnly to set. + * The readOnly to set. */ public void setReadOnly(Boolean readOnly) { if (!readOnly.equals(WDDXTAGS.BOOLEAN_NULL_VALUE)) { @@ -1315,18 +1327,18 @@ } public ArrayList getActivityEvaluations() { - return activityEvaluations; + return activityEvaluations; } public void setActivityEvaluations(ArrayList activityEvaluations) { - this.activityEvaluations = activityEvaluations; + this.activityEvaluations = activityEvaluations; } public PlannerActivityMetadataDTO getPlannerMetadataDTO() { - return plannerMetadataDTO; + return plannerMetadataDTO; } public void setPlannerMetadataDTO(PlannerActivityMetadataDTO plannerActivityMetadata) { - this.plannerMetadataDTO = plannerActivityMetadata; + this.plannerMetadataDTO = plannerActivityMetadata; } } \ No newline at end of file Index: lams_common/src/java/org/lamsfoundation/lams/learningdesign/service/ExportToolContentService.java =================================================================== diff -u -r260f167585ffb5b4db7b021294782607437aed4a -rfe06d16b234341fc965d9b40494e6a2fb4cb9438 --- lams_common/src/java/org/lamsfoundation/lams/learningdesign/service/ExportToolContentService.java (.../ExportToolContentService.java) (revision 260f167585ffb5b4db7b021294782607437aed4a) +++ lams_common/src/java/org/lamsfoundation/lams/learningdesign/service/ExportToolContentService.java (.../ExportToolContentService.java) (revision fe06d16b234341fc965d9b40494e6a2fb4cb9438) @@ -659,11 +659,17 @@ String destinationPath = FileUtil.getFullPath(contentDir, ExportToolContentService.SVG_IMAGE_FILE_NAME); String svgPath = service.createLearningDesignSVG(learningDesignId, SVGGenerator.OUTPUT_FORMAT_SVG_LAMS_COMMUNITY); - FileUtils.copyFile(new File(svgPath), new File(destinationPath)); + File svgFile = new File(svgPath); + if (svgFile.canRead()){ + FileUtils.copyFile(svgFile, new File(destinationPath)); + } destinationPath = FileUtil.getFullPath(contentDir, ExportToolContentService.PNG_IMAGE_FILE_NAME); String pngPath = service.createLearningDesignSVG(learningDesignId, SVGGenerator.OUTPUT_FORMAT_PNG); - FileUtils.copyFile(new File(pngPath), new File(destinationPath)); + File pngFile = new File(pngPath); + if (pngFile.canRead()){ + FileUtils.copyFile(pngFile, new File(destinationPath)); + } } log.debug("Learning design xml export success"); Index: lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/web/MonitoringAction.java =================================================================== diff -u -rbf965a1a2768bdec78ccb7b0ff8f7b694580e02c -rfe06d16b234341fc965d9b40494e6a2fb4cb9438 --- lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/web/MonitoringAction.java (.../MonitoringAction.java) (revision bf965a1a2768bdec78ccb7b0ff8f7b694580e02c) +++ lams_monitoring/src/java/org/lamsfoundation/lams/monitoring/web/MonitoringAction.java (.../MonitoringAction.java) (revision fe06d16b234341fc965d9b40494e6a2fb4cb9438) @@ -62,6 +62,7 @@ import org.lamsfoundation.lams.learningdesign.ContributionTypes; import org.lamsfoundation.lams.learningdesign.Group; import org.lamsfoundation.lams.learningdesign.LearningDesign; +import org.lamsfoundation.lams.learningdesign.OptionsWithSequencesActivity; import org.lamsfoundation.lams.learningdesign.SequenceActivity; import org.lamsfoundation.lams.learningdesign.exception.LearningDesignException; import org.lamsfoundation.lams.lesson.LearnerProgress; @@ -72,7 +73,6 @@ import org.lamsfoundation.lams.lesson.util.LearnerProgressNameComparator; import org.lamsfoundation.lams.monitoring.MonitoringConstants; import org.lamsfoundation.lams.monitoring.dto.ContributeActivityDTO; -import org.lamsfoundation.lams.monitoring.dto.ContributeActivityDTO.ContributeEntry; import org.lamsfoundation.lams.monitoring.service.IMonitoringService; import org.lamsfoundation.lams.monitoring.service.MonitoringServiceProxy; import org.lamsfoundation.lams.timezone.service.ITimezoneService; @@ -88,6 +88,7 @@ import org.lamsfoundation.lams.util.Configuration; import org.lamsfoundation.lams.util.ConfigurationKeys; import org.lamsfoundation.lams.util.DateUtil; +import org.lamsfoundation.lams.util.JsonUtil; import org.lamsfoundation.lams.util.MessageService; import org.lamsfoundation.lams.util.ValidationUtil; import org.lamsfoundation.lams.util.WebUtil; @@ -217,7 +218,7 @@ Boolean learnerRestart = WebUtil.readBooleanParam(request, "learnerRestart", false); Lesson newLesson = null; - if (copyType != null && copyType.equals(LearningDesign.COPY_TYPE_PREVIEW)) { + if ((copyType != null) && copyType.equals(LearningDesign.COPY_TYPE_PREVIEW)) { newLesson = monitoringService.initializeLessonForPreview(title, desc, ldId, getUserId(), customCSV, learnerPresenceAvailable, learnerImAvailable, liveEditEnabled); } else { @@ -293,7 +294,7 @@ if (!ValidationUtil.isOrgNameValid(lessonName)) { throw new IOException("Lesson name contains invalid characters"); } - + int organisationId = WebUtil.readIntParam(request, AttributeNames.PARAM_ORGANISATION_ID); long ldId = WebUtil.readLongParam(request, AttributeNames.PARAM_LEARNINGDESIGN_ID); @@ -835,7 +836,6 @@ .getServletContext()); monitoringService.checkOwnerOrStaffMember(user.getUserID(), lessonId, "monitor lesson"); - // should info box on Sequence tab be displayed? Short sequenceTabInfoShowCount = (Short) ss.getAttribute("sequenceTabInfoShowCount"); if (sequenceTabInfoShowCount == null) { @@ -996,7 +996,7 @@ Gson gson = new GsonBuilder().create(); responseJSON.put("contributeActivities", new JSONArray(gson.toJson(contributeActivities))); } - + response.setContentType("application/json;charset=utf-8"); response.getWriter().write(responseJSON.toString()); return null; @@ -1025,17 +1025,41 @@ Long activityId = activity.getActivityId(); JSONObject activityJSON = new JSONObject(); activityJSON.put("id", activityId); + activityJSON.put("title", activity.getTitle()); - if (activity.isBranchingActivity()) { - activityJSON.put("isBranching", true); + int activityType = activity.getActivityTypeId(); + activityJSON.put("type", activityType); + Activity parentActivity = activity.getParentActivity(); + if (activity.isBranchingActivity() && (((BranchingActivity) activity).getXcoord() == null)) { + // old branching is just a rectangle like Tool + // new branching has start and finish points, it's exploded + activityJSON.put("flaFormat", true); + activityJSON.put("x", ((BranchingActivity) activity).getStartXcoord()); + activityJSON.put("y", ((BranchingActivity) activity).getStartYcoord()); + } else if (activity.isOptionsWithSequencesActivity() + && (((OptionsWithSequencesActivity) activity).getXcoord() == null)) { + // old optional sequences is just a long rectangle + // new optional sequences has start and finish points, it's exploded + activityJSON.put("flaFormat", true); + activityJSON.put("x", ((OptionsWithSequencesActivity) activity).getStartXcoord()); + activityJSON.put("y", ((OptionsWithSequencesActivity) activity).getStartYcoord()); + } else if ((parentActivity != null) + && (Activity.OPTIONS_ACTIVITY_TYPE == parentActivity.getActivityTypeId())) { + // Optional Activity children had coordinates relative to parent + activityJSON.put("x", parentActivity.getXcoord() + activity.getXcoord()); + activityJSON.put("y", parentActivity.getYcoord() + activity.getYcoord()); } else { - String monitorUrl = monitoringService.getActivityMonitorURL(lessonId, activityId, contentFolderId, - monitorUserId); - if (monitorUrl != null) { - // whole activity monitor URL - activityJSON.put("url", monitorUrl); - } + activityJSON.put("x", activity.getXcoord()); + activityJSON.put("y", activity.getYcoord()); } + + String monitorUrl = monitoringService.getActivityMonitorURL(lessonId, activityId, contentFolderId, + monitorUserId); + if (monitorUrl != null) { + // whole activity monitor URL + activityJSON.put("url", monitorUrl); + } + activitiesMap.put(activityId, activityJSON); } } @@ -1053,15 +1077,21 @@ && ((branchingActivityId == null) || MonitoringAction.isBranchingChild(branchingActivityId, currentActivity))) { JSONObject learnerJSON = WebUtil.userToJSON(learner); - Long currentActivityId = currentActivity.getActivityId(); + // assign learners to child activity or parent branching/options with sequences? Activity parentActivity = currentActivity.getParentActivity(); - Long targetActivityId = (branchingActivityId != null) || (parentActivity == null) + Long targetActivityId = (branchingActivityId != null) + || (parentActivity == null) || (parentActivity.getParentActivity() == null) - || !parentActivity.getParentActivity().isBranchingActivity() ? currentActivity + || !(parentActivity.getParentActivity().isBranchingActivity() || parentActivity + .getParentActivity().isOptionsWithSequencesActivity()) ? currentActivity .getActivityId() : parentActivity.getParentActivity().getActivityId(); JSONObject targetActivityJSON = activitiesMap.get(targetActivityId); + if (Boolean.TRUE.equals(JsonUtil.opt(targetActivityJSON, "flaFormat"))) { + // for new format, we always set learners to child activity, not parent + targetActivityJSON = activitiesMap.get(currentActivity.getActivityId()); + } targetActivityJSON.append("learners", learnerJSON); } } Index: lams_monitoring/web/includes/javascript/monitorLesson.js =================================================================== diff -u -r85c9bb1cef2a5b0fe0b561d60ecc599280eff310 -rfe06d16b234341fc965d9b40494e6a2fb4cb9438 --- lams_monitoring/web/includes/javascript/monitorLesson.js (.../monitorLesson.js) (revision 85c9bb1cef2a5b0fe0b561d60ecc599280eff310) +++ lams_monitoring/web/includes/javascript/monitorLesson.js (.../monitorLesson.js) (revision fe06d16b234341fc965d9b40494e6a2fb4cb9438) @@ -816,7 +816,13 @@ $.each(response.activities, function(activityIndex, activity){ addActivityIconsHandlers(activity); - if (activity.url || activity.isBranching) { + if (activity.url || (activity.isBranching && !activity.flaFormat)) { + // find the activity in SVG + var coord = getActivityCoordinates(activity); + if (!coord || !coord.elem) { + return; + } + var dblClickFunction = // different behaviour for regular/branching activities activity.isBranching ? @@ -827,19 +833,17 @@ openPopUp(LAMS_URL + activity.url, "MonitorActivity", 720, 900, true, true); }; // find activity group, if it is not hidden - $('g#' + activity.id, sequenceCanvas) - .css('cursor', 'pointer') - .dblclick(dblClickFunction) - // double tap detection on mobile devices - .tap(function(event){ - var currentTime = new Date().getTime(), - tapLength = currentTime - lastTap; - if (tapLength < tapTimeout && tapLength > 0) { - event.preventDefault(); - dblClickFunction(); - } - lastTap = currentTime; - }); + coord.elem.css('cursor', 'pointer') + // double tap detection on mobile devices; it works also for click + .tap(function(event){ + var currentTime = new Date().getTime(), + tapLength = currentTime - lastTap; + if (tapLength < tapTimeout && tapLength > 0) { + event.preventDefault(); + dblClickFunction(); + } + lastTap = currentTime; + }); } }); @@ -969,88 +973,83 @@ if (!activity.learners && !activity.requiresAttention) { return; } - var isGate = false, - actX = null, - actY = null, - activityGroup = $('g#' + activity.id, sequenceCanvas), - activityShape = $('rect[id="act' + activity.id + '"]', activityGroup); - if (activityShape.length == 0){ - // is it Gate activity? - activityShape = $('polygon', activityGroup); - if (activityShape.length > 0){ - isGate = true; - var polygonPoints = activityShape.attr('points').split(' '); - var polygonStartPoints = polygonPoints[4].split(','); - actX = +polygonStartPoints[0]; - actY = +polygonStartPoints[1] - 10; - } else { - // unknown or invisible shape (System Gate?) - return; - } - } else { - actX = +activityShape.attr('x') + 1; - actY = +activityShape.attr('y') + 1; + + // fint the activity in SVG + var coord = getActivityCoordinates(activity); + if (!coord) { + return; } // add group of users icon - var actRightBorder = actX + (isGate? 40 : +activityShape.attr('width')), - actBottomBorder = actY + (isGate? 50 : +activityShape.attr('height')); + var activityGroup = $('g#' + activity.id, sequenceCanvas), + // in old SVG format, add to a group; in new, go straight for the SVG root element + appendTarget = (activityGroup.length > 0 ? activityGroup : $('svg', sequenceCanvas))[0], + // branching and gates require extra adjustments + isNewBranching = [10,11,12,13].indexOf(activity.type) > -1 && activity.flaFormat, + isGate = [3,4,5,14].indexOf(activity.type) > -1; + if (activity.learners){ var groupTitle = activity.learners.length + ' ' + LABELS.LEARNER_GROUP_COUNT + ' ' + LABELS.LEARNER_GROUP_SHOW, // if icons do not fit in shape anymore, show a group icon element = appendXMLElement('image', { 'id' : 'act' + activity.id + 'learnerGroup', - 'x' : actRightBorder - 19, - 'y' : actY + 1, + 'x' : isNewBranching ? coord.x + 2 : (isGate ? coord.x + 10 : coord.x2 - 18), + 'y' : isNewBranching ? coord.y - 12 : coord.y + 1, 'height' : 16, 'width' : 16, - 'xlink:href' : LAMS_URL + 'images/icons/group.png' - }, null, activityGroup[0]); + 'xlink:href' : LAMS_URL + 'images/icons/group.png', + 'style' : 'cursor : pointer' + }, null, appendTarget); appendXMLElement('title', null, groupTitle, element); // add a small number telling how many learners are in the group element = appendXMLElement('text', { 'id' : 'act' + activity.id + 'learnerGroupText', - 'x' : actRightBorder - 10, - 'y' : actY + 24, + 'x' : isNewBranching ? coord.x + 9 : (isGate ? coord.x + 17 : coord.x2 - 9), + 'y' : isNewBranching ? coord.y + 12 : coord.y + 25, 'text-anchor': 'middle', 'font-family': 'Verdana', - 'font-size' : 8 - }, activity.learners.length, activityGroup[0]); + 'font-size' : 8, + 'style' : 'cursor : pointer' + }, activity.learners.length, appendTarget); appendXMLElement('title', null, groupTitle, element); var actTooltip = LABELS.LEARNER_GROUP_LIST_TITLE; - // draw single user icons for the first few - if (!isGate) { + // draw single icons for the first few learners; + // don't do it for gate and optional activities, and new branching/optional sequences format + if ([3,4,5,7,13,14].indexOf(activity.type) == -1 && !activity.flaFormat) { $.each(activity.learners, function(learnerIndex, learner){ var learnerDisplayName = getLearnerDisplayName(learner); actTooltip += '\n' + learnerDisplayName; if (learnerIndex < 7) { element = appendXMLElement('image', { 'id' : 'act' + activity.id + 'learner' + learner.id, - 'x' : actX + learnerIndex*15, - 'y' : actY, + 'x' : coord.x + learnerIndex*15 + 1, + // a bit lower for Optional Activity + 'y' : coord.y, 'height' : 16, 'width' : 16, - 'xlink:href' : LAMS_URL + 'images/icons/user.png' - }, null, activityGroup[0]); + 'xlink:href' : LAMS_URL + 'images/icons/user.png', + 'style' : 'cursor : pointer' + }, null, appendTarget); appendXMLElement('title', null, learnerDisplayName, element); } }); } - appendXMLElement('title', null, actTooltip, activityGroup[0]); + appendXMLElement('title', null, actTooltip, appendTarget); } if (activity.requiresAttention) { var element = appendXMLElement('image', { 'id' : 'act' + activity.id + 'attention', - 'x' : actRightBorder - 19, - 'y' : actBottomBorder - 19, + 'x' : isNewBranching ? coord.x + 14 : coord.x2 - 19, + 'y' : isNewBranching ? coord.y + 6 : coord.y2 - 19, 'height' : 16, 'width' : 16, - 'xlink:href' : LAMS_URL + 'images/icons/exclamation.png' - }, null, activityGroup[0]); + 'xlink:href' : LAMS_URL + 'images/icons/exclamation.png', + 'style' : 'cursor : pointer' + }, null, appendTarget); appendXMLElement('title', null, LABELS.CONTRIBUTE_ATTENTION, element); } } @@ -1063,18 +1062,13 @@ if (!activity.learners && !activity.requiresAttention) { return; } - - var activityGroup = $('g#' + activity.id, sequenceCanvas); - if (activityGroup.length == 0) { - // the activity is probably hidden (branching child, system gate) - return; - } + // gate activity does not allows users' view - var usersViewable = $('polygon', activityGroup).length == 0; + var usersViewable = [3,4,5,14].indexOf(activity.type) == -1; if (activity.learners){ $.each(activity.learners, function(learnerIndex, learner){ - var learnerIcon = $('image[id="act' + activity.id + 'learner' + learner.id + '"]', activityGroup) + var learnerIcon = $('image[id="act' + activity.id + 'learner' + learner.id + '"]', sequenceCanvas) .css('cursor', 'pointer') // drag learners to force complete activities .draggable({ @@ -1109,21 +1103,15 @@ }); - var learnerGroupIcon = $('*[id^="act' + activity.id + 'learnerGroup"]', activityGroup); - // 0 is for no group icon, 2 is for icon + digits - if (learnerGroupIcon.length == 2) { - var activityName = $('text[id^="TextElement"]', activityGroup).text(); - learnerGroupIcon.dblclick(function(event){ - // double click on learner icon to see activity from his perspective - event.stopPropagation(); - showLearnerGroupDialog(activity.id, activityName, activity.learners, true, usersViewable); - }); - } + $('*[id^="act' + activity.id + 'learnerGroup"]', sequenceCanvas).dblclick(function(event){ + // double click on learner group icon to see list of learners + event.stopPropagation(); + showLearnerGroupDialog(activity.id, activity.title, activity.learners, true, usersViewable); + }); } if (activity.requiresAttention){ - var attentionIcon = $('*[id^="act' + activity.id + 'attention"]', activityGroup); - attentionIcon.click(function(event){ + $('*[id^="act' + activity.id + 'attention"]', sequenceCanvas).click(function(event){ event.stopPropagation(); // switch to first tab where attention prompts are listed $('#tabs').tabs('select', 0); @@ -1192,6 +1180,67 @@ /** + * Extracts activity using SVG attributes. + */ +function getActivityCoordinates(activity){ + // special processing for gates + if ([3,4,5,14].indexOf(activity.type) > -1) { + return { + 'x' : activity.x, + 'y' : activity.y - 18, + 'x2' : activity.x + 39, + 'y2' : activity.y + 40 + } + } + + // special processing for new format of branching and optional sequences + if ([10,11,12,13].indexOf(activity.type) > -1 && activity.flaFormat) { + return { + 'x' : activity.x, + 'y' : activity.y + } + } + + // get either rectangle from old Batik SVG format + // or path from new Flashless Authoring format (IE and other browsers format paths differently) + var elem = $('rect[x="' + activity.x + '.0"][y="' + activity.y + '.0"], ' + + 'rect[x="' + activity.x + '"][y="' + activity.y + '"], ' + + 'path[d^="M' + activity.x + ',' + activity.y +'"], ' + + 'path[d^="M ' + activity.x + ' ' + activity.y +'"]', + sequenceCanvas); + if (elem.length == 0) { + return; + } + + // if it's a rectangle, it has these attributes + var width = elem.attr('width'), + height = elem.attr('height'); + if (width) { + return { + 'elem' : elem, + 'x' : activity.x, + 'y' : activity.y, + 'x2' : activity.x + +width, + 'y2' : activity.y + +height + } + } else { + // extract width and height from path M,HV... or M H V ... + var match = /H\s?(\d+)\s?V\s?(\d+)/i.exec(elem.attr('d')); + if (match) { + return { + 'elem' : elem, + 'x' : activity.x, + 'y' : activity.y + 1, + 'x2' : +match[1], + 'y2' : +match[2] + } + } + } + +} + + +/** * Shows Edit Class dialog for class manipulation. */ function showClassDialog(){