Index: lams_central/src/java/org/lamsfoundation/lams/authoring/ObjectExtractor.java
===================================================================
diff -u -r10c87fd05c34bda4f1695bb872296803ab77faa0 -raa19ce90c4ed489336e8d4ab26ab432f2ef91501
--- lams_central/src/java/org/lamsfoundation/lams/authoring/ObjectExtractor.java (.../ObjectExtractor.java) (revision 10c87fd05c34bda4f1695bb872296803ab77faa0)
+++ lams_central/src/java/org/lamsfoundation/lams/authoring/ObjectExtractor.java (.../ObjectExtractor.java) (revision aa19ce90c4ed489336e8d4ab26ab432f2ef91501)
@@ -2736,7 +2736,7 @@
Long entryId = JsonUtil.optLong(details, AuthoringJsonTags.BRANCH_ACTIVITY_ENTRY_ID);
Integer entryUIID = details.getInt(AuthoringJsonTags.BRANCH_ACTIVITY_ENTRY_UIID);
- Integer sequenceActivityUIID = details.getInt(AuthoringJsonTags.BRANCH_SEQUENCE_ACTIVITY_UIID);
+ Integer sequenceActivityUIID = (Integer) JsonUtil.opt(details, AuthoringJsonTags.BRANCH_SEQUENCE_ACTIVITY_UIID);
Boolean gateOpenWhenConditionMet = (Boolean) JsonUtil.opt(details,
AuthoringJsonTags.BRANCH_GATE_OPENS_WHEN_CONDITION_MET);
Integer branchingActivityUIID = null;
Index: lams_central/web/author2.jsp
===================================================================
diff -u -r10c87fd05c34bda4f1695bb872296803ab77faa0 -raa19ce90c4ed489336e8d4ab26ab432f2ef91501
--- lams_central/web/author2.jsp (.../author2.jsp) (revision 10c87fd05c34bda4f1695bb872296803ab77faa0)
+++ lams_central/web/author2.jsp (.../author2.jsp) (revision aa19ce90c4ed489336e8d4ab26ab432f2ef91501)
@@ -226,9 +226,9 @@
Delay:
@@ -393,6 +409,16 @@
|
+
Match conditions to branches
|
Index: lams_central/web/includes/javascript/authoring/authoringActivity.js
===================================================================
diff -u -r10c87fd05c34bda4f1695bb872296803ab77faa0 -raa19ce90c4ed489336e8d4ab26ab432f2ef91501
--- lams_central/web/includes/javascript/authoring/authoringActivity.js (.../authoringActivity.js) (revision 10c87fd05c34bda4f1695bb872296803ab77faa0)
+++ lams_central/web/includes/javascript/authoring/authoringActivity.js (.../authoringActivity.js) (revision aa19ce90c4ed489336e8d4ab26ab432f2ef91501)
@@ -95,6 +95,8 @@
this.gateActivityCompletionBased = gateActivityCompletionBased;
};
+ // mapping between tool output and gate states ("branches"), if applicable
+ this.conditionsToBranches = [];
this.transitions = {
'from' : [],
'to' : []
@@ -157,12 +159,20 @@
/**
* Represents a subsequence of activities. It is not displayed on canvas.
*/
- BranchActivity : function(id, uiid, title, branchingActivity, transitionFrom) {
+ BranchActivity : function(id, uiid, title, branchingActivity, transitionFrom, defaultBranch) {
this.id = +id || null;
this.uiid = +uiid || ++layout.ld.maxUIID;
this.title = title || ('Branch ' + (branchingActivity.branches.length + 1));
this.branchingActivity = branchingActivity;
this.transitionFrom = transitionFrom;
+ this.defaultBranch = defaultBranch;
+ if (defaultBranch) {
+ this.defaultBranch = true;
+ // there can be only one default branch
+ $.each(branchingActivity.branches, function(){
+ this.defaultBranch = false;
+ });
+ }
},
@@ -671,7 +681,7 @@
});
if (!branch) {
// create a new branch
- branch = new ActivityLib.BranchActivity(null, null, branchData, fromActivity.branchingActivity);
+ branch = new ActivityLib.BranchActivity(null, null, branchData, fromActivity.branchingActivity, false);
}
}
@@ -688,6 +698,9 @@
branch.transitionFrom = transition;
transition.branch = branch;
fromActivity.branchingActivity.branches.push(branch);
+ if (fromActivity.branchingActivity.branches.length == 1) {
+ branch.defaultBranch = true;
+ }
}
setModified(true);
@@ -709,20 +722,27 @@
// remove corresponding branch
var branches = transition.branch.branchingActivity.branches;
branches.splice(branches.indexOf(transition.branch), 1);
+
+ if (transition.branch.defaultBranch && branches.length > 0) {
+ // reset the first branch as the default one
+ branches[0].defaultBranch = true;
+ }
}
if (!redraw){
// remove grouping or input references if chain was broken by the removed transition
$.each(layout.activities, function(){
var coreActivity = this.branchingActivity || this;
if (coreActivity.grouping || coreActivity.input) {
- var candidate = this,
+ var candidate = this.branchingActivity ? coreActivity.start : this,
groupingFound = false,
inputFound = false;
do {
if (candidate.transitions && candidate.transitions.to.length > 0) {
candidate = candidate.transitions.to[0].fromActivity;
- } else if (candidate.parentActivity) {
+ } else if (candidate.branchingActivity && !candidate.isStart) {
+ candidate = candidate.branchingActivity.start;
+ } else if (!candidate.branchingActivity && candidate.parentActivity) {
candidate = candidate.parentActivity;
} else {
candidate = null;
Index: lams_central/web/includes/javascript/authoring/authoringGeneral.js
===================================================================
diff -u -r10c87fd05c34bda4f1695bb872296803ab77faa0 -raa19ce90c4ed489336e8d4ab26ab432f2ef91501
--- lams_central/web/includes/javascript/authoring/authoringGeneral.js (.../authoringGeneral.js) (revision 10c87fd05c34bda4f1695bb872296803ab77faa0)
+++ lams_central/web/includes/javascript/authoring/authoringGeneral.js (.../authoringGeneral.js) (revision aa19ce90c4ed489336e8d4ab26ab432f2ef91501)
@@ -903,6 +903,7 @@
null, null, 0, 0, null, null, branchingEdge.branchingActivity);
layout.activities.push(branchingEdge);
+ branchingEdge.branchingActivity.defaultActivityUIID = activityData.defaultActivityUIID;
if (branchingType == 'optional'){
branchingEdge.branchingActivity.minOptions = activityData.minOptions;
branchingEdge.branchingActivity.maxOptions = activityData.maxOptions;
@@ -978,10 +979,19 @@
&& this.branchingActivity.id == branchingID){
var branchingActivity = this.branchingActivity;
branchingActivity.branches = branches;
+ var defaultBranchSet = false;
$.each(branches, function(){
this.branchingActivity = branchingActivity;
+ if (branchingActivity.defaultActivityUIID == this.uiid && !defaultBranchSet){
+ this.defaultBranch = true;
+ defaultBranchSet = true;
+ }
});
+ branchingActivity.defaultActivityUIID = null;
+ if (!defaultBranchSet && branches.length > 0) {
+ branches[0].defaultBranch = true;
+ }
return false;
}
});
@@ -1053,9 +1063,10 @@
// apply group -> branch mappings
$.each(ld.branchMappings, function(){
var entry = this,
- group = null,
input = null,
- branch = null;
+ group = null,
+ branch = null,
+ gate = null;
$.each(layout.activities, function(){
// is it the branch we're looking for?
if (this instanceof ActivityLib.BranchingEdgeActivity && this.isStart) {
@@ -1073,32 +1084,46 @@
return false;
}
});
+ }
+ // is it the gate we're looking for
+ else if (this instanceof ActivityLib.GateActivity && entry.gateActivityUIID == this.uiid) {
+ gate = this;
} else if (entry.condition && entry.condition.toolActivityUIID == this.uiid) {
input = this;
}
// found both, no need to continue iteration
- if (branch && (group || input)) {
+ if ((gate || branch) && (input || group)) {
return false;
}
});
- if (branch) {
- if (group) {
+ if (group) {
+ if (branch) {
branch.branchingActivity.groupsToBranches.push({
'id' : entry.entryID,
'uiid' : entry.entryUIID,
'group' : group,
'branch' : branch
});
- } else if (input) {
+ }
+ } else if (input) {
+ if (branch) {
branch.branchingActivity.input = input;
branch.branchingActivity.conditionsToBranches.push({
'id' : entry.entryID,
'uiid' : entry.entryUIID,
'condition' : entry.condition,
'branch' : branch
});
+ } else if (gate) {
+ gate.input = input;
+ gate.conditionsToBranches.push({
+ 'id' : entry.entryID,
+ 'uiid' : entry.entryUIID,
+ 'condition' : entry.condition,
+ 'branch' : entry.gateOpenWhenConditionMet ? 'open' : 'closed'
+ });
}
}
});
@@ -1219,10 +1244,11 @@
if (this instanceof ActivityLib.BranchingEdgeActivity){
if (this.isStart){
var branchingActivity = this.branchingActivity;
+ branchingActivity.defaultActivityUIID = null;
layoutActivities.push(branchingActivity);
$.each(branchingActivity.branches, function(branchOrderID){
- if (!branchingActivity.defaultActivityUIID) {
+ if (!branchingActivity.defaultActivityUIID && this.defaultBranch) {
branchingActivity.defaultActivityUIID = this.uiid;
}
this.defaultActivityUIID = null;
@@ -1249,6 +1275,11 @@
childActivity = childActivity.transitions.from[0].toActivity;
}
});
+
+ if (!branchingActivity.defaultActivityUIID && branchingActivity.branches.length > 0) {
+ branchingActivity.defaultActivityUIID = branchingActivity.branches[0].uiid;
+ branchingActivity.branches[0].defaultBranch = true;
+ }
}
} else {
layoutActivities.push(this);
@@ -1324,7 +1355,34 @@
case 'sync' : activityTypeID = 3; break;
case 'schedule' : activityTypeID = 4; break;
case 'permission' : activityTypeID = 5; break;
- case 'condition' : activityTypeID = 14; break;
+ case 'condition' :
+ activityTypeID = 14;
+
+ if (activity.input) {
+ $.each(activity.conditionsToBranches, function(index){
+ if (!this.branch) {
+ return true;
+ }
+
+ var condition = this.condition;
+ if (condition) {
+ condition.orderID = index + 1;
+ if (condition.exactMatchValue) {
+ condition.startValue = condition.endValue = null;
+ }
+ }
+
+ branchMappings.push({
+ 'entryID' : this.id,
+ 'entryUIID' : this.uiid,
+ 'gateActivityUIID' : activity.uiid,
+ 'gateOpenWhenConditionMet' : this.branch == 'open',
+ 'condition' : condition
+ });
+ });
+ }
+
+ break;
}
} else if (activity instanceof ActivityLib.ParallelActivity) {
activityTypeID = 6;
@@ -1342,11 +1400,12 @@
// no break, so fall to 'tool'
case 'tool' :
activityTypeID = activityTypeID || 12;
- var branchMappingCopy = branchMappingCopy || activity.conditionsToBranches.slice(),
- // yes, yes, a lousy construction
- branchMapping = branchMapping || (activity.conditionsToBranches = []);
if (activity.defaultActivityUIID && (activityTypeID == 11 || activity.input)) {
+ var branchMappingCopy = branchMappingCopy || activity.conditionsToBranches.slice(),
+ // yes, yes, a lousy construction
+ branchMapping = branchMapping || (activity.conditionsToBranches = []);
+
$.each(branchMappingCopy, function(index){
if (activity.branches.indexOf(this.branch) == -1){
return true;
Index: lams_central/web/includes/javascript/authoring/authoringProperty.js
===================================================================
diff -u -r10c87fd05c34bda4f1695bb872296803ab77faa0 -raa19ce90c4ed489336e8d4ab26ab432f2ef91501
--- lams_central/web/includes/javascript/authoring/authoringProperty.js (.../authoringProperty.js) (revision 10c87fd05c34bda4f1695bb872296803ab77faa0)
+++ lams_central/web/includes/javascript/authoring/authoringProperty.js (.../authoringProperty.js) (revision aa19ce90c4ed489336e8d4ab26ab432f2ef91501)
@@ -76,10 +76,11 @@
}
]
});
+ // add to dialogs array so they can be easily closed at once
layout.dialogs.push(layout.items.groupNamingDialog);
- // initialise dialog from matching groups to branches in branching activities
+ // initialise dialog for matching groups to branches in branching activities
var gtbDialog = layout.items.groupsToBranchesMappingDialog = $('#branchMappingDialog')
.clone()
.attr('id','gtbDialog')
@@ -100,7 +101,8 @@
'click' : function() {
var dialog = $(this),
branchingActivity = dialog.dialog('option', 'branchingActivity'),
- assignedToDefault = false;
+ assignedToDefault = false,
+ defaultBranch = null;
// find references to groups and branches
branchingActivity.groupsToBranches = [];
@@ -119,7 +121,20 @@
}
});
} else {
- branch = branchingActivity.branches[0];
+ if (!defaultBranch) {
+ $.each(branchingActivity.branches, function(){
+ if (this.defaultBranch) {
+ defaultBranch = this;
+ return false;
+ }
+ });
+ // fall back to first branch
+ if (!defaultBranch) {
+ defaultBranch = branchingActivity.branches[0];
+ defaultBranch.defaultBranch = true;
+ }
+ }
+ branch = defaultBranch;
assignedToDefault = true;
}
@@ -148,6 +163,7 @@
]
});
+ // initialise buttons and labels
$('.branchMappingAddButton', gtbDialog).button({
'icons' : {
'primary' : 'ui-icon-seek-next'
@@ -170,6 +186,7 @@
layout.dialogs.push(gtbDialog);
+ // initialise dialog for defining input conditions
var outputConditionsDialog = layout.items.outputConditionsDialog = $('#outputConditionsDialog').dialog({
'autoOpen' : false,
'modal' : true,
@@ -186,10 +203,12 @@
'class' : 'outputSelectDependent rangeOutputButton',
'text' : 'Clear all',
'click' : function() {
+ // remove all range conditions
var rows = $('#rangeConditions td', this).closest('tr');
rows.each(function(){
+ // check for conditions already linked to branches/gate states
if ($(this).data('mappingEntry').branch) {
- if (confirm('There are conditions linked to an existing branch.\nDo you wish to remove them?')) {
+ if (!confirm('There are conditions linked to an existing branch.\nDo you wish to remove them?')) {
rows = null;
}
return false;
@@ -205,6 +224,7 @@
'class' : 'outputSelectDependent rangeOutputButton',
'text' : 'Remove',
'click' : function() {
+ // remove the selected range condition
var selected = $('#rangeConditions tr.selected', this);
if (!selected.data('mappingEntry').branch
|| confirm('This condition is linked to an existing branch.\nDo you wish to remove it?')) {
@@ -216,8 +236,9 @@
'class' : 'outputSelectDependent complexOutputButton',
'text' : 'Refresh',
'click' : function() {
+ // get output definitions again
$(this).dialog('option', 'refreshDefinitions')();
- $(this).dialog('option', 'buildContent')();
+ $(this).dialog('option', 'buildContent')(true);
}
},
{
@@ -233,21 +254,25 @@
var dialog = $(this),
activity = dialog.dialog('option', 'parentObject');
+ // extract created mappings from UI
if (activity instanceof ActivityLib.BranchingActivity) {
activity.conditionsToBranches = [];
$('#rangeConditions tr, #complexConditions li', dialog).each(function(){
+ // if it's hidden, then another output was selected, so skip it
var mappingEntry = $(this).is(':visible') ? $(this).data('mappingEntry') : null;
if (!mappingEntry) {
return true;
}
+ // new UIID for new conditions
if (!mappingEntry.uiid) {
mappingEntry.uiid = ++layout.ld.maxUIID;
}
if (!mappingEntry.condition.conditionUIID) {
mappingEntry.condition.conditionUIID = ++layout.ld.maxUIID;
}
+ // range conditions can have their names changed
var input = $('input', this);
if (input.length > 0) {
mappingEntry.condition.displayName = input.val();
@@ -257,6 +282,7 @@
}
dialog.dialog('close');
+ // go straight to mapping dialog
PropertyLib.openConditionsToBranchesMappingDialog(activity);
}
}
@@ -267,8 +293,12 @@
}
});
+ // define utility methods as dialog "options" for encapsulation, ease of access
outputConditionsDialog.dialog('option',
{
+ /**
+ * Get output definitions from Tool activity
+ */
'refreshDefinitions' : function(){
var dialog = layout.items.outputConditionsDialog,
activity = dialog.dialog('option', 'parentObject');
@@ -289,20 +319,26 @@
},
- 'buildContent' : function() {
+ /**
+ * Link output data to UI widgets
+ */
+ 'buildContent' : function(useDefaultConditions) {
var dialog = layout.items.outputConditionsDialog,
activity = dialog.dialog('option', 'parentObject'),
outputSelect = $('#outputSelect', dialog),
emptyOption = $('option[value="none"]', outputSelect).attr('selected', 'selected'),
+ // conditions can have names like "output.name#6", but real output names do not have a suffix
outputName = activity.conditionsToBranches && activity.conditionsToBranches.length > 0
? activity.conditionsToBranches[0].condition.name.split('#')[0] : null;
+ // remove all previously defined outputs
$('option[value!="none"]', outputSelect).remove();
if (!activity.input.outputDefinitions) {
dialog.dialog('option', 'refreshDefinitions')();
}
if (activity.input.outputDefinitions) {
+ // build output dropdown and bind data to each option
$.each(activity.input.outputDefinitions,function(){
var suffix = '';
switch(this.type) {
@@ -320,25 +356,30 @@
.text(this.description + suffix)
.data('output', this)
.appendTo(outputSelect);
+ // select the output for which mappings were already defined
if (this.name == outputName) {
option.attr('selected', 'selected');
emptyOption.attr('selected', null);
}
});
}
- dialog.dialog('option', 'outputChange')();
+ dialog.dialog('option', 'outputChange')(useDefaultConditions);
},
- 'outputChange' : function(){
+ /**
+ * Rebuild dialog content based on selected output
+ */
+ 'outputChange' : function(useDefaultConditions){
var dialog = layout.items.outputConditionsDialog,
container = dialog.closest('.ui-dialog'),
activity = dialog.dialog('option', 'parentObject'),
outputOption = $('#outputSelect option:selected', dialog),
output = outputOption.data('output');
$('.outputSelectDependent', container).hide();
+ // no output = "none" option was selected
if (!output) {
return;
}
@@ -348,25 +389,54 @@
complexOutputWidgets = $('.complexOutputButton', container).add(complexConditionNames),
rangeOutputWidgets = $('#rangeOptionSelect, .rangeOutputButton', container).add(rangeConditionNames);
if (output.showConditionNameOnly) {
+ // complex, i.e. user defined conditions
complexOutputWidgets.show();
- var list = $('ul', complexConditionNames);
+ // build a list with immutable conditoon names
+ var list = $('ul', complexConditionNames),
+ entries = [];
$('li', list).remove();
-
- if (output.defaultConditions){
- $.each(output.defaultConditions, function(){
- $('').text(this.displayName)
- .data('mappingEntry', {
- 'condition' : {
- 'name' : this.name,
- 'displayName' : this.displayName,
- 'type' : 'OUTPUT_COMPLEX',
- 'toolActivityUIID' : output.toolActivityUIID
- }
- })
- .appendTo(list);
- });
+
+ // see if there are existing mappings; if so, use conditions name from there instead from tool activity's output
+ $.each(activity.conditionsToBranches, function(){
+ if (this.branch && output.name == this.condition.name.split('#')[0]) {
+ entries.push(this);
+ }
+ });
+
+ // if user choosed to refresh the conditions and there are existing mappings, ask him to confirm
+ if (entries.length == 0
+ || (useDefaultConditions
+ && confirm('You are about to update your conditions for the selected output definition.\n'
+ + 'This will clear all links to existing branches.\nDo you wish to continue?'))) {
+ if (entries.length > 0) {
+ // clear existing mappings
+ entries = [];
+ activity.conditionsToBranches = [];
+ }
+
+ if (output.defaultConditions) {
+ // build list using conditions from Tool activity output definitions
+ $.each(output.defaultConditions, function(){
+ entries.push({
+ 'condition' : {
+ 'name' : this.name,
+ 'displayName' : this.displayName,
+ 'type' : 'OUTPUT_COMPLEX',
+ 'conditionID' : this.conditionId,
+ 'toolActivityUIID' : output.toolActivityUIID
+ }
+ });
+ });
+ }
}
+
+ $.each(entries, function(){
+ $('').text(this.condition.displayName)
+ .data('mappingEntry', this)
+ .appendTo(list);
+ });
} else {
+ // show menu and list of range conditions
rangeOutputWidgets.show();
outputConditionsDialog.dialog('option', 'rangeOptionChange')();
@@ -375,6 +445,7 @@
$.each(activity.conditionsToBranches, function(){
if (output.toolActivityUIID == this.condition.toolActivityUIID
&& output.name == this.condition.name) {
+ // set start and end values for easier validation of collapsing ranges
if (this.condition.exactMatchValue) {
this.condition.startValue = this.condition.endValue = this.condition.exactMatchValue;
}
@@ -385,6 +456,10 @@
}
},
+
+ /**
+ * Show widgets appropriate for given range definition
+ */
'rangeOptionChange' : function(){
var dialog = layout.items.outputConditionsDialog,
selectedOption = $('#rangeOptionSelect option:selected', dialog).attr('value');
@@ -405,6 +480,9 @@
},
+ /**
+ * Fill table of existing range conditions
+ */
'addRangeConditionRow' : function(mappingEntry){
var condition = mappingEntry.condition;
if (condition.type != 'OUTPUT_LONG') {
@@ -424,17 +502,19 @@
}
var row = $('