Index: lams_build/lib/lams/lams.jar =================================================================== diff -u -rf26fb3937b73bfdefd25a6166863ea188d5f8cb9 -r9fb16007bc803d29180994effaed30ebb0a2e561 Binary files differ Index: lams_central/src/java/org/lamsfoundation/lams/authoring/web/AuthoringAction.java =================================================================== diff -u -r91846a63ca7f8b611b2acb7a09cd42bb522fd305 -r9fb16007bc803d29180994effaed30ebb0a2e561 --- lams_central/src/java/org/lamsfoundation/lams/authoring/web/AuthoringAction.java (.../AuthoringAction.java) (revision 91846a63ca7f8b611b2acb7a09cd42bb522fd305) +++ lams_central/src/java/org/lamsfoundation/lams/authoring/web/AuthoringAction.java (.../AuthoringAction.java) (revision 9fb16007bc803d29180994effaed30ebb0a2e561) @@ -111,7 +111,7 @@ public ActionForward openAuthoring(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws IOException { - request.setAttribute("tools", getLearningDesignService().getToolDTOs(request.getRemoteUser())); + request.setAttribute("tools", getLearningDesignService().getToolDTOs(true, request.getRemoteUser())); request.setAttribute(AttributeNames.PARAM_CONTENT_FOLDER_ID, FileUtil.generateUniqueContentFolderID()); return mapping.findForward("openAutoring"); } Index: lams_central/src/java/org/lamsfoundation/lams/web/DisplayGroupAction.java =================================================================== diff -u -rf92865513dd2beca642af28ab42096ee4849ac32 -r9fb16007bc803d29180994effaed30ebb0a2e561 --- lams_central/src/java/org/lamsfoundation/lams/web/DisplayGroupAction.java (.../DisplayGroupAction.java) (revision f92865513dd2beca642af28ab42096ee4849ac32) +++ lams_central/src/java/org/lamsfoundation/lams/web/DisplayGroupAction.java (.../DisplayGroupAction.java) (revision 9fb16007bc803d29180994effaed30ebb0a2e561) @@ -110,8 +110,8 @@ iob.setAllowSorting(allowSorting && iob.getAllowSorting()); if (org.getEnableSingleActivityLessons() && (roles.contains(Role.ROLE_GROUP_MANAGER) || roles.contains(Role.ROLE_MONITOR))) { - // if sinble activity lessons are enabled, put sorted list of tools - request.setAttribute("tools", getLearningDesignService().getToolDTOs(request.getRemoteUser())); + // if single activity lessons are enabled, put sorted list of tools + request.setAttribute("tools", getLearningDesignService().getToolDTOs(false, request.getRemoteUser())); } } Index: lams_central/web/author2.jsp =================================================================== diff -u -r8068bd165e981855f43bdeb2358e2a6b3654020c -r9fb16007bc803d29180994effaed30ebb0a2e561 --- lams_central/web/author2.jsp (.../author2.jsp) (revision 8068bd165e981855f43bdeb2358e2a6b3654020c) +++ lams_central/web/author2.jsp (.../author2.jsp) (revision 9fb16007bc803d29180994effaed30ebb0a2e561) @@ -126,8 +126,9 @@
-
@@ -405,7 +406,29 @@
+ +
+ + + + + + + + + +
+ Title: + + +
+ Grouping: + + +
+
+
Index: lams_central/web/css/authoring.css =================================================================== diff -u -r91846a63ca7f8b611b2acb7a09cd42bb522fd305 -r9fb16007bc803d29180994effaed30ebb0a2e561 --- lams_central/web/css/authoring.css (.../authoring.css) (revision 91846a63ca7f8b611b2acb7a09cd42bb522fd305) +++ lams_central/web/css/authoring.css (.../authoring.css) (revision 9fb16007bc803d29180994effaed30ebb0a2e561) @@ -239,7 +239,7 @@ } td#templateContainerCell { - width: 152px; + width: 150px; border: black thin solid; vertical-align: top; background-color: rgb(219, 230, 252); @@ -262,7 +262,7 @@ div.template div { float: right; - width: 92px; + width: 89px; padding-top: 11px; font-size: 10pt; font-family: serif; Index: lams_central/web/includes/javascript/authoring/authoringActivity.js =================================================================== diff -u -rf7bdb0b820dd3047c08763d965bb0cae0f5ea29b -r9fb16007bc803d29180994effaed30ebb0a2e561 --- lams_central/web/includes/javascript/authoring/authoringActivity.js (.../authoringActivity.js) (revision f7bdb0b820dd3047c08763d965bb0cae0f5ea29b) +++ lams_central/web/includes/javascript/authoring/authoringActivity.js (.../authoringActivity.js) (revision 9fb16007bc803d29180994effaed30ebb0a2e561) @@ -72,7 +72,7 @@ this.loadPropertiesDialogContent = PropertyLib.groupingProperties; - this.draw = ActivityLib.draw.grouping; + this.draw = ActivityLib.draw.grouping; this.draw(x, y); }, @@ -149,6 +149,26 @@ }, + ParallelActivity : function(id, uiid, learningLibraryID, x, y, title, childActivities){ + DecorationLib.Container.call(this, title); + + this.id = +id; + this.uiid = +uiid || ++layout.ld.maxUIID; + this.learningLibraryID = +learningLibraryID; + this.transitions = { + 'from' : [], + 'to' : [] + }; + if (childActivities){ + this.childActivities = childActivities; + } + + this.loadPropertiesDialogContent = PropertyLib.parallelProperties; + + this.draw = ActivityLib.draw.parallelActivity; + this.draw(x, y); + }, + /** * Constructor for an Optional Activity. */ @@ -369,6 +389,40 @@ }, + parallelActivity : function(x, y) { + if (x == undefined || y == undefined) { + // if no new coordinates are given, just redraw the activity + x = this.items.shape.getBBox().x; + y = this.items.shape.getBBox().y; + } + + if (this.childActivities && this.childActivities.length > 0) { + // draw one by one, vertically + var activityY = y + 30, + allElements = paper.set(), + optionalActivity = this; + $.each(this.childActivities, function(orderID){ + this.parentActivity = optionalActivity; + this.orderID = orderID + 1; + this.draw(x + 20, activityY); + activityY = this.items.shape.getBBox().y2 + 10; + allElements.push(this.items.shape); + }); + // area containing all drawn child activities + var box = allElements.getBBox(); + + this.drawContainer(x, y, box.x2 + 20, box.y2 + 20, layout.colors.optionalActivity); + } else { + this.drawContainer(x, y, x + 50, y + 70, layout.colors.optionalActivity); + } + + // allow transition drawing and other activity behaviour + this.items.shape.unmousedown().mousedown(HandlerLib.activityMousedownHandler); + + this.items.data('parentObject', this); + }, + + optionalActivity : function(x, y, ignoredParam1, ignoredParam2, childActivities) { if (x == undefined || y == undefined) { // if no new coordinates are given, just redraw the activity Index: lams_central/web/includes/javascript/authoring/authoringDecoration.js =================================================================== diff -u -r8068bd165e981855f43bdeb2358e2a6b3654020c -r9fb16007bc803d29180994effaed30ebb0a2e561 --- lams_central/web/includes/javascript/authoring/authoringDecoration.js (.../authoringDecoration.js) (revision 8068bd165e981855f43bdeb2358e2a6b3654020c) +++ lams_central/web/includes/javascript/authoring/authoringDecoration.js (.../authoringDecoration.js) (revision 9fb16007bc803d29180994effaed30ebb0a2e561) @@ -65,7 +65,10 @@ this.items = paper.set(); if (this.title) { var label = paper.text(x + 7, y + 10, this.title) - .attr('text-anchor', 'start') + .attr({ + 'text-anchor' : 'start', + 'cursor' : 'pointer' + }) .toBack(); this.items.push(label); @@ -79,10 +82,11 @@ 'fill' : color, 'cursor' : 'pointer' }) - .mousedown(HandlerLib.containerMousedownHandler) - .click(HandlerLib.itemClickHandler) .toBack(); this.items.push(this.items.shape); + + this.items.mousedown(HandlerLib.containerMousedownHandler) + .click(HandlerLib.itemClickHandler); }, /** @@ -231,5 +235,6 @@ // set prototype hierarchy DecorationLib.Region.prototype = new DecorationLib.Container; +ActivityLib.ParallelActivity.prototype = new DecorationLib.Container; ActivityLib.OptionalActivity.prototype = new DecorationLib.Container; ActivityLib.FloatingActivity.prototype = new DecorationLib.Container; \ No newline at end of file Index: lams_central/web/includes/javascript/authoring/authoringGeneral.js =================================================================== diff -u -rf7bdb0b820dd3047c08763d965bb0cae0f5ea29b -r9fb16007bc803d29180994effaed30ebb0a2e561 --- lams_central/web/includes/javascript/authoring/authoringGeneral.js (.../authoringGeneral.js) (revision f7bdb0b820dd3047c08763d965bb0cae0f5ea29b) +++ lams_central/web/includes/javascript/authoring/authoringGeneral.js (.../authoringGeneral.js) (revision 9fb16007bc803d29180994effaed30ebb0a2e561) @@ -92,12 +92,37 @@ */ function initTemplates(){ $('.template').each(function(){ - var toolId = +$(this).attr('toolId'); + var learningLibraryID = +$(this).attr('learningLibraryId'), + activityCategoryID = +$(this).attr('activityCategoryId'), + 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; + } + } + // register tool properties so they are later easily accessible - layout.toolMetadata[toolId] = { - 'iconPath' : $('img', this).attr('src'), - 'supportsOutputs' : $(this).attr('supportsOutputs'), - 'activityCategoryID' : +$(this).attr('activityCategoryID') + layout.toolMetadata[learningLibraryID] = { + 'iconPath' : $('img', this).attr('src'), + 'supportsOutputs' : $(this).attr('supportsOutputs'), + 'activityCategoryID' : activityCategoryID, + 'parallelChildActivities' : parallelChildActivities }; // if a tool's name is too long and gets broken into two lines @@ -140,15 +165,34 @@ $(draggable.helper).remove(); // calculate the position and create an instance of the tool activity - var toolID = draggable.draggable.attr('toolId'), + var learningLibraryID = +draggable.draggable.attr('learningLibraryId'), + activityCategoryID = +draggable.draggable.attr('activityCategoryId'), x = draggable.offset.left + canvas.scrollLeft() - canvas.offset().left, y = draggable.offset.top + canvas.scrollTop() - canvas.offset().top, label = $('div', draggable.draggable).text(), - activity = new ActivityLib.ToolActivity(null, null, null, toolID, x, y, label), + activity = null, translatedEvent = ActivityLib.translateEventOnCanvas(event), eventX = translatedEvent[0], eventY = translatedEvent[1]; + if (activityCategoryID == 5) { + // construct child activities out of previously referenced HTML templates + var childActivities = []; + layout.toolMetadata[learningLibraryID].parallelChildActivities.each(function(){ + var toolActivityLibraryID = +$(this).attr('learningLibraryId'), + toolLabel = $('div', this).text(), + childActivity = new ActivityLib.ToolActivity(null, null, null, + toolActivityLibraryID, x, y, toolLabel); + + layout.activities.push(childActivity); + childActivities.push(childActivity); + }); + + activity = new ActivityLib.ParallelActivity(null, null, learningLibraryID, x, y, label, childActivities); + } else { + activity = new ActivityLib.ToolActivity(null, null, null, learningLibraryID, x, y, label); + } + layout.activities.push(activity); ActivityLib.dropActivity(activity, eventX, eventY); } @@ -464,7 +508,7 @@ case 3: var gateType = 'sync'; case 4: var gateType = gateType || 'schedule'; case 5: var gateType = gateType || 'permision'; - case 6: + case 14: var gateType = gateType || 'condition'; activity = new ActivityLib.GateActivity(activityData.activityID, activityData.activityUIID, @@ -473,6 +517,16 @@ gateType); break; + // Parallel Activity + case 6: + activity = new ActivityLib.ParallelActivity(activityData.activityID, + activityData.activityUIID, + activityData.learningLibraryID, + activityData.xCoord, + activityData.yCoord, + activityData.activityTitle); + break; + // Optional Activity case 7: activity = new ActivityLib.OptionalActivity(activityData.activityID, @@ -627,11 +681,13 @@ } } - // find Optional Activity + // find Optional/Parallel Activity if (activityData.parentActivityID && !activity.parentActivity) { $.each(layout.activities, function(){ - if (activityData.parentActivityID == this.id && this instanceof ActivityLib.OptionalActivity) { - // add a Tool Activity as a Optional Activity element + if (activityData.parentActivityID == this.id + && (this instanceof ActivityLib.ParallelActivity + || this instanceof ActivityLib.OptionalActivity)) { + // add a Tool Activity as a Optional/Parallel Activity element if (!this.childActivities) { this.childActivities = []; } @@ -824,16 +880,17 @@ activityBox = activity.items ? activity.items.shape.getBBox() : null, activityTypeID = null, toolID = activity.toolID, + learningLibraryID = toolID ? toolID : activity.learningLibraryID, iconPath = null, isGrouped = activity.grouping ? true : false, parentActivityID = activity.parentActivity ? activity.parentActivity.id : null; if (toolID) { activityTypeID = 1; // find out what is the icon for tool acitivty - var templateIcon = $('.template[toolId=' + toolID +'] img'); + var templateIcon = $('.template[learningLibraryId=' + learningLibraryID +'] img'); if (templateIcon.width() > 0) { - iconPath = layout.toolMetadata[toolID].iconPath; + iconPath = layout.toolMetadata[learningLibraryID].iconPath; } } // translate activity type to back-end understandable @@ -880,8 +937,10 @@ case 'sync' : activityTypeID = 3; break; case 'schedule' : activityTypeID = 4; break; case 'permision' : activityTypeID = 5; break; - case 'condition' : activityTypeID = 6; break; + case 'condition' : activityTypeID = 14; break; } + } else if (activity instanceof ActivityLib.ParallelActivity) { + activityTypeID = 6; } else if (activity instanceof ActivityLib.OptionalActivity) { activityTypeID = 7; } else if (activity instanceof ActivityLib.BranchingActivity) { @@ -917,7 +976,7 @@ 'activityID' : activity.id, 'activityUIID' : activity.uiid, 'toolID' : toolID, - 'learningLibraryID' : toolID, + 'learningLibraryID' : learningLibraryID, 'toolContentID' : activity.toolContentID, 'stopAfterActivity' : false, 'groupingSupportType' : 2, @@ -930,8 +989,9 @@ 'xCoord' : activityBox ? parseInt(activityBox.x) : null, 'yCoord' : activityBox ? parseInt(activityBox.y) : null, 'activityTitle' : activity.title, - 'activityCategoryID' : activity instanceof ActivityLib.ToolActivity ? - layout.toolMetadata[toolID].activityCategoryID : 1, + 'activityCategoryID' : activity instanceof ActivityLib.ToolActivity + || activity instanceof ActivityLib.ParallelActivity ? + layout.toolMetadata[learningLibraryID].activityCategoryID : 1, 'activityTypeID' : activityTypeID, 'orderID' : activity.orderID, 'defaultActivityUIID' : activity.defaultActivityUIID, Index: lams_central/web/includes/javascript/authoring/authoringHandler.js =================================================================== diff -u -r8068bd165e981855f43bdeb2358e2a6b3654020c -r9fb16007bc803d29180994effaed30ebb0a2e561 --- lams_central/web/includes/javascript/authoring/authoringHandler.js (.../authoringHandler.js) (revision 8068bd165e981855f43bdeb2358e2a6b3654020c) +++ lams_central/web/includes/javascript/authoring/authoringHandler.js (.../authoringHandler.js) (revision 9fb16007bc803d29180994effaed30ebb0a2e561) @@ -106,7 +106,8 @@ items.attr('cursor', 'move'); var parentObject = draggedElement.data('parentObject'); - sticky = parentObject && (parentObject instanceof ActivityLib.OptionalActivity + sticky = parentObject && (parentObject instanceof ActivityLib.ParallelActivity + || parentObject instanceof ActivityLib.OptionalActivity || parentObject instanceof ActivityLib.FloatingActivity); if (sticky) { $.each(parentObject.childActivities, function(){ @@ -388,7 +389,8 @@ if (event.ctrlKey) { // when CTRL is held down, start drawing a transition HandlerLib.drawTransitionStartHandler(activity, event, x, y); - } else { + } else if (!activity.parentActivity + || !(activity.parentActivity instanceof ActivityLib.ParallelActivity)){ var mouseupHandler = function(event){ if (HandlerLib.isElemenentBinned(event)) { // if the activity was over rubbish bin, remove it @@ -481,7 +483,9 @@ } } else { HandlerLib.dropObject(container); - if (container instanceof ActivityLib.FloatingActivity) { + if (container instanceof ActivityLib.FloatingActivity + || container instanceof ActivityLib.OptionalActivity + || container instanceof ActivityLib.ParallelActivity) { ActivityLib.dropActivity(container); } } Index: lams_central/web/includes/javascript/authoring/authoringMenu.js =================================================================== diff -u -rf7bdb0b820dd3047c08763d965bb0cae0f5ea29b -r9fb16007bc803d29180994effaed30ebb0a2e561 --- lams_central/web/includes/javascript/authoring/authoringMenu.js (.../authoringMenu.js) (revision f7bdb0b820dd3047c08763d965bb0cae0f5ea29b) +++ lams_central/web/includes/javascript/authoring/authoringMenu.js (.../authoringMenu.js) (revision 9fb16007bc803d29180994effaed30ebb0a2e561) @@ -274,7 +274,7 @@ * Opens "Save sequence" dialog where an user can choose where to save the Learning Design. */ saveLearningDesign : function(showDialog){ - if (!showDialog) { + if (!showDialog && layout.ld.learningDesignID) { saveLearningDesign(layout.ld.folderID, layout.ld.learningDesignID, layout.ld.title); return; } Index: lams_central/web/includes/javascript/authoring/authoringProperty.js =================================================================== diff -u -rcfbe222136efc72d14e61537ebc809cd6912a723 -r9fb16007bc803d29180994effaed30ebb0a2e561 --- lams_central/web/includes/javascript/authoring/authoringProperty.js (.../authoringProperty.js) (revision cfbe222136efc72d14e61537ebc809cd6912a723) +++ lams_central/web/includes/javascript/authoring/authoringProperty.js (.../authoringProperty.js) (revision 9fb16007bc803d29180994effaed30ebb0a2e561) @@ -181,12 +181,15 @@ */ toolProperties : function() { var activity = this, - content = activity.propertiesContent; + content = activity.propertiesContent, + allowsGrouping = !this.parentActivity || !(this.parentActivity instanceof ActivityLib.ParallelActivity); + if (!content) { // first run, create the content content = activity.propertiesContent = $('#propertiesContentTool').clone().attr('id', null) .show().data('parentObject', activity); $('.propertiesContentFieldTitle', content).val(activity.title); + $('.propertiesContentFieldGrouping', content).closest('tr').remove(); $('input, select', content).change(function(){ // extract changed properties and redraw the activity @@ -198,11 +201,15 @@ activity.title = newTitle; redrawNeeded = true; } - var newGroupingValue = $('.propertiesContentFieldGrouping option:selected', content) - .data('grouping'); - if (newGroupingValue != activity.grouping) { - activity.grouping = newGroupingValue; - redrawNeeded = true; + + var selectedGrouping = $('.propertiesContentFieldGrouping option:selected', content); + if (selectedGrouping.length > 0){ + var newGroupingValue = $('.propertiesContentFieldGrouping option:selected', content) + .data('grouping'); + if (newGroupingValue != activity.grouping) { + activity.grouping = newGroupingValue; + redrawNeeded = true; + } } if (redrawNeeded) { @@ -211,7 +218,9 @@ }); } - PropertyLib.fillGroupingDropdown(content, activity.grouping); + if (allowsGrouping){ + PropertyLib.fillGroupingDropdown(content, activity.grouping); + } }, @@ -406,6 +415,46 @@ /** + * Properties dialog content for Parallel activities. + */ + parallelProperties : function() { + var activity = this, + content = activity.propertiesContent; + + if (!content) { + // first run, create the content + content = activity.propertiesContent = $('#propertiesContentParallel').clone().attr('id', null) + .show().data('parentObject', activity); + $('.propertiesContentFieldTitle', content).val(activity.title); + + $('input, select', content).change(function(){ + // extract changed properties and redraw the activity + var content = $(this).closest('.dialogContainer'), + activity = content.data('parentObject'), + redrawNeeded = false, + newTitle = $('.propertiesContentFieldTitle', content).val(); + if (newTitle != activity.title) { + activity.title = newTitle; + redrawNeeded = true; + } + var newGroupingValue = $('.propertiesContentFieldGrouping option:selected', content) + .data('grouping'); + if (newGroupingValue != activity.grouping) { + activity.grouping = newGroupingValue; + redrawNeeded = true; + } + + if (redrawNeeded) { + activity.draw(); + } + }); + } + + PropertyLib.fillGroupingDropdown(content, activity.grouping); + }, + + + /** * Properties dialog content for Optional Activity. */ optionalActivityProperties : function() { @@ -536,7 +585,7 @@ var emptyOption = $('