Index: lams_central/conf/language/lams/ApplicationResources.properties =================================================================== diff -u -re52d30b33ec37f94d5838417763f6b29d6cc7d70 -r73b16b1e6ae040974e8ba89abf3497abceb9420f --- lams_central/conf/language/lams/ApplicationResources.properties (.../ApplicationResources.properties) (revision e52d30b33ec37f94d5838417763f6b29d6cc7d70) +++ lams_central/conf/language/lams/ApplicationResources.properties (.../ApplicationResources.properties) (revision 73b16b1e6ae040974e8ba89abf3497abceb9420f) @@ -592,6 +592,7 @@ authoring.fla.page.prop.hours = hours authoring.fla.page.prop.minutes = minutes authoring.fla.page.prop.gate.activity.finish.based = Since learner finished previous activity? +authoring.fla.page.prop.gate.stop.at.preceding = Stop learners at preceding activity? authoring.fla.page.prop.conditions.create = Create conditions authoring.fla.page.prop.gate.conditions.map = Map gate conditions authoring.fla.page.prop.branching.type = Branching type: Index: lams_central/src/java/org/lamsfoundation/lams/authoring/ObjectExtractor.java =================================================================== diff -u -r2a60aefd13ef4aac8e67f7e23ff837062aa837d9 -r73b16b1e6ae040974e8ba89abf3497abceb9420f --- lams_central/src/java/org/lamsfoundation/lams/authoring/ObjectExtractor.java (.../ObjectExtractor.java) (revision 2a60aefd13ef4aac8e67f7e23ff837062aa837d9) +++ lams_central/src/java/org/lamsfoundation/lams/authoring/ObjectExtractor.java (.../ObjectExtractor.java) (revision 73b16b1e6ae040974e8ba89abf3497abceb9420f) @@ -1209,11 +1209,11 @@ if (activity instanceof SynchGateActivity) { buildSynchGateActivity((SynchGateActivity) activity); } else if (activity instanceof PermissionGateActivity) { - buildPermissionGateActivity((PermissionGateActivity) activity); + buildPermissionGateActivity((PermissionGateActivity) activity, activityDetails); } else if (activity instanceof SystemGateActivity) { buildSystemGateActivity((SystemGateActivity) activity); } else if (activity instanceof ConditionGateActivity) { - buildConditionGateActivity((ConditionGateActivity) activity); + buildConditionGateActivity((ConditionGateActivity) activity, activityDetails); } else if (activity instanceof ScheduleGateActivity) { buildScheduleGateActivity((ScheduleGateActivity) activity, activityDetails); } else { @@ -1227,7 +1227,9 @@ activity.setSystemTool(getSystemTool(SystemTool.SYNC_GATE)); } - private void buildPermissionGateActivity(PermissionGateActivity activity) { + private void buildPermissionGateActivity(PermissionGateActivity activity, ObjectNode activityDetails) { + activity.setGateStopAtPrecedingActivity(JsonUtil.optBoolean(activityDetails, + AuthoringJsonTags.GATE_STOP_AT_PRECEDING_ACTIVITY, false)); activity.setSystemTool(getSystemTool(SystemTool.PERMISSION_GATE)); } @@ -1246,6 +1248,8 @@ Boolean isGateActivityCompletionBased = JsonUtil.optBoolean(activityDetails, AuthoringJsonTags.GATE_ACTIVITY_COMPLETION_BASED); activity.setGateActivityCompletionBased(isGateActivityCompletionBased); + activity.setGateStopAtPrecedingActivity(JsonUtil.optBoolean(activityDetails, + AuthoringJsonTags.GATE_STOP_AT_PRECEDING_ACTIVITY, false)); activity.setSystemTool(getSystemTool(SystemTool.SCHEDULE_GATE)); } @@ -1667,7 +1671,9 @@ JsonUtil.optBoolean(groupingDetails, AuthoringJsonTags.VIEW_STUDENTS_BEFORE_SELECTION)); } - private void buildConditionGateActivity(ConditionGateActivity activity) { + private void buildConditionGateActivity(ConditionGateActivity activity, ObjectNode activityDetails) { + activity.setGateStopAtPrecedingActivity(JsonUtil.optBoolean(activityDetails, + AuthoringJsonTags.GATE_STOP_AT_PRECEDING_ACTIVITY, false)); activity.setSystemTool(getSystemTool(SystemTool.CONDITION_GATE)); } } \ No newline at end of file Index: lams_central/web/authoring/authoring.jsp =================================================================== diff -u -r9dcc3e2d26b504f92d919f53f0d45dd4093a82a2 -r73b16b1e6ae040974e8ba89abf3497abceb9420f --- lams_central/web/authoring/authoring.jsp (.../authoring.jsp) (revision 9dcc3e2d26b504f92d919f53f0d45dd4093a82a2) +++ lams_central/web/authoring/authoring.jsp (.../authoring.jsp) (revision 73b16b1e6ae040974e8ba89abf3497abceb9420f) @@ -476,7 +476,7 @@ onClick="javascript:MenuLib.toggleDescriptionDiv()"> - + ?

@@ -813,15 +813,15 @@ - + - + @@ -838,28 +838,36 @@ - + - + + + + + + + + + - +
- + Index: lams_central/web/includes/javascript/authoring/authoringActivity.js =================================================================== diff -u -r8b07361616a84041e46ce81176f84026e1fc7136 -r73b16b1e6ae040974e8ba89abf3497abceb9420f --- lams_central/web/includes/javascript/authoring/authoringActivity.js (.../authoringActivity.js) (revision 8b07361616a84041e46ce81176f84026e1fc7136) +++ lams_central/web/includes/javascript/authoring/authoringActivity.js (.../authoringActivity.js) (revision 73b16b1e6ae040974e8ba89abf3497abceb9420f) @@ -180,13 +180,16 @@ /** * Constructor for a Gate Activity. */ - GateActivity : function(id, uiid, x, y, title, description, readOnly, gateType, startTimeOffset, gateActivityCompletionBased, password) { + GateActivity : function(id, uiid, x, y, title, description, readOnly, gateType, startTimeOffset, + gateActivityCompletionBased, gateStopAtPrecedingActivity, password) { this.id = +id || null; this.uiid = +uiid || ++layout.ld.maxUIID; this.title = title; this.description = description; this.readOnly = readOnly; this.gateType = gateType || 'permission'; + this.gateStopAtPrecedingActivity = gateStopAtPrecedingActivity; + if (gateType == 'schedule') { var day = 24*60; this.offsetDay = Math.floor(startTimeOffset/day); @@ -199,6 +202,7 @@ if (gateType == 'password') { this.password = password; } + // mapping between tool output and gate states ("branches"), if applicable this.conditionsToBranches = []; this.transitions = { Index: lams_central/web/includes/javascript/authoring/authoringGeneral.js =================================================================== diff -u -r9eb09148e5b2bc28bf60fa6c7300d544947f4379 -r73b16b1e6ae040974e8ba89abf3497abceb9420f --- lams_central/web/includes/javascript/authoring/authoringGeneral.js (.../authoringGeneral.js) (revision 9eb09148e5b2bc28bf60fa6c7300d544947f4379) +++ lams_central/web/includes/javascript/authoring/authoringGeneral.js (.../authoringGeneral.js) (revision 73b16b1e6ae040974e8ba89abf3497abceb9420f) @@ -810,7 +810,6 @@ // activities in the another LD have different clousures, so they can not be imported directly // they need to be recreated from a scratch with current LD being their context var frameWindow = $('#ldStoreDialogImportPartFrame', layout.ldStoreDialog)[0].contentWindow, - frameActivities = frameWindow.layout.activities, frameActivityDefs = frameWindow.ActivityDefs, // the local activity addActivity = null; @@ -839,7 +838,8 @@ } else if (activity instanceof frameActivityDefs.GateActivity) { addActivity = new ActivityDefs.GateActivity( null, activity.uiid, 0, 0, activity.title, activity.description, false, activity.gateType, - activity.startTimeoffset, activity.gateActivityCompletionBased + activity.startTimeoffset, activity.gateActivityCompletionBased, activity.gateStopAtPrecedingActivity, + activity.password ); } else if (activity instanceof frameActivityDefs.GroupingActivity) { addActivity = new ActivityDefs.GroupingActivity( @@ -1922,6 +1922,7 @@ gateType, activityData.gateStartTimeOffset, activityData.gateActivityCompletionBased, + activityData.gateStopAtPrecedingActivity, activityData.gatePassword); if (gateType == 'system'){ @@ -2564,13 +2565,10 @@ x = activityBox ? parseInt(activityBox.x) : null, y = activityBox ? parseInt(activityBox.y) : null, activityTypeID = null, - activityCategoryID = activity instanceof ActivityDefs.ToolActivity ? - layout.toolMetadata[activity.learningLibraryID].activityCategoryID : - activity instanceof ActivityDefs.ParallelActivity ? 5 : 1, iconPath = null, isGrouped = activity.grouping ? true : false, - parentActivityID = activity.parentActivity ? activity.parentActivity.id : null, gateActivityCompletionBased = false, + gateStopAtPrecedingActivity = false, activityTransitions = activity instanceof ActivityDefs.BranchingActivity ? activity.end.transitions : activity.transitions; @@ -2620,21 +2618,26 @@ }); } else if (activity instanceof ActivityDefs.GateActivity){ + let previousActivityExists = activityTransitions && activityTransitions.to && activityTransitions.to.length > 0; + switch(activity.gateType) { case 'sync' : activityTypeID = 3; break; case 'schedule' : activityTypeID = 4; - gateActivityCompletionBased = activity.gateActivityCompletionBased - //check the previous activity is available as well - && (activityTransitions && activityTransitions.to && activityTransitions.to.length > 0); + gateActivityCompletionBased = activity.gateActivityCompletionBased && previousActivityExists; + gateStopAtPrecedingActivity = activity.gateStopAtPrecedingActivity && previousActivityExists; break; - case 'permission' : activityTypeID = 5; break; + case 'permission' : + activityTypeID = 5; + gateStopAtPrecedingActivity = activity.gateStopAtPrecedingActivity && previousActivityExists; + break; case 'password' : activityTypeID = 16; break; case 'system' : activityTypeID = 9; systemGate = activity; break; case 'condition' : activityTypeID = 14; - + gateStopAtPrecedingActivity = activity.gateStopAtPrecedingActivity && previousActivityExists; + if (activity.input) { $.each(activity.conditionsToBranches, function(index){ if (!this.branch) { @@ -2761,6 +2764,7 @@ 'gateStartTimeOffset' : activity.gateType == 'schedule' ? activity.offsetDay*24*60 + activity.offsetHour*60 + activity.offsetMinute : null, 'gateActivityCompletionBased' : gateActivityCompletionBased, + 'gateStopAtPrecedingActivity' : gateStopAtPrecedingActivity, 'gatePassword' : activity.gateType == 'password' ? activity.password : null, 'gateActivityLevelID' : activity instanceof ActivityDefs.GateActivity ? 1 : null, 'minOptions' : activity.minOptions || null, Index: lams_central/web/includes/javascript/authoring/authoringProperty.js =================================================================== diff -u -r82cb3e631a089f00c5cf3492074aa0972f2506d0 -r73b16b1e6ae040974e8ba89abf3497abceb9420f --- lams_central/web/includes/javascript/authoring/authoringProperty.js (.../authoringProperty.js) (revision 82cb3e631a089f00c5cf3492074aa0972f2506d0) +++ lams_central/web/includes/javascript/authoring/authoringProperty.js (.../authoringProperty.js) (revision 73b16b1e6ae040974e8ba89abf3497abceb9420f) @@ -215,37 +215,40 @@ activity.gateType = $('.propertiesContentFieldGateType', content).val(); + $('.propertiesContentRowGateTypeBased', content).hide(); if (activity.gateType == 'schedule') { // show inputs for setting delay before the gate is closed $(".propertiesContentRowGateSchedule", content).show(); activity.offsetDay = +$('.propertiesContentFieldOffsetDay', content).val(); activity.offsetHour = +$('.propertiesContentFieldOffsetHour', content).val(); activity.offsetMinute = +$('.propertiesContentFieldOffsetMinute', content).val(); activity.gateActivityCompletionBased = $('.propertiesContentFieldActivityCompletionBased', content).is(':checked'); - } else { - $(".propertiesContentRowGateSchedule", content).hide(); + activity.gateStopAtPrecedingActivity = $('.propertiesContentFieldStopAtPrecedingActivity', content).is(':checked'); } if (activity.gateType == 'password') { $(".propertiesContentRowGatePassword", content).show(); activity.password = $('.propertiesContentFieldPassword', content).val(); - } else { - $(".propertiesContentRowGatePassword", content).hide(); } // Gate can be input-based - var inputRow = $('.propertiesContentFieldInput', content).closest('tr'), - inputDefinitionRows = $('.propertiesContentRowConditions', content); if (activity.gateType == 'condition') { + var inputRow = $('.propertiesContentFieldInput', content).closest('tr'), + inputDefinitionRows = $('.propertiesContentRowConditions', content); + + activity.gateStopAtPrecedingActivity = $('.propertiesContentFieldStopAtPrecedingActivity', content).is(':checked'); + activity.input = inputRow.show().find('option:selected').data('input'); if (activity.input) { inputDefinitionRows.show(); } else { - inputDefinitionRows.hide(); + $('.propertiesContentFieldStopAtPrecedingActivity', content).closest('tr').show(); } - } else { - inputRow.hide(); - inputDefinitionRows.hide(); + } + + if (activity.gateType == 'permission') { + $(".propertiesContentRowPermission", content).show(); + activity.gateStopAtPrecedingActivity = $('.propertiesContentFieldStopAtPrecedingActivity', content).is(':checked'); } if (redrawNeeded) { @@ -277,8 +280,11 @@ .on('input', changeFunction); $('.propertiesContentFieldActivityCompletionBased', content) - .attr('checked', activity.gateActivityCompletionBased? 'checked' : null); + .attr('checked', activity.gateActivityCompletionBased ? 'checked' : null); + $('.propertiesContentFieldStopAtPrecedingActivity', content) + .attr('checked', activity.gateStopAtPrecedingActivity ? 'checked' : null); + $('.propertiesContentFieldPassword', content) .val(activity.password); Index: lams_common/src/java/org/lamsfoundation/lams/dbupdates/patch20210712.sql =================================================================== diff -u --- lams_common/src/java/org/lamsfoundation/lams/dbupdates/patch20210712.sql (revision 0) +++ lams_common/src/java/org/lamsfoundation/lams/dbupdates/patch20210712.sql (revision 73b16b1e6ae040974e8ba89abf3497abceb9420f) @@ -0,0 +1,15 @@ +-- Turn off autocommit, so nothing is committed if there is an error +SET AUTOCOMMIT = 0; +SET FOREIGN_KEY_CHECKS=0; +-- Put all sql statements below here + +--LDEV-5219 Add "stop-students-at-activity-before-gate" feature + +ALTER TABLE lams_learning_activity ADD COLUMN gate_stop_at_preceding_activity TINYINT NOT NULL DEFAULT 0 AFTER gate_password; + +-- Put all sql statements above here + +-- If there were no errors, commit and restore autocommit to on +COMMIT; +SET AUTOCOMMIT = 1; +SET FOREIGN_KEY_CHECKS=1; Index: lams_common/src/java/org/lamsfoundation/lams/learningdesign/GateActivity.java =================================================================== diff -u -r1ee503e3d0e0228ea8a45025fddf15d9623c0377 -r73b16b1e6ae040974e8ba89abf3497abceb9420f --- lams_common/src/java/org/lamsfoundation/lams/learningdesign/GateActivity.java (.../GateActivity.java) (revision 1ee503e3d0e0228ea8a45025fddf15d9623c0377) +++ lams_common/src/java/org/lamsfoundation/lams/learningdesign/GateActivity.java (.../GateActivity.java) (revision 73b16b1e6ae040974e8ba89abf3497abceb9420f) @@ -68,12 +68,15 @@ @Column(name = "gate_open_time") private Date gateOpenTime; + @Column(name = "gate_stop_at_preceding_activity") + private boolean gateStopAtPrecedingActivity; + /** * The learners who passed the gate. */ @ManyToMany @JoinTable(name = "lams_gate_allowed_learners", joinColumns = @JoinColumn(name = "activity_id"), inverseJoinColumns = @JoinColumn(name = "user_id")) - private Set allowedToPassLearners = new HashSet(); + private Set allowedToPassLearners = new HashSet<>(); /** full constructor */ public GateActivity(Long activityId, Integer id, String description, String title, Integer xcoord, Integer ycoord, @@ -187,4 +190,12 @@ public void setAllowedToPassLearners(Set allowedToPassLearners) { this.allowedToPassLearners = allowedToPassLearners; } + + public boolean isGateStopAtPrecedingActivity() { + return gateStopAtPrecedingActivity; + } + + public void setGateStopAtPrecedingActivity(boolean stopAtPrecedingActivity) { + this.gateStopAtPrecedingActivity = stopAtPrecedingActivity; + } } \ No newline at end of file Index: lams_common/src/java/org/lamsfoundation/lams/learningdesign/dto/AuthoringActivityDTO.java =================================================================== diff -u -r2a60aefd13ef4aac8e67f7e23ff837062aa837d9 -r73b16b1e6ae040974e8ba89abf3497abceb9420f --- lams_common/src/java/org/lamsfoundation/lams/learningdesign/dto/AuthoringActivityDTO.java (.../AuthoringActivityDTO.java) (revision 2a60aefd13ef4aac8e67f7e23ff837062aa837d9) +++ lams_common/src/java/org/lamsfoundation/lams/learningdesign/dto/AuthoringActivityDTO.java (.../AuthoringActivityDTO.java) (revision 73b16b1e6ae040974e8ba89abf3497abceb9420f) @@ -176,6 +176,8 @@ private Boolean gateActivityCompletionBased; + private boolean gateStopAtPrecedingActivity; + private String gatePassword; private Boolean applyGrouping; @@ -451,6 +453,7 @@ GateActivity gateActivity = (GateActivity) activity; gateActivityLevelID = gateActivity.getGateActivityLevelId(); gateOpen = gateActivity.getGateOpen(); + gateStopAtPrecedingActivity = gateActivity.isGateStopAtPrecedingActivity(); adminURL = gateActivity.getSystemTool().getAdminUrl(); } @@ -578,6 +581,14 @@ this.gateActivityCompletionBased = gateActivityCompletionBased; } + public boolean isGateStopAtPrecedingActivity() { + return gateStopAtPrecedingActivity; + } + + public void setGateStopAtPrecedingActivity(boolean gateStopAtPrecedingActivity) { + this.gateStopAtPrecedingActivity = gateStopAtPrecedingActivity; + } + public String getGatePassword() { return gatePassword; } Index: lams_common/src/java/org/lamsfoundation/lams/util/AuthoringJsonTags.java =================================================================== diff -u -r2a60aefd13ef4aac8e67f7e23ff837062aa837d9 -r73b16b1e6ae040974e8ba89abf3497abceb9420f --- lams_common/src/java/org/lamsfoundation/lams/util/AuthoringJsonTags.java (.../AuthoringJsonTags.java) (revision 2a60aefd13ef4aac8e67f7e23ff837062aa837d9) +++ lams_common/src/java/org/lamsfoundation/lams/util/AuthoringJsonTags.java (.../AuthoringJsonTags.java) (revision 73b16b1e6ae040974e8ba89abf3497abceb9420f) @@ -86,6 +86,7 @@ public static final String GATE_START_OFFSET = "gateStartTimeOffset"; public static final String GATE_END_OFFSET = "gateEndTimeOffset"; public static final String GATE_ACTIVITY_COMPLETION_BASED = "gateActivityCompletionBased"; + public static final String GATE_STOP_AT_PRECEDING_ACTIVITY = "gateStopAtPrecedingActivity"; public static final String GATE_PASSWORD = "gatePassword"; /** Grouping Activity specific tags */