Index: lams_central/conf/language/lams/ApplicationResources.properties =================================================================== diff -u -r0a66b57371500a885e7d2ad77907b4bee705f46b -r0c1f66c648e0405319e5061e1dcf85de077ee2f0 --- lams_central/conf/language/lams/ApplicationResources.properties (.../ApplicationResources.properties) (revision 0a66b57371500a885e7d2ad77907b4bee705f46b) +++ lams_central/conf/language/lams/ApplicationResources.properties (.../ApplicationResources.properties) (revision 0c1f66c648e0405319e5061e1dcf85de077ee2f0) @@ -511,6 +511,7 @@ authoring.fla.transition.place.prompt =Click on an activity authoring.fla.paste.error =Sorry, you can not paste this type of activity authoring.fla.preview.error =Error while initialising lesson for preview +authoring.fla.cross.branching.error =Cross-branching transitions are not allowed authoring.fla.ok.button =OK authoring.fla.cancel.button =Cancel authoring.fla.clear.all.button =Clear all Index: lams_central/web/authoring/authoring.jsp =================================================================== diff -u -r0a66b57371500a885e7d2ad77907b4bee705f46b -r0c1f66c648e0405319e5061e1dcf85de077ee2f0 --- lams_central/web/authoring/authoring.jsp (.../authoring.jsp) (revision 0a66b57371500a885e7d2ad77907b4bee705f46b) +++ lams_central/web/authoring/authoring.jsp (.../authoring.jsp) (revision 0c1f66c648e0405319e5061e1dcf85de077ee2f0) @@ -102,7 +102,7 @@ RUN_SEQUENCES_FOLDER : '', ARRANGE_CONFIRM : '', CLEAR_CANVAS_CONFIRM : '', - BRANCHING_START_PLACE_PROMPT : '', + BRANCHING_START_PLACE_PROMPT : '', BRANCHING_END_PLACE_PROMPT : '', ANNOTATION_REGION_PLACE_PROMPT : '', ANNOTATION_LABEL_PLACE_PROMPT : '', @@ -111,6 +111,7 @@ TRANSITION_PLACE_PROMPT : '', PASTE_ERROR : '', PREVIEW_ERROR : '', + CROSS_BRANCHING_ERROR : '', // PropertyLib OK_BUTTON : '', Index: lams_central/web/includes/javascript/authoring/authoringActivity.js =================================================================== diff -u -re15d2e51298e68fff7ee35cd7d85e34faf1951a2 -r0c1f66c648e0405319e5061e1dcf85de077ee2f0 --- lams_central/web/includes/javascript/authoring/authoringActivity.js (.../authoringActivity.js) (revision e15d2e51298e68fff7ee35cd7d85e34faf1951a2) +++ lams_central/web/includes/javascript/authoring/authoringActivity.js (.../authoringActivity.js) (revision 0c1f66c648e0405319e5061e1dcf85de077ee2f0) @@ -817,6 +817,15 @@ * Draws a transition between two activities. */ addTransition : function(fromActivity, toActivity, redraw, id, uiid, branchData) { + // check if a branching's start does not connect with another branching's end + if (fromActivity instanceof ActivityDefs.BranchingEdgeActivity + && toActivity instanceof ActivityDefs.BranchingEdgeActivity + && fromActivity.isStart && !toActivity.isStart + && fromActivity.branchingActivity != toActivity.branchingActivity) { + alert(LABELS.CROSS_BRANCHING_ERROR); + return; + } + // if a child activity was detected, use the parent activity as the target if (toActivity.parentActivity && toActivity.parentActivity instanceof DecorationDefs.Container){ toActivity = toActivity.parentActivity; @@ -838,33 +847,34 @@ return; } + // check for circular sequences + var activity = fromActivity; + do { + if (activity.transitions && activity.transitions.to.length > 0) { + activity = activity.transitions.to[0].fromActivity; + } else if (activity.branchingActivity && !activity.isStart) { + activity = activity.branchingActivity.start; + } else { + activity = null; + } + + if (toActivity == activity) { + alert(LABELS.CIRCULAR_SEQUENCE_ERROR); + return; + } + } while (activity); + // user chose to create outbound transition from an activity that already has one if (!redraw && fromActivity.transitions.from.length > 0 - && !(fromActivity instanceof ActivityDefs.BranchingEdgeActivity && fromActivity.isStart) - && !(toActivity instanceof ActivityDefs.BranchingEdgeActivity && toActivity.isStart)) { + && !(fromActivity instanceof ActivityDefs.BranchingEdgeActivity && fromActivity.isStart)) { if (confirm(LABELS.BRANCHING_CREATE_CONFIRM)) { ActivityLib.addBranching(fromActivity, toActivity); } return; } - // check for circular sequences - var candidate = fromActivity; - do { - if (candidate.transitions && candidate.transitions.to.length > 0) { - candidate = candidate.transitions.to[0].fromActivity; - } else if (candidate.branchingActivity && !candidate.isStart) { - candidate = candidate.branchingActivity.start; - } else { - candidate = null; - } - - if (toActivity == candidate) { - alert(LABELS.CIRCULAR_SEQUENCE_ERROR); - return; - } - } while (candidate != null); + // start building the transition // branchData can be either an existing branch or a title for the new branch var branch = branchData && branchData instanceof ActivityDefs.BranchActivity ? branchData : null, @@ -915,9 +925,107 @@ } } + + // after adding the transition, check for self-nested branching + activity = fromActivity; + var branchingActivity = null; + // find the top-most enveloping branching activity, if any + do { + if (activity.transitions && activity.transitions.to.length > 0) { + activity = activity.transitions.to[0].fromActivity; + + if (activity instanceof ActivityDefs.BranchingEdgeActivity) { + if (activity.isStart) { + // found the top branching the activity belongs to + branchingActivity = activity.branchingActivity; + } else { + // jump over nested branching + activity = activity.branchingActivity.start; + } + } + } else { + activity = null; + } + } while (activity); + + + if (branchingActivity) { + // look for all nested branchings + var nestedBranchings = ActivityLib.findNestedBranching(branchingActivity); + // check each of them + $.each(nestedBranchings, function(){ + var branching = this; + // check if one branching's end does not match with another branching's start + $.each(branching.end.transitions.to, function(){ + // crawl from end to start + var activity = this.fromActivity; + while (activity) { + if (activity instanceof ActivityDefs.BranchingEdgeActivity) { + if (activity.isStart) { + // this branching's end matches with its own start, all OK + if (activity.branchingActivity == branching) { + break; + } + // this branching's end does not match with own start, error + alert(LABELS.CROSS_BRANCHING_ERROR); + // remove the just added transition + ActivityLib.removeTransition(transition); + // tell the outer iteration loop to quit + transition = null; + return false; + } + // a nested branching encountered when crawling, just jump over it + activity = activity.branchingActivity.start; + } + // keep crawling + if (activity.transitions && activity.transitions.to.length > 0) { + activity = activity.transitions.to[0].fromActivity; + } else { + activity = null; + } + } + }); + + if (!transition) { + // there was an error, do not carry on + return false; + } + }); + } + GeneralLib.setModified(true); return transition; }, + + + findNestedBranching : function(branchingActivity) { + var nestedBranching = []; + $.each(branchingActivity.branches, function(){ + var activity = this.transitionFrom.toActivity; + while (activity) { + if (activity instanceof ActivityDefs.BranchingEdgeActivity) { + if (activity.branchingActivity == branchingActivity){ + break; + } + if (nestedBranching.indexOf(activity.branchingActivity) == -1) { + nestedBranching.push(activity.branchingActivity); + } + if (activity.isStart) { + nestedBranching = nestedBranching.concat(ActivityLib.findNestedBranching(activity.branchingActivity)); + activity = activity.branchingActivity.end; + } + } + + if (activity.transitions && activity.transitions.from.length > 0) { + activity = activity.transitions.from[0].toActivity; + } else { + activity = null; + } + } + }); + + return nestedBranching; + }, /**