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 @@ - Branches + - Branch + @@ -256,6 +256,14 @@ + + + Default? + + + + + @@ -371,6 +379,14 @@ + + + Input (Tool): + + + + + Delay: @@ -393,6 +409,16 @@ + + +
Create conditions
+ + + + +
Map gate conditions
+ + @@ -436,12 +462,12 @@ - +
Create conditions
- +
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 = $('').appendTo(rangeConditionNames).data('mappingEntry', mappingEntry).click(function(){ + // highlight the row $(this).addClass('selected').siblings('tr').removeClass('selected'); }), nameCell = $('').appendTo(row), - nameInput = $('').val(condition.displayName).appendTo(nameCell), conditionCell = $('').text(conditionText).appendTo(row); + $('').val(condition.displayName).appendTo(nameCell); } }); - - $('#outputSelect', outputConditionsDialog).change(outputConditionsDialog.dialog('option', 'outputChange')); + // assign handlers for events + $('#outputSelect', outputConditionsDialog).change(function(){outputConditionsDialog.dialog('option', 'outputChange')()}); $('#rangeOptionSelect', outputConditionsDialog).change(outputConditionsDialog.dialog('option', 'rangeOptionChange')); + // add a new range condition $('#rangeAddButton', outputConditionsDialog).button().click(function(){ var dialog = layout.items.outputConditionsDialog, rangeConditionNames = $('#rangeConditions', dialog), @@ -465,6 +545,7 @@ $('td', rangeConditionNames).closest('tr').each(function(){ var existingCondition = $(this).data('mappingEntry').condition; + // validate the new condition so it does not overlap with an existing one if ((typeof condition.startValue == 'undefined' && existingCondition.startValue <= condition.endValue) || (typeof condition.endValue == 'undefined' && (typeof existingCondition.endValue == 'undefined' || existingCondition.endValue >= condition.startValue)) @@ -488,6 +569,7 @@ return; } + // find an unique name for the new condition var nameIndex = 1; while (!condition.displayName) { condition.displayName = 'Untitled ' + nameIndex; @@ -502,14 +584,16 @@ dialog.dialog('option', 'addRangeConditionRow')({'condition' : condition}); }); + + // initialise spinner widgets $('#singleRangeSpinner, #multiRangeFromSpinner, #multiRangeToSpinner', outputConditionsDialog).spinner({ 'min' : 0, }).spinner('value', 0); layout.dialogs.push(outputConditionsDialog); - // initialise dialog for matching conditions to branches in branching activities + // initialise dialog for matching conditions to branches/gate states in branching/gate activities var ctbDialog = layout.items.conditionsToBranchesMappingDialog = $('#branchMappingDialog') .clone() .attr('id','ctbDialog') @@ -523,52 +607,89 @@ }, 'width' : 800, 'height' : 400, - 'title' : 'Match Conditions to Branches', 'buttons' : [ { 'text' : 'OK', 'click' : function() { - var dialog = $(this), - branchingActivity = dialog.dialog('option', 'branchingActivity'), - assignedToDefault = false; - - $.each(branchingActivity.conditionsToBranches, function(){ - var mappingEntry = this; - mappingEntry.branch = null; - // find references to conditions and branches - $('.branchMappingBoundItemCell div', dialog).each(function(){ - var entryUIID = +$(this).attr('uiid'), - branchUIID = +$(this).data('boundItem').attr('uiid'); - - if (entryUIID == mappingEntry.uiid) { - $.each(branchingActivity.branches, function(){ - if (branchUIID == this.uiid) { - mappingEntry.branch = this; - return false; - } - }); - return false; - } - }); - - if (!mappingEntry.branch) { - assignedToDefault = true; - mappingEntry.branch = branchingActivity.branches[0]; - } - }); - - - if (assignedToDefault){ - alert('All remaining conditions will be mapped to the default branch'); - } - - dialog.dialog('close'); - setModified(true); + $(this).dialog('close'); } } - ] + ], + + /** + * This event can be triggered either by "OK" button or cross in the dialog's upper right corner + */ + 'beforeClose' : function(event) { + var dialog = $(this), + activity = dialog.dialog('option', 'activity'), + isGate = activity instanceof ActivityLib.GateActivity, + assignedToDefault = false, + defaultBranch = isGate ? 'closed' : null, + close = true; + + // see what was mapped + $.each(activity.conditionsToBranches, function(){ + var mappingEntry = this; + mappingEntry.branch = null; + // find references to conditions and branches + $('.branchMappingBoundItemCell div', dialog).each(function(){ + if (mappingEntry.uiid != +$(this).attr('uiid')) { + return true; + } + + // same dialog works for both branching and gate activities, but mapping is done slightly different + if (isGate) { + mappingEntry.branch = $(this).data('boundItem').attr('gateState'); + } else { + var branchUIID = +$(this).data('boundItem').attr('uiid'); + $.each(activity.branches, function(){ + if (branchUIID == this.uiid) { + mappingEntry.branch = this; + return false; + } + }); + } + return false; + }); + + // a condition was not mapped, so map it to the default branch + if (!mappingEntry.branch) { + if (!defaultBranch) { + $.each(activity.branches, function(){ + if (this.defaultBranch) { + defaultBranch = this; + return false; + } + }); + // fall back to first branch + if (!defaultBranch) { + defaultBranch = activity.branches[0]; + defaultBranch.defaultBranch = true; + } + } + + mappingEntry.branch = defaultBranch; + assignedToDefault = true; + } + }); + + // were any conditions assigned to the default branch? + if (assignedToDefault) { + close = confirm(isGate ? + "All remaining conditions will be mapped to the selected gate's closed state" + : "All remaining conditions will be mapped to the default branch"); + } + + if (close) { + setModified(true); + } + + // if false, the dialog will not close + return close; + } }); + // initialise the dialog buttons $('.branchMappingAddButton', ctbDialog).button({ 'icons' : { 'primary' : 'ui-icon-seek-next' @@ -591,6 +712,10 @@ layout.dialogs.push(ctbDialog); }, + + /** + * Opens properties dialog with the contents specific for each activity + */ openPropertiesDialog : function(object) { object.loadPropertiesDialogContent(); var dialog = layout.items.propertiesDialog; @@ -623,6 +748,13 @@ .show().data('parentObject', transition); $('.propertiesContentFieldTitle', content).val(transition.title); + var defaultBranch = $('.propertiesContentFieldDefault', content); + if (transition.branch) { + defaultBranch.show(); + } else { + defaultBranch.hide(); + } + $('input', content).change(function(){ // extract changed properties and redraw the transition var content = $(this).closest('.dialogContainer'), @@ -641,13 +773,27 @@ } } + if (transition.branch) { + transition.branch.defaultBranch = $('.propertiesContentFieldDefault', content).is(':checked'); + if (transition.branch.defaultBranch) { + $.each(transition.branch.branchingActivity.branches, function(){ + if (this != transition.branch) { + this.defaultBranch = false; + } + }); + } + } + if (redrawNeeded) { transition.draw(); ActivityLib.addSelectEffect(activity, true); setModified(true); } }); } + + $('.propertiesContentFieldDefault', content).attr('checked', + transition.branch && transition.branch.defaultBranch ? 'checked' : null); }, @@ -721,7 +867,8 @@ var content = $(this).closest('.dialogContainer'), activity = content.data('parentObject'), redrawNeeded = false, - newTitle = $('.propertiesContentFieldTitle', content).val(); + newTitle = $('.propertiesContentFieldTitle', content).val(), + newGroupCount = +$('.propertiesContentFieldGroupCount', content).val(); if (newTitle != activity.title) { if (!nameValidator.test(newTitle)) { alert('Grouping title can not contain any of these characters < > ^ * @ % $'); @@ -750,7 +897,10 @@ $('.propertiesContentFieldNameGroups', content).css('display', activity.groupDivide == 'groups' ? '' : 'none'); - activity.groupCount = +$('.propertiesContentFieldGroupCount', content).val(); + if (activity.groupCount != newGroupCount){ + activity.groupCount = newGroupCount; + activity.groups = PropertyLib.fillNameAndUIIDList(activity.groupCount, activity.groups, 'name', 'Group '); + } activity.learnerCount = +$('.propertiesContentFieldLearnerCount', content).val(); activity.equalSizes = $('.propertiesContentFieldEqualSizes', content).is(':checked'); activity.viewLearners = $('.propertiesContentFieldViewLearners', content).is(':checked'); @@ -814,6 +964,13 @@ $('.propertiesContentFieldTitle', content).val(activity.title); $('.propertiesContentFieldGateType', content).val(activity.gateType); + $('.propertiesContentFieldCreateConditions', content).button().click(function(){ + PropertyLib.openOutputConditionsDialog(activity); + }); + $('.propertiesContentFieldMatchConditions', content).button().click(function(){ + PropertyLib.openConditionsToBranchesMappingDialog(activity); + }); + // make onChange function a local variable, because it's used several times var changeFunction = function(){ // extract changed properties and redraw the activity @@ -840,6 +997,20 @@ $(".propertiesContentRowGateSchedule").hide(); } + var inputRow = $('.propertiesContentFieldInput', content).closest('tr'), + inputDefinitionRows = $('.propertiesContentRowConditions', content); + if (activity.gateType == 'condition') { + activity.input = inputRow.show().find('option:selected').data('input'); + if (activity.input) { + inputDefinitionRows.show(); + } else { + inputDefinitionRows.hide(); + } + } else { + inputRow.hide(); + inputDefinitionRows.hide(); + } + if (redrawNeeded) { activity.draw(); ActivityLib.addSelectEffect(activity, true); @@ -871,6 +1042,7 @@ .attr('checked', activity.gateActivityCompletionBased? 'checked' : null); $('input, select', content).change(changeFunction); + PropertyLib.fillToolInputDropdown(activity, activity.input); changeFunction.call(content); } @@ -882,6 +1054,8 @@ $('.propertiesContentFieldActivityCompletionBased', content) .attr('disabled', null); } + + PropertyLib.fillToolInputDropdown(activity, activity.input); }, @@ -908,9 +1082,9 @@ 'max' : activity.branchingActivity.branches.length }); if (activity.branchingActivity.branches.length == 0) { - $('.propertiesContentFieldCreateConditions, .propertiesContentFieldMatchConditions,'+ - '.propertiesContentFieldMatchGroups', content) - .closest('tr').hide(); + $('.propertiesContentRowConditions', content) + .add($('.propertiesContentFieldMatchGroups', content).closest('tr')) + .hide(); } } @@ -951,14 +1125,12 @@ .find('option:selected').data('grouping'); } else { groupingRow.hide(); - branchingActivity.grouping = null; } $('.propertiesContentFieldMatchGroups', content).closest('tr') .css('display', branchingActivity.grouping && branchingActivity.branches.length > 0 ? '' : 'none'); var inputRow = $('.propertiesContentFieldInput', content).closest('tr'), - inputDefinitionRows = $('.propertiesContentFieldCreateConditions, .propertiesContentFieldMatchConditions', content) - .closest('tr'); + inputDefinitionRows = $('.propertiesContentRowConditions', content); if (branchingActivity.branchingType == 'tool') { branchingActivity.input = inputRow.show() .find('option:selected').data('input'); @@ -970,7 +1142,6 @@ } else { inputRow.hide(); inputDefinitionRows.hide(); - branchingActivity.input = null; } var optionalSequenceRows = $('.spinner', content).closest('tr'); @@ -1243,11 +1414,13 @@ }); } else { // normal activities can use only preceeding groupings - var candidate = activity; + var candidate = activity.branchingActivity ? activity.branchingActivity.start : activity; 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; @@ -1281,12 +1454,14 @@ var emptyOption = $('