Index: lams_central/conf/language/lams/ApplicationResources.properties =================================================================== diff -u -rdcb7977d20f0d29b809b2139a6814bc113c4485c -r0e442ec998f242b5d7874b92488fb86fa881bf5e --- lams_central/conf/language/lams/ApplicationResources.properties (.../ApplicationResources.properties) (revision dcb7977d20f0d29b809b2139a6814bc113c4485c) +++ lams_central/conf/language/lams/ApplicationResources.properties (.../ApplicationResources.properties) (revision 0e442ec998f242b5d7874b92488fb86fa881bf5e) @@ -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 -rdcb7977d20f0d29b809b2139a6814bc113c4485c -r0e442ec998f242b5d7874b92488fb86fa881bf5e --- lams_central/web/authoring/authoring.jsp (.../authoring.jsp) (revision dcb7977d20f0d29b809b2139a6814bc113c4485c) +++ lams_central/web/authoring/authoring.jsp (.../authoring.jsp) (revision 0e442ec998f242b5d7874b92488fb86fa881bf5e) @@ -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 -r1367c68bda1ff51ded26c5220a9a059fa67235f5 -r0e442ec998f242b5d7874b92488fb86fa881bf5e --- lams_central/web/includes/javascript/authoring/authoringActivity.js (.../authoringActivity.js) (revision 1367c68bda1ff51ded26c5220a9a059fa67235f5) +++ lams_central/web/includes/javascript/authoring/authoringActivity.js (.../authoringActivity.js) (revision 0e442ec998f242b5d7874b92488fb86fa881bf5e) @@ -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; + }, /**