Index: lams_build/lib/lams/lams.jar =================================================================== diff -u -ra623f7ff1c6789bed2bf4500d23af7c30cdf386c -r260f167585ffb5b4db7b021294782607437aed4a Binary files differ Index: lams_central/src/java/org/lamsfoundation/lams/authoring/service/AuthoringService.java =================================================================== diff -u -r035853516626933d59e2473b4410b1dc54bb023e -r260f167585ffb5b4db7b021294782607437aed4a --- lams_central/src/java/org/lamsfoundation/lams/authoring/service/AuthoringService.java (.../AuthoringService.java) (revision 035853516626933d59e2473b4410b1dc54bb023e) +++ lams_central/src/java/org/lamsfoundation/lams/authoring/service/AuthoringService.java (.../AuthoringService.java) (revision 260f167585ffb5b4db7b021294782607437aed4a) @@ -2029,6 +2029,7 @@ for (LearningDesignAccess access : accessList) { LearningDesign learningDesign = learningDesignDAO.getLearningDesignById(access.getLearningDesignId()); access.setTitle(learningDesign.getTitle()); + access.setWorkspaceFolderId(learningDesign.getWorkspaceFolder().getWorkspaceFolderId()); } return accessList; } Index: lams_central/src/java/org/lamsfoundation/lams/authoring/web/AuthoringAction.java =================================================================== diff -u -r035853516626933d59e2473b4410b1dc54bb023e -r260f167585ffb5b4db7b021294782607437aed4a --- lams_central/src/java/org/lamsfoundation/lams/authoring/web/AuthoringAction.java (.../AuthoringAction.java) (revision 035853516626933d59e2473b4410b1dc54bb023e) +++ lams_central/src/java/org/lamsfoundation/lams/authoring/web/AuthoringAction.java (.../AuthoringAction.java) (revision 260f167585ffb5b4db7b021294782607437aed4a) @@ -46,6 +46,7 @@ import org.lamsfoundation.lams.authoring.ObjectExtractorException; import org.lamsfoundation.lams.authoring.service.IAuthoringService; import org.lamsfoundation.lams.learningdesign.LearningDesign; +import org.lamsfoundation.lams.learningdesign.LearningDesignAccess; import org.lamsfoundation.lams.learningdesign.dto.LearningDesignDTO; import org.lamsfoundation.lams.learningdesign.dto.LicenseDTO; import org.lamsfoundation.lams.learningdesign.dto.ValidationErrorDTO; @@ -95,6 +96,8 @@ private static IAuthoringService authoringService; private static ILearningDesignService learningDesignService; + private static int LEARNING_DESIGN_ACCESS_ENTRIES_LIMIT = 7; + private Integer getUserId() { HttpSession ss = SessionManager.getSession(); UserDTO user = (UserDTO) ss.getAttribute(AttributeNames.USER); @@ -112,9 +115,11 @@ request.setAttribute("tools", getLearningDesignService().getToolDTOs(true, request.getRemoteUser())); request.setAttribute(AttributeNames.PARAM_CONTENT_FOLDER_ID, FileUtil.generateUniqueContentFolderID()); + List accessList = getAuthoringService().getLearningDesignAccessByUser(getUserId()); + accessList = accessList.subList(0, + Math.min(accessList.size(), AuthoringAction.LEARNING_DESIGN_ACCESS_ENTRIES_LIMIT - 1)); Gson gson = new GsonBuilder().create(); - String access = gson.toJson(getAuthoringService().getLearningDesignAccessByUser(getUserId())); - request.setAttribute("access", access); + request.setAttribute("access", gson.toJson(accessList)); return mapping.findForward("openAutoring"); } @@ -186,7 +191,12 @@ JSONObject responseJSON = new JSONObject(); Gson gson = new GsonBuilder().create(); responseJSON.put("ld", new JSONObject(gson.toJson(learningDesignDTO))); - responseJSON.put("access", new JSONArray(gson.toJson(getAuthoringService().getLearningDesignAccessByUser(userId)))); + + List accessList = getAuthoringService().getLearningDesignAccessByUser(userId); + accessList = accessList.subList(0, + Math.min(accessList.size(), AuthoringAction.LEARNING_DESIGN_ACCESS_ENTRIES_LIMIT - 1)); + responseJSON.put("access", new JSONArray(gson.toJson(accessList))); + response.getWriter().write(responseJSON.toString()); return null; } @@ -385,7 +395,7 @@ } return null; } - + /** * Creates a LD with the given activity and starts a lesson with default class and settings. */ @@ -478,7 +488,11 @@ Integer userId = getUserId(); getAuthoringService().storeLearningDesignAccess(learningDesignID, userId); - responseJSON.put("access", new JSONArray(gson.toJson(getAuthoringService().getLearningDesignAccessByUser(userId)))); + + List accessList = getAuthoringService().getLearningDesignAccessByUser(userId); + accessList = accessList.subList(0, + Math.min(accessList.size(), AuthoringAction.LEARNING_DESIGN_ACCESS_ENTRIES_LIMIT - 1)); + responseJSON.put("access", new JSONArray(gson.toJson(accessList))); } } Index: lams_central/web/author2.jsp =================================================================== diff -u -r035853516626933d59e2473b4410b1dc54bb023e -r260f167585ffb5b4db7b021294782607437aed4a --- lams_central/web/author2.jsp (.../author2.jsp) (revision 035853516626933d59e2473b4410b1dc54bb023e) +++ lams_central/web/author2.jsp (.../author2.jsp) (revision 260f167585ffb5b4db7b021294782607437aed4a) @@ -139,6 +139,11 @@ learningLibraryId="${tool.learningLibraryId}" supportsOutputs="${tool.supportsOutputs}" activityCategoryId="${tool.activityCategoryID}" + childToolIds=" + + ${childId}, + + " class="template"> @@ -197,7 +202,7 @@ <%-- This will be moved to dialog's button pane --%>
- Title: + Title:
Index: lams_central/web/css/authoring.css =================================================================== diff -u -r035853516626933d59e2473b4410b1dc54bb023e -r260f167585ffb5b4db7b021294782607437aed4a --- lams_central/web/css/authoring.css (.../authoring.css) (revision 035853516626933d59e2473b4410b1dc54bb023e) +++ lams_central/web/css/authoring.css (.../authoring.css) (revision 260f167585ffb5b4db7b021294782607437aed4a) @@ -94,11 +94,15 @@ } div#ldStoreDialog #ldStoreDialogAccessCell > div.access { - padding-top: 5px; + padding: 3px 0 3px 3px; cursor: pointer; } +div#ldStoreDialog #ldStoreDialogAccessCell > div.selected { + background-color: #dfeffc; +} + div#ldStoreDialog td#ldStoreDialogCanvasCell { text-align: center; padding: 10px 0px 0px 10px; @@ -195,17 +199,20 @@ } div#toolbar .split-ui-button + ul { - padding: 0 5px 5px 5px; font-size: 11px; color: #2E6E9E; z-index: 1100; } div#toolbar .split-ui-button + ul li { - padding-top: 5px; + padding: 3px 5px; cursor: pointer; } +div#toolbar .split-ui-button + ul li:hover { + background-color: #dfeffc; +} + table#authoringTable { table-layout: fixed; width: 100%; Index: lams_central/web/includes/javascript/authoring/authoringActivity.js =================================================================== diff -u -r035853516626933d59e2473b4410b1dc54bb023e -r260f167585ffb5b4db7b021294782607437aed4a --- lams_central/web/includes/javascript/authoring/authoringActivity.js (.../authoringActivity.js) (revision 035853516626933d59e2473b4410b1dc54bb023e) +++ lams_central/web/includes/javascript/authoring/authoringActivity.js (.../authoringActivity.js) (revision 260f167585ffb5b4db7b021294782607437aed4a) @@ -578,6 +578,7 @@ if (layout.items.copiedActivity = activity) { layout.items.copiedActivity = null; } + if (activity instanceof ActivityLib.GroupingActivity) { $.each(layout.activities, function(){ if (activity == this.grouping) { @@ -706,6 +707,33 @@ branches.splice(branches.indexOf(transition.branch), 1); } + // remove grouping references if chain was broken by the removed transition + $.each(layout.activities, function(){ + if (this.grouping) { + var candidate = this, + groupingFound = false; + do { + if (candidate.transitions && candidate.transitions.to.length > 0) { + candidate = candidate.transitions.to[0].fromActivity; + } else if (candidate.parentActivity) { + candidate = candidate.parentActivity; + } else { + candidate = null; + } + + if (this.grouping == candidate) { + groupingFound = true; + candidate = null; + } + } while (candidate != null); + } + + if (!groupingFound) { + this.grouping = null; + this.draw(); + } + }); + transition.items.remove(); setModified(true); }, Index: lams_central/web/includes/javascript/authoring/authoringGeneral.js =================================================================== diff -u -r6f1d9060e228ef70caffe407480da9e857f05ca0 -r260f167585ffb5b4db7b021294782607437aed4a --- lams_central/web/includes/javascript/authoring/authoringGeneral.js (.../authoringGeneral.js) (revision 6f1d9060e228ef70caffe407480da9e857f05ca0) +++ lams_central/web/includes/javascript/authoring/authoringGeneral.js (.../authoringGeneral.js) (revision 260f167585ffb5b4db7b021294782607437aed4a) @@ -73,8 +73,7 @@ 'FFF8DC', 'FF8C00', '00BFFF', 'DCDCDC', 'ADD8E6', '20B2AA', 'B0C4DE', 'FFE4E1', 'FF4500', 'EE82EE'], 'optionalActivity' : 'rgb(194,213,254)' - }, - maxAccessEntries : 7 + } }; @@ -114,24 +113,18 @@ parallelChildActivities = null; if (activityCategoryID == 5) { - // mark which HTML templates construct this parallel activity - switch(learningLibraryID){ - case 28: - // share resources and forum - parallelChildActivities = $('.template[learningLibraryId=12]') - .add($('.template[learningLibraryId=6]')); - break; - case 29: - // chat and scribe - parallelChildActivities = $('.template[learningLibraryId=3]') - .add($('.template[learningLibraryId=20]')); - break; - case 30: - // forum and scribe - parallelChildActivities = $('.template[learningLibraryId=6]') - .add($('.template[learningLibraryId=20]')); - break; - } + var childToolIds = $(this).attr('childToolIds').split(','); + $.each(childToolIds, function(){ + var childToolId = this.trim(); + if (childToolId) { + parallelChildActivity = $('.template[toolId=' + childToolId + ']'); + if (parallelChildActivities) { + parallelChildActivities = parallelChildActivities.add(parallelChildActivity); + } else { + parallelChildActivities = parallelChildActivity; + } + } + }); } // register tool properties so they are later easily accessible @@ -264,15 +257,21 @@ 'click' : function() { var dialog = $(this), tree = dialog.dialog('option', 'ldTree'), - ldNode = tree.getHighlightedNode(); + ldNode = tree.getHighlightedNode(), + learningDesignID = ldNode ? ldNode.data.learningDesignId : null; + + if (!learningDesignID) { + learningDesignID = +$('#ldStoreDialogAccessCell > div.selected').attr('learningDesignId'); + } + // no LD was chosen - if (!ldNode || !ldNode.data.learningDesignId) { + if (!learningDesignID) { alert("Please choose a sequence"); return; } dialog.dialog('close'); - openLearningDesign(ldNode.data.learningDesignId); + openLearningDesign(learningDesignID); } } ], @@ -295,40 +294,74 @@ return; } - var tree = dialog.dialog('option', 'ldTree'), + var learningDesignID = null, + folderNode = null, + folderID = null, + tree = dialog.dialog('option', 'ldTree'), node = tree.getHighlightedNode(); - if (!node) { + if (node) { + // get folder from LD tree + folderNode = node.data.learningDesignId ? node.parent : node; + folderID = folderNode.data.folderID; + } else { + // get data from "recently used sequences" list + var selectedAccess = $('#ldStoreDialogAccessCell > div.selected'); + // if title was altered, do not consider this an overwrite + if (selectedAccess.length > 0 && title == selectedAccess.text()) { + learningDesignID = +selectedAccess.attr('learningDesignId'); + folderID = +selectedAccess.attr('folderID'); + + var folders = tree.getRoot().children; + if (folders) { + $.each(folders, function(){ + if (folderID == this.data.folderID) { + this.highlight(); + folderNode = this; + return false; + } + }); + } + } + } + + if (!folderID) { // although an existing sequence can be highlighted alert('Please choose a folder'); return; } - var nodeTitle = $(node.getContentHtml()).text(), - // if a node is highlighted but user modified the title, - // it is considered a new sequence - learningDesingID = node.data.learningDesignId && nodeTitle == title ? - node.data.learningDesignId : null; - if (learningDesingID + // if a node is highlighted but user modified the title, + // it is considered a new sequence + // otherwise check if there is no other sequence with the same name + if (folderNode && folderNode.children) { + $.each(folderNode.children, function(){ + var nodeTitle = $(this.getContentHtml()).text(); + if (nodeTitle == title) { + this.highlight(); + learningDesignID = this.data.learningDesignId; + return false; + } + }); + } + if (learningDesignID && !confirm('Are you sure you want to overwrite the existing sequence?')) { return; } - - var folderID = node.data.folderID; - if (!folderID) { - folderID = node.parent.data.folderID; - } - var result = saveLearningDesign(folderID, learningDesingID, title); + var result = saveLearningDesign(folderID, learningDesignID, title); if (result) { dialog.dialog('close'); } } } ], 'open' : function(){ + showLearningDesignThumbnail(); + var nameContainer = $('#ldStoreDialogNameContainer'); $('input', nameContainer).val(null); $(this).siblings('.ui-dialog-buttonpane').append(nameContainer); + $('#ldStoreDialogNameField', nameContainer).focus(); } }); @@ -348,10 +381,8 @@ ldStoreDialog.dialog('option', 'ldTree', tree); // make folder contents load dynamically on open tree.setDynamicLoad(function(node, callback){ - var dialog = $(this.getEl()).closest('.ui-dialog'), - isSaveDialog = dialog.hasClass('ldStoreDialogSave'); // load subfolder contents - var childNodeData = MenuLib.getFolderContents(node.data.folderID, isSaveDialog); + var childNodeData = MenuLib.getFolderContents(node.data.folderID); if (childNodeData) { $.each(childNodeData, function(){ // create and add a leaf @@ -366,30 +397,16 @@ tree.subscribe('clickEvent', function(event){ var dialog = $(this.getEl()).closest('.ui-dialog'), isSaveDialog = dialog.hasClass('ldStoreDialogSave'); - + if (!isSaveDialog && !event.node.data.learningDesignId){ // it is a folder in load sequence dialog, do not highlight return false; } - // display "loading" animation and finally LD thumbnail - $('.ldChoiceDependentCanvasElement', dialog).css('display', 'none'); - if (event.node.highlightState == 0) { - if (event.node.data.learningDesignId) { - $('#ldStoreDialog #ldScreenshotLoading', dialog).css('display', 'inline'); - // get the image of the chosen LD and prevent caching - $('#ldStoreDialog #ldScreenshotAuthor', dialog) - .attr('src', LD_THUMBNAIL_URL_BASE + event.node.data.learningDesignId + '&_=' + new Date().getTime()); - $('#ldStoreDialog #ldScreenshotAuthor', dialog).css({ - 'width' : 'auto', - 'height' : 'auto' - }); - if (isSaveDialog) { - // copy title of the highligthed sequence to title field - var title = $(event.node.getContentHtml()).text(); - $('#ldStoreDialogNameField', dialog).val(title); - } - } - } + + var learningDesignID = event.node.highlightState == 0 ? +event.node.data.learningDesignId : null, + title = isSaveDialog && learningDesignID ? $(event.node.getContentHtml()).text() : null; + + showLearningDesignThumbnail(learningDesignID, title); }); tree.subscribe('clickEvent', tree.onEventToggleHighlight); @@ -399,8 +416,7 @@ layout.items.infoDialog = $('
').attr('id', 'infoDialog').dialog({ 'autoOpen' : false, 'width' : 290, - 'height' : 35, - 'resizable' : false, + 'minHeight' : 'auto', 'show' : 'fold', 'hide' : 'fold', 'draggable' : false, @@ -515,6 +531,11 @@ }); }); + // sort groups by asceding UIID + groups.sort(function(a,b) { + return a.uiid - b.uiid; + }); + activity = new ActivityLib.GroupingActivity( activityData.activityID, activityData.activityUIID, @@ -606,11 +627,18 @@ case 8: var branches = branchToBranching[activityData.parentActivityID]; if (!branches) { - branches = branchToBranching[activityData.parentActivityID] = []; + branches = branchToBranching[activityData.parentActivityID] = []; } branches.push(new ActivityLib.BranchActivity(activityData.activityID, activityData.activityUIID, activityData.activityTitle)); + + var branchData = branchToActivities[activityData.activityID]; + if (!branchData) { + branchData = branchToActivities[activityData.activityID] = {}; + } + branchData.stopAfterActivity = activityData.stopAfterActivity; + break; // Support (Floating) activity @@ -637,7 +665,7 @@ if (activityData.parentActivityID) { var branchData = branchToActivities[activityData.parentActivityID]; if (branchData) { - if (activityData.orderID > branchData.lastActivityOrderID) { + if (!branchData.lastActivityOrderID || activityData.orderID > branchData.lastActivityOrderID) { // is it the last activity in the branch? branchData.lastActivityOrderID = activityData.orderID; branchData.lastActivity = activity; @@ -791,7 +819,7 @@ ActivityLib.addTransition(branchingActivity.start, branchData ? branchData.firstActivity : branchingActivity.end, true, null, null, branch); - if (branchData) { + if (branchData && !branchData.stopAfterActivity) { ActivityLib.addTransition(branchData.lastActivity, branchingActivity.end, true); } }); @@ -847,6 +875,15 @@ setModified(false); updateAccess(response.access); + + if (!ld.validDesign) { + var dialog = layout.items.infoDialog.html('The sequence is not valid.
It needs to be corrected before it can be used in lessons.'); + dialog.dialog('open'); + + setTimeout(function(){ + dialog.text('').dialog('close'); + }, 5000); + } } }); } @@ -889,6 +926,7 @@ this.defaultActivityUIID = null; this.orderID = branchOrderID + 1; this.parentActivity = branchingActivity; + this.stopAfterActivity = false; layoutActivities.push(this); var childActivity = this.transitionFrom.toActivity, @@ -903,8 +941,7 @@ orderID++; if (childActivity.transitions.from.length == 0) { - // we need to carry on to assign parent to all remaining child activities - error = 'One of branches does not have a transition to the end point'; + this.stopAfterActivity = true; break; } childActivity = childActivity.transitions.from[0].toActivity; @@ -916,11 +953,6 @@ } }); - if (error) { - alert(error); - return false; - } - if (layout.floatingActivity){ layoutActivities.push(layout.floatingActivity); } @@ -989,7 +1021,7 @@ switch(activity.gateType) { case 'sync' : activityTypeID = 3; break; case 'schedule' : activityTypeID = 4; break; - case 'permision' : activityTypeID = 5; break; + case 'permission' : activityTypeID = 5; break; case 'condition' : activityTypeID = 14; break; } } else if (activity instanceof ActivityLib.ParallelActivity) { @@ -1058,6 +1090,7 @@ 'gateActivityCompletionBased' : activity.gateActivityCompletionBased, 'minOptions' : activity.minOptions, 'maxOptions' : activity.maxOptions, + 'stopAfterActivity' : activity.stopAfterActivity ? true : false, 'gradebookToolOutputDefinitionName' : null, 'helpText' : null, @@ -1250,12 +1283,13 @@ }); if (response.validation.length == 0) { - setModified(false); alert('Congratulations! Your design is valid and has been saved.'); - result = true; } + + result = true; + setModified(false); } - + updateAccess(response.access); }, error : function(){ @@ -1354,13 +1388,63 @@ function updateAccess(access){ var accessCell = $('#ldStoreDialogAccessCell'); accessCell.children('div.access').remove(); - $.each(access, function(index){ - if (index >= layout.maxAccessEntries) { - return false; - } + $.each(access, function(){ $('
').addClass('access') - .attr('learningDesignId', this.learningDesignId) + .attr({ + 'learningDesignId' : this.learningDesignId, + 'folderID' : this.workspaceFolderId + }) .text(this.title) - .appendTo(accessCell); + .appendTo(accessCell) + .click(function(){ + var accessEntry = $(this); + if (accessEntry.hasClass('selected')) { + return; + } + + var dialog = accessEntry.closest('.ui-dialog'), + isSaveDialog = dialog.hasClass('ldStoreDialogSave'), + learningDesignID = +accessEntry.attr('learningDesignId'), + title = isSaveDialog ? accessEntry.text() : null; + + showLearningDesignThumbnail(learningDesignID, title); + }); }); +} + + +function showLearningDesignThumbnail(learningDesignID, title) { + // display "loading" animation and finally LD thumbnail + $('.ldChoiceDependentCanvasElement').css('display', 'none'); + if (learningDesignID) { + var dialogContent = $('#ldStoreDialog'); + $('#ldScreenshotLoading', dialogContent).css('display', 'inline'); + // get the image of the chosen LD and prevent caching + $('#ldScreenshotAuthor', dialogContent) + .attr('src', LD_THUMBNAIL_URL_BASE + learningDesignID + '&_=' + new Date().getTime()) + .css({ + 'width' : 'auto', + 'height' : 'auto' + }); + if (title) { + // copy title of the highligthed sequence to title field + $('#ldStoreDialogNameField').val(title).focus(); + } + + var tree = $('#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(){ + var access = $(this); + if (+access.attr('learningDesignId') == learningDesignID){ + access.addClass('selected'); + } else { + access.removeClass('selected'); + } + }); } \ No newline at end of file Index: lams_central/web/includes/javascript/authoring/authoringMenu.js =================================================================== diff -u -r6f1d9060e228ef70caffe407480da9e857f05ca0 -r260f167585ffb5b4db7b021294782607437aed4a --- lams_central/web/includes/javascript/authoring/authoringMenu.js (.../authoringMenu.js) (revision 6f1d9060e228ef70caffe407480da9e857f05ca0) +++ lams_central/web/includes/javascript/authoring/authoringMenu.js (.../authoringMenu.js) (revision 260f167585ffb5b4db7b021294782607437aed4a) @@ -65,8 +65,7 @@ // converge point was just place, end of function HandlerLib.resetCanvasMode(true); - dialog.text(''); - dialog.dialog('close'); + dialog.text('').dialog('close'); setModified(true); } else { @@ -325,15 +324,15 @@ /** * Loads subfolders and LDs from the server. */ - getFolderContents : function(folderID, allowInvalidDesigns) { + getFolderContents : function(folderID) { var result = null; $.ajax({ url : LAMS_URL + 'home.do', data : { 'method' : 'getFolderContents', 'folderID' : folderID, - 'allowInvalidDesigns' : allowInvalidDesigns + 'allowInvalidDesigns' : true }, cache : false, async: false, Index: lams_central/web/includes/javascript/authoring/authoringProperty.js =================================================================== diff -u -r035853516626933d59e2473b4410b1dc54bb023e -r260f167585ffb5b4db7b021294782607437aed4a --- lams_central/web/includes/javascript/authoring/authoringProperty.js (.../authoringProperty.js) (revision 035853516626933d59e2473b4410b1dc54bb023e) +++ lams_central/web/includes/javascript/authoring/authoringProperty.js (.../authoringProperty.js) (revision 260f167585ffb5b4db7b021294782607437aed4a) @@ -45,24 +45,24 @@ 'click' : function() { var dialog = $(this), activity = dialog.dialog('option', 'parentObject'), - error = false; + error = null; // extract group names from text fields $('input', dialog).each(function(){ var groupName = $(this).val().trim(); if (!nameValidator.test(groupName)) { - alert('Group name can not contain any of these characters < > ^ * @ % $'); - error = true; + error = 'Group name can not contain any of these characters < > ^ * @ % $'; return false; } }); if (error) { + alert(error); return; } $('input', dialog).each(function(index){ - activity.groups[index].groupName = $(this).val().trim(); + activity.groups[index].name = $(this).val().trim(); }); dialog.dialog('close'); @@ -792,7 +792,7 @@ // normal activities can use only preceeding groupings var candidate = activity; do { - if (candidate.transitions.to.length > 0) { + if (candidate.transitions && candidate.transitions.to.length > 0) { candidate = candidate.transitions.to[0].fromActivity; } else if (candidate.parentActivity) { candidate = candidate.parentActivity; @@ -857,7 +857,7 @@ activity.groups = PropertyLib.fillNameAndUIIDList(activity.groupCount, activity.groups, 'name', 'Group '); $.each(activity.groups, function(){ - $('').addClass('groupName').appendTo(dialog).val(this.groupName); + $('').addClass('groupName').appendTo(dialog).val(this.name); dialog.append('
'); }); @@ -950,8 +950,7 @@ item[nameAttr] = prefix + itemIndex; } if (!item.uiid) { - // new unique UIID; TODO: change - item.uiid = new Date().getTime() + '_' + itemIndex; + item.uiid = ++layout.ld.maxUIID; } list.push(item); } Index: lams_common/conf/language/lams/ApplicationResources.properties =================================================================== diff -u -r02fd9bc11bce2f15195f1e9ee0b46f2f3de243c8 -r260f167585ffb5b4db7b021294782607437aed4a --- lams_common/conf/language/lams/ApplicationResources.properties (.../ApplicationResources.properties) (revision 02fd9bc11bce2f15195f1e9ee0b46f2f3de243c8) +++ lams_common/conf/language/lams/ApplicationResources.properties (.../ApplicationResources.properties) (revision 260f167585ffb5b4db7b021294782607437aed4a) @@ -17,6 +17,7 @@ validation.error.GroupingRequired =Grouping is required validation.error.GroupingNotRequired =Grouping is not supported validation.error.GroupingSelected =Grouping is selected but does not exist +validation.error.GroupingNotUsed =Grouping is not used in any of activities validation.error.OptionalActivity =An Optional Activity must have one or more activities validation.error.OptionalActivityOrderId =This Optional Activity has invalid order ids validation.error.illegalScheduleGateOffsetsType1 =A Schedule Gate cannot have equal start and end time offsets. Index: lams_common/src/java/org/lamsfoundation/lams/learningdesign/LearningDesignAccess.java =================================================================== diff -u -r035853516626933d59e2473b4410b1dc54bb023e -r260f167585ffb5b4db7b021294782607437aed4a --- lams_common/src/java/org/lamsfoundation/lams/learningdesign/LearningDesignAccess.java (.../LearningDesignAccess.java) (revision 035853516626933d59e2473b4410b1dc54bb023e) +++ lams_common/src/java/org/lamsfoundation/lams/learningdesign/LearningDesignAccess.java (.../LearningDesignAccess.java) (revision 260f167585ffb5b4db7b021294782607437aed4a) @@ -40,8 +40,9 @@ Integer userId; Date accessDate; - // non-persistent field + // non-persistent fields String title; + Integer workspaceFolderId; public Long getLearningDesignId() { return learningDesignId; @@ -75,6 +76,14 @@ this.title = title; } + public Integer getWorkspaceFolderId() { + return workspaceFolderId; + } + + public void setWorkspaceFolderId(Integer workspaceFolderId) { + this.workspaceFolderId = workspaceFolderId; + } + @Override public int hashCode() { return new HashCodeBuilder().append(learningDesignId).append(userId).toHashCode(); Index: lams_common/src/java/org/lamsfoundation/lams/learningdesign/dto/ValidationErrorDTO.java =================================================================== diff -u -r284923f86a16bfc0fa2681918f532b1eb12ac8b9 -r260f167585ffb5b4db7b021294782607437aed4a --- lams_common/src/java/org/lamsfoundation/lams/learningdesign/dto/ValidationErrorDTO.java (.../ValidationErrorDTO.java) (revision 284923f86a16bfc0fa2681918f532b1eb12ac8b9) +++ lams_common/src/java/org/lamsfoundation/lams/learningdesign/dto/ValidationErrorDTO.java (.../ValidationErrorDTO.java) (revision 260f167585ffb5b4db7b021294782607437aed4a) @@ -40,6 +40,7 @@ public static final String GROUPING_REQUIRED_ERROR_KEY = "validation.error.GroupingRequired"; // GR public static final String GROUPING_NOT_REQUIRED_ERROR_KEY = "validation.error.GroupingNotRequired"; // GNR public static final String GROUPING_SELECTED_ERROR_KEY = "validation.error.GroupingSelected"; // GS + public static final String GROUPING_NOT_USED_ERROR_KEY = "validation.error.GroupingNotUsed"; // GNU public static final String OPTIONAL_ACTIVITY_ERROR_KEY = "validation.error.OptionalActivity"; // OA public static final String OPTIONAL_ACTIVITY_ORDER_ID_INVALID_ERROR_KEY = "validation.error.OptionalActivityOrderId"; // OAOI public static final String FLOATING_ACTIVITY_ERROR_KEY = "validation.error.FloatingActivity"; // FLA @@ -70,6 +71,7 @@ public static final String GROUPING_REQUIRED_ERROR_CODE = "GR"; public static final String GROUPING_NOT_REQUIRED_ERROR_CODE = "GNR"; public static final String GROUPING_SELECTED_ERROR_CODE = "GS"; + public static final String GROUPING_NOT_USED_ERROR_CODE = "GNU"; public static final String OPTIONAL_ACTIVITY_ERROR_CODE = "OA"; public static final String OPTIONAL_ACTIVITY_ORDER_ID_INVALID_ERROR_CODE = "OAOI"; public static final String FLOATING_ACTIVITY_ERROR_CODE = "FLA"; Index: lams_common/src/java/org/lamsfoundation/lams/learningdesign/service/ExportToolContentService.java =================================================================== diff -u -rb656ce2bbd8af424fa40fab8a178419311cffe87 -r260f167585ffb5b4db7b021294782607437aed4a --- lams_common/src/java/org/lamsfoundation/lams/learningdesign/service/ExportToolContentService.java (.../ExportToolContentService.java) (revision b656ce2bbd8af424fa40fab8a178419311cffe87) +++ lams_common/src/java/org/lamsfoundation/lams/learningdesign/service/ExportToolContentService.java (.../ExportToolContentService.java) (revision 260f167585ffb5b4db7b021294782607437aed4a) @@ -96,6 +96,7 @@ import org.lamsfoundation.lams.learningdesign.GroupingActivity; import org.lamsfoundation.lams.learningdesign.LearnerChoiceGrouping; import org.lamsfoundation.lams.learningdesign.LearningDesign; +import org.lamsfoundation.lams.learningdesign.LearningLibrary; import org.lamsfoundation.lams.learningdesign.License; import org.lamsfoundation.lams.learningdesign.OptionsActivity; import org.lamsfoundation.lams.learningdesign.PermissionGateActivity; @@ -319,6 +320,10 @@ // Other fields private Logger log = Logger.getLogger(ExportToolContentService.class); + // words found both in current complex learning library descriptions and in old exported LD XML files + private static final String[][] COMPLEX_LEARNING_LIBRARY_KEY_WORDS = { { "Share", "Forum" }, { "Chat", "Scribe" }, + { "Forum", "Scribe" } }; + private static MessageService messageService; private ApplicationContext applicationContext; @@ -1360,7 +1365,7 @@ Map removedActMap = new HashMap(); List activities = ldDto.getActivities(); for (AuthoringActivityDTO activity : activities) { - ExportToolContentService.fillLearningLibraryID(activity); + fillLearningLibraryID(activity); // skip non-tool activities if (!activity.getActivityTypeID().equals(Activity.TOOL_ACTIVITY_TYPE)) { continue; @@ -2614,18 +2619,28 @@ * Guess missing Learning Library ID based on activity tool ID or description. Old exported LDs may not contain this * value. */ - private static void fillLearningLibraryID(AuthoringActivityDTO activity) { + @SuppressWarnings("unchecked") + private void fillLearningLibraryID(AuthoringActivityDTO activity) { if (activity.getLearningLibraryID() == null) { if (activity.getActivityTypeID().equals(Activity.TOOL_ACTIVITY_TYPE)) { activity.setLearningLibraryID(activity.getToolID()); } else if (activity.getActivityTypeID().equals(Activity.PARALLEL_ACTIVITY_TYPE)) { String description = activity.getDescription(); - if (description.contains("Share") && description.contains("Forum")) { - activity.setLearningLibraryID(28L); - } else if (description.contains("Chat") && description.contains("Scribe")) { - activity.setLearningLibraryID(29L); - } else if (description.contains("Forum") && description.contains("Scribe")) { - activity.setLearningLibraryID(30L); + // recognise learning libraries by their word description + for (LearningLibrary library : (List) learningLibraryDAO.getAllLearningLibraries()) { + for (String[] keyWords : COMPLEX_LEARNING_LIBRARY_KEY_WORDS) { + boolean found = false; + for (String keyWord : keyWords) { + found = description.contains(keyWord) && library.getDescription().contains(keyWord); + if (!found) { + break; + } + } + if (found) { + activity.setLibraryActivityID(library.getLearningLibraryId()); + return; + } + } } } } Index: lams_common/src/java/org/lamsfoundation/lams/learningdesign/service/LearningDesignService.java =================================================================== diff -u -r0144e9d0f7fc574a887933024183a8a9049bc414 -r260f167585ffb5b4db7b021294782607437aed4a --- lams_common/src/java/org/lamsfoundation/lams/learningdesign/service/LearningDesignService.java (.../LearningDesignService.java) (revision 0144e9d0f7fc574a887933024183a8a9049bc414) +++ lams_common/src/java/org/lamsfoundation/lams/learningdesign/service/LearningDesignService.java (.../LearningDesignService.java) (revision 260f167585ffb5b4db7b021294782607437aed4a) @@ -209,6 +209,7 @@ /** * Gets basic information on available tools. */ + @SuppressWarnings("unchecked") public List getToolDTOs(boolean includeParallel, String userName) throws IOException { User user = (User) learningLibraryDAO.findByProperty(User.class, "login", userName).get(0); String languageCode = user.getLocale().getLanguageIsoCode(); @@ -218,10 +219,19 @@ // skip invalid tools boolean isParallel = learningLibrary.getTemplateActivities().size() > 1; if (learningLibrary.getValidFlag() && (includeParallel || !isParallel)) { - LibraryActivityDTO libraryActivityDTO = (LibraryActivityDTO) learningLibrary.getTemplateActivities() - .get(0); + List libraryActivityDTOs = learningLibrary.getTemplateActivities(); + LibraryActivityDTO libraryActivityDTO = libraryActivityDTOs.get(0); ToolDTO toolDTO = new ToolDTO(); - if (!isParallel) { + if (isParallel) { + List childLibraryIDs = new ArrayList(); + for (LibraryActivityDTO childActivityDTO : libraryActivityDTOs) { + Long childToolID = childActivityDTO.getToolID(); + if (childToolID != null) { + childLibraryIDs.add(childToolID); + } + } + toolDTO.setChildToolIds(childLibraryIDs.toArray(new Long[] {})); + } else { toolDTO.setToolId(libraryActivityDTO.getToolID()); } toolDTO.setLearningLibraryId(learningLibrary.getLearningLibraryID()); Index: lams_common/src/java/org/lamsfoundation/lams/learningdesign/service/LearningDesignValidator.java =================================================================== diff -u -r284923f86a16bfc0fa2681918f532b1eb12ac8b9 -r260f167585ffb5b4db7b021294782607437aed4a --- lams_common/src/java/org/lamsfoundation/lams/learningdesign/service/LearningDesignValidator.java (.../LearningDesignValidator.java) (revision 284923f86a16bfc0fa2681918f532b1eb12ac8b9) +++ lams_common/src/java/org/lamsfoundation/lams/learningdesign/service/LearningDesignValidator.java (.../LearningDesignValidator.java) (revision 260f167585ffb5b4db7b021294782607437aed4a) @@ -64,6 +64,7 @@ } /** Run the validation */ + @SuppressWarnings("unchecked") public Vector validate() { errors = new Vector(); // initialises the list of validation messages. @@ -83,7 +84,8 @@ Set topLevelActivities = extractFloatingActivities(learningDesign.getParentActivities()); validateActivityTransitionRules(topLevelActivities, learningDesign.getTransitions()); - for (Activity activity : (Set) learningDesign.getActivities()) { + Set activities = (Set) learningDesign.getActivities(); + for (Activity activity : activities) { if (!ValidationUtil.isOrgNameValid(activity.getTitle())) { errors.add(new ValidationErrorDTO(ValidationErrorDTO.TITLE_CHARACTERS_ERROR_CODE, messageService .getMessage(ValidationErrorDTO.TITLE_CHARACTERS_ERROR_KEY), activity.getActivityUIID())); @@ -94,7 +96,7 @@ validateOptionalActivity(activity); validateOptionsActivityOrderId(activity); validateFloatingActivity(activity); - validateGroupingActivity(activity); + validateGroupingActivity(activity, activities); Vector activityErrors = activity.validateActivity(messageService); if (activityErrors != null && !activityErrors.isEmpty()) { errors.addAll(activityErrors); @@ -458,7 +460,7 @@ * * @param parentActivity */ - private void validateGroupingActivity(Activity activity) { + private void validateGroupingActivity(Activity activity, Set activities) { if (activity.isGroupingActivity()) { // get the child activities and check how many there are. @@ -482,8 +484,21 @@ messageService.getMessage(ValidationErrorDTO.GROUPING_ACTIVITY_GROUP_COUNT_MISMATCH_KEY), activity.getActivityUIID())); } - } + boolean used = false; + for (Activity groupedActivity : activities) { + if (groupedActivity.getApplyGrouping() + && groupingActivity.getCreateGroupingUIID().equals(groupedActivity.getGroupingUIID())) { + used = true; + break; + } + } + + if (!used) { + errors.add(new ValidationErrorDTO(ValidationErrorDTO.GROUPING_NOT_USED_ERROR_CODE, messageService + .getMessage(ValidationErrorDTO.GROUPING_NOT_USED_ERROR_KEY), activity.getActivityUIID())); + } + } } /** Index: lams_common/src/java/org/lamsfoundation/lams/tool/dto/ToolDTO.java =================================================================== diff -u -r9fb16007bc803d29180994effaed30ebb0a2e561 -r260f167585ffb5b4db7b021294782607437aed4a --- lams_common/src/java/org/lamsfoundation/lams/tool/dto/ToolDTO.java (.../ToolDTO.java) (revision 9fb16007bc803d29180994effaed30ebb0a2e561) +++ lams_common/src/java/org/lamsfoundation/lams/tool/dto/ToolDTO.java (.../ToolDTO.java) (revision 260f167585ffb5b4db7b021294782607437aed4a) @@ -30,6 +30,7 @@ private String iconPath; private Boolean supportsOutputs; private Integer activityCategoryID; + private Long[] childToolIds; public ToolDTO() { } @@ -75,10 +76,19 @@ } public Long getLearningLibraryId() { - return learningLibraryId; + return learningLibraryId; } public void setLearningLibraryId(Long learningLibraryId) { - this.learningLibraryId = learningLibraryId; + this.learningLibraryId = learningLibraryId; } + + public Long[] getChildToolIds() { + return childToolIds; + } + + public void setChildToolIds(Long[] childLearningLibraryIds) { + this.childToolIds = childLearningLibraryIds; + } + } \ No newline at end of file