Index: lams_central/web/author2.jsp
===================================================================
diff -u -rebe1058e6422f0e8ce4d72f37a130316da559d62 -ra3d8ca871cecdad8f45756fdcae6d697bd0e8499
--- lams_central/web/author2.jsp (.../author2.jsp) (revision ebe1058e6422f0e8ce4d72f37a130316da559d62)
+++ lams_central/web/author2.jsp (.../author2.jsp) (revision a3d8ca871cecdad8f45756fdcae6d697bd0e8499)
@@ -37,6 +37,9 @@
- |
- |
-
-
@@ -74,7 +76,9 @@
|
- |
+
+
+ |
Index: lams_central/web/css/authoring.css
===================================================================
diff -u -rebe1058e6422f0e8ce4d72f37a130316da559d62 -ra3d8ca871cecdad8f45756fdcae6d697bd0e8499
--- lams_central/web/css/authoring.css (.../authoring.css) (revision ebe1058e6422f0e8ce4d72f37a130316da559d62)
+++ lams_central/web/css/authoring.css (.../authoring.css) (revision a3d8ca871cecdad8f45756fdcae6d697bd0e8499)
@@ -1,11 +1,24 @@
-div.dialogContainer, .ldChoiceDependentCanvasElement {
- display: none;
+.ygtv-highlight1, .ygtv-highlight1 .ygtvlabel {
+ background-color: #dfeffc;
}
+a.ygtvspacer {
+ border-bottom: none;
+}
+
.ui-dialog {
font-size: 12px;
}
+div.dialogContainer, .ldChoiceDependentCanvasElement,
+.dialog-no-title .ui-dialog-titlebar {
+ display: none;
+}
+
+#infoDialog {
+ font-weight: bold;
+}
+
div.dialogTitle {
padding: 5px 0px 5px 0px;
font-weight: bold;
@@ -19,26 +32,18 @@
border-top: thin dotted #2E6E9E;
}
-a.ygtvspacer {
- border-bottom: none;
-}
-
-td#learningDesignTreeCell {
+div#openLearningDesignDialog td#learningDesignTreeCell {
padding: 2px 2px 0px 5px;
vertical-align: top;
width: 200px;
border-right: thin dotted #2E6E9E;
}
-div#learningDesignTree {
+div#openLearningDesignDialog div#learningDesignTree {
overflow: auto;
}
-.ygtv-highlight1, .ygtv-highlight1 .ygtvlabel {
- background-color: #dfeffc;
-}
-
-#recentlyUsedCell {
+div#openLearningDesignDialog #recentlyUsedCell {
height: 200px;
vertical-align: top;
border-top: thin dotted #2E6E9E;
@@ -49,18 +54,18 @@
text-align: center;
}
-td#canvasCell {
+div#openLearningDesignDialog td#canvasCell {
text-align: center;
padding: 10px 0px 0px 10px;
vertical-align: middle;
}
-div#canvasDiv {
+div#openLearningDesignDialog div#canvasDiv {
overflow: auto;
height: 665px;
}
-img#ldScreenshotLoading {
+div#openLearningDesignDialog img#ldScreenshotLoading {
padding-top: 200px;
}
@@ -96,23 +101,20 @@
width: 100%;
}
-td#layoutCell {
- width: 152px;
-}
-
#groupingButton span {
background: url('../images/icons/group.png') no-repeat 3px 3px;
padding-left: 25px;
}
td#templateContainerCell {
+ width: 152px;
border: black thin solid;
vertical-align: top;
background-color: rgb(219, 230, 252);
}
div#templateContainer {
- height: 800px;
+ height: 745px;
overflow: auto;
}
@@ -133,6 +135,13 @@
font-size: 10pt;
}
+#canvas {
+ overflow: auto;
+ width: 100%;
+ height: 745px;
+ vertical-align: top;
+}
+
div.propertiesDialog {
font-size: 12px;
}
Index: lams_central/web/includes/javascript/authoring/authoringActivity.js
===================================================================
diff -u -rebe1058e6422f0e8ce4d72f37a130316da559d62 -ra3d8ca871cecdad8f45756fdcae6d697bd0e8499
--- lams_central/web/includes/javascript/authoring/authoringActivity.js (.../authoringActivity.js) (revision ebe1058e6422f0e8ce4d72f37a130316da559d62)
+++ lams_central/web/includes/javascript/authoring/authoringActivity.js (.../authoringActivity.js) (revision a3d8ca871cecdad8f45756fdcae6d697bd0e8499)
@@ -10,25 +10,32 @@
ToolActivity: function(id, toolID, x, y, label) {
this.id = id;
this.type = 'tool';
+ this.transitions = {
+ 'from' : [],
+ 'to' : []
+ };
this.toolID = toolID;
+ this.draw = function(x, y) {
+ if (this.items) {
+ this.items.remove();
+ }
+
+ // create activity SVG elements
+ paper.setStart();
+ var shape = paper.path(Raphael.format('M {0} {1}' + layout.defs.activity, x, y))
+ .attr({
+ 'fill' : layout.colors.activity
+ });
+ paper.image(layout.toolIcons[toolID], x + 47, y + 2, 30, 30);
+ paper.text(x + 62, y + 40, label);
+
+ this.items = paper.setFinish();
+ this.items.shape = shape;
+
+ ActivityLib.initActivity(this);
+ };
- // create activity SVG elements
- paper.setStart();
- var shape = paper.rect(x, y, layout.conf.activityWidth, layout.conf.activityHeight)
- .attr({
- 'fill' : layout.colors.activity
- });
-
- paper.image(layout.toolIcons[toolID], shape.attr('x')
- + shape.attr('width') / 2 - 15, shape.attr('y') + 2, 30, 30);
-
- paper.text(shape.attr('x') + shape.attr('width') / 2, shape
- .attr('y') + 40, label);
-
- this.items = paper.setFinish();
- this.items.shape = shape;
-
- ActivityLib.initActivity(this);
+ this.draw(x, y);
},
/**
@@ -37,29 +44,35 @@
GroupingActivity : function(id, x, y) {
this.id = id;
this.type = 'group';
+ this.transitions = {
+ 'from' : [],
+ 'to' : []
+ };
+ this.draw = function(x, y) {
+ if (this.items) {
+ this.items.remove();
+ }
+
+ x-=47;
+ y-=2;
+
+ // create activity SVG elements
+ paper.setStart();
+ var shape = paper.path(Raphael.format('M {0} {1}' + layout.defs.activity, x, y))
+ .attr({
+ 'fill' : layout.colors.activity
+ });
+
+ paper.image('../images/grouping.gif', x + 47, y + 2, 30, 30);
+ paper.text(x + 62, y + 40, 'Grouping');
+
+ this.items = paper.setFinish();
+ this.items.shape = shape;
+
+ ActivityLib.initActivity(this);
+ };
- // create activity SVG elements
- paper.setStart();
- var shape = paper.rect(
- x - layout.conf.activityWidth/2,
- y - layout.conf.activityHeight/2,
- layout.conf.activityWidth, layout.conf.activityHeight)
- .attr({
- 'fill' : layout.colors.activity
- });
-
- paper.image('../images/grouping.gif',
- shape.attr('x') + shape.attr('width') / 2 - 15,
- shape.attr('y') + 2,
- 30, 30);
-
- paper.text(shape.attr('x') + shape.attr('width') / 2, shape
- .attr('y') + 40, 'Grouping');
-
- this.items = paper.setFinish();
- this.items.shape = shape;
-
- ActivityLib.initActivity(this);
+ this.draw(x, y);
},
/**
@@ -68,134 +81,140 @@
GateActivity : function(id, x, y) {
this.id = id;
this.type = 'gate';
-
- // create activity SVG elements
- paper.setStart();
- var shape = paper.path('M ' + x + ' ' + y + layout.defs.gate)
- .attr({
- 'fill' : layout.colors.gate
- });
+ this.transitions = {
+ 'from' : [],
+ 'to' : []
+ };
+ this.draw = function(x, y) {
+ if (this.items) {
+ this.items.remove();
+ }
+
+ // create activity SVG elements
+ paper.setStart();
+ var shape = paper.path(Raphael.format('M {0} {1}' + layout.defs.gate, x, y))
+ .attr({
+ 'fill' : layout.colors.gate
+ });
+
+ paper.text(x + 7, y + 14, 'STOP')
+ .attr({
+ 'font-size' : 9,
+ 'font' : 'sans-serif',
+ 'stroke' : layout.colors.gateText
+ });
+
+ this.items = paper.setFinish();
+ this.items.shape = shape;
+
+ ActivityLib.initActivity(this);
+ };
- paper.text(x + 7, y + 14, 'STOP')
- .attr({
- 'font-size' : 9,
- 'font' : 'sans-serif',
- 'stroke' : layout.colors.gateText
- });
-
- this.items = paper.setFinish();
- this.items.shape = shape;
-
- ActivityLib.initActivity(this);
+ this.draw(x, y);
},
+ /**
+ * Either branching or converge point.
+ */
BranchingEdgeActivity : function(id, x, y, branchingActivity) {
this.type = 'branchingEdge';
+ this.transitions = {
+ 'from' : [],
+ 'to' : []
+ };
+
if (branchingActivity) {
+ // branchingActivity already exists, so this is the converge point
this.isStart = false;
branchingActivity.end = this;
} else {
+ // this is the branching point
this.isStart = true;
branchingActivity = new ActivityLib.BranchingActivity(id, this);
}
this.branchingActivity = branchingActivity;
+ this.draw = function(x, y) {
+ if (this.items) {
+ this.items.remove();
+ }
- // create activity SVG elements
- paper.setStart();
- var shape = paper.path('M ' + x + ' ' + y +
- (this.isStart ? layout.defs.branchingEdgeStart : layout.defs.branchingEdgeEnd))
- .attr({
- 'fill' : this.isStart ? layout.colors.branchingEdgeStart
- : layout.colors.branchingEdgeEnd
- });
-
- paper.text(x, y + 14, this.isStart ? 'Branching point'
- : 'Converge point')
- .attr({
- 'font-size' : 9,
- 'font' : 'sans-serif'
- });
+ // create activity SVG elements
+ paper.setStart();
+ var shape = paper.path('M ' + x + ' ' + y +
+ (this.isStart ? layout.defs.branchingEdgeStart : layout.defs.branchingEdgeEnd))
+ .attr({
+ 'fill' : this.isStart ? layout.colors.branchingEdgeStart
+ : layout.colors.branchingEdgeEnd
+ });
+
+ paper.text(x, y + 14, this.isStart ? 'Branching point'
+ : 'Converge point')
+ .attr({
+ 'font-size' : 9,
+ 'font' : 'sans-serif'
+ });
+
+ this.items = paper.setFinish();
+ this.items.shape = shape;
+
+ ActivityLib.initActivity(this);
+ };
- this.items = paper.setFinish();
- this.items.shape = shape;
-
- ActivityLib.initActivity(this);
+ this.draw(x, y);
},
+ /**
+ * Represents a set of branches. It is not displayed on canvas.
+ */
BranchingActivity : function(id, branchingEdgeStart) {
this.id = id;
this.start = branchingEdgeStart;
this.branches = [];
},
+ /**
+ * Represents a subsequence of activities. It is not displayed on canvas.
+ */
BranchActivity : function(id, branchingActivity, transitionFrom) {
this.id = id;
- this.transitionsFrom = transitionFrom;
+ this.transitionFrom = transitionFrom;
this.branchingActivity = branchingActivity;
- branchingActivity.branches.push(this);
},
/**
* Make a new activity fully functional on canvas.
*/
- initActivity : function(activity) {
- activity.items.mousedown(function(event, x, y){
- if (event.ctrlKey) {
- // when CTRL is held down, start drawing a transition
- HandlerLib.drawTransitionStartHandler(activity, event, x, y);
- } else {
- // start dragging the activity
- var mouseupHandler = function(){
- HandlerLib.dragActivityEndHandler(activity);
- };
-
- HandlerLib.dragItemsStartHandler(activity.items, this, mouseupHandler, event, x, y);
+ initActivity : function(activity) {
+ // set all the handlers
+ activity.items
+ .data('activity', activity)
+ .mousedown(HandlerLib.activityMousedownHandler)
+ .click(HandlerLib.activityClickHandler)
+ .dblclick(HandlerLib.activityDblclickHandler)
+ .attr({
+ 'cursor' : 'pointer'
+ });
+
+ if (activity.type == 'branchingEdge' && activity.branchingActivity.end) {
+ // highligh branching edges on hover
+ activity.branchingActivity.start.items.hover(HandlerLib.branchingEdgeMouseoverHandler,
+ HandlerLib.branchingEdgeMouseoutHandler);
+ activity.branchingActivity.end.items.hover(HandlerLib.branchingEdgeMouseoverHandler,
+ HandlerLib.branchingEdgeMouseoutHandler);
}
- })
- .click(function(event){
- // inform that user wants to select, not drag the activity
- activity.items.clicked = true;
- HandlerLib.selectActivityHandler(event, activity);
- })
- .dblclick(function(){
- // inform that user wants to open, not drag the activity
- activity.items.clicked = true;
- HandlerLib.openActivityAuthoringHandler(activity);
- })
- .attr({
- 'cursor' : 'pointer'
- });
-
- if (activity.type == 'branchingEdge' && activity.branchingActivity.end) {
- var startItems = activity.branchingActivity.start.items;
- var endItems = activity.branchingActivity.end.items;
- var mouseover = function(){
- if (!startItems.isDragged && !endItems.isDragged) {
- startItems.shape.attr('fill', layout.colors.branchingEdgeMatch);
- endItems.shape.attr('fill', layout.colors.branchingEdgeMatch);
- }
- };
- var mouseout = function(){
- if (!startItems.isDragged && !endItems.isDragged) {
- startItems.shape.attr('fill', layout.colors.branchingEdgeStart);
- endItems.shape.attr('fill', layout.colors.branchingEdgeEnd);
- }
- };
- startItems.shape.hover(mouseover, mouseout);
- endItems.shape.hover(mouseover, mouseout);
- }
- },
+ },
/**
* Deletes the given activity.
*/
removeActivity : function(activity, forceRemove) {
if (!forceRemove && activity.type == 'branchingEdge'){
+ // user removes one of the branching edges, so remove the whole activity
if (confirm('Are you sure you want to remove the whole branching activity?')){
var otherEdge = activity.isStart ? activity.branchingActivity.end
: activity.branchingActivity.start;
@@ -206,20 +225,18 @@
}
// remove the transitions
- if (activity.fromTransition) {
- var toActivity = activity.fromTransition.toActivity;
+ $.each(activity.transitions.from.slice(), function() {
// if grouping activity is gone, remove the grouping effect
- if (activity.type == 'group' && toActivity.items.groupingEffect) {
- toActivity.items.groupingEffect.remove();
- toActivity.items.groupingEffect = null;
+ if (activity.type == 'group' && this.toActivity.items.groupingEffect) {
+ this.toActivity.items.groupingEffect.remove();
+ this.toActivity.items.groupingEffect = null;
}
- toActivity.toTransition = null;
- activity.fromTransition.remove();
- }
- if (activity.toTransition){
- activity.toTransition.fromActivity.fromTransition = null
- activity.toTransition.remove();
- }
+ ActivityLib.removeTransition(this);
+ });
+ // need to use slice() to copy the array as it gets modified in removeTransition()
+ $.each(activity.transitions.to.slice(), function() {
+ ActivityLib.removeTransition(this);
+ });
// remove the activity from activities table
activities.splice(activities.indexOf(activity), 1);
@@ -231,58 +248,73 @@
/**
* Draws a transition between two activities.
*/
- drawTransition : function(fromActivity, toActivity) {
- // remove the existing activities
- if (fromActivity.fromTransition) {
- fromActivity.fromTransition.remove();
+ drawTransition : function(fromActivity, toActivity, redraw) {
+ // only converge points are allowed to have few inbound transitions
+ if (!redraw
+ && toActivity.transitions.to.length > 0
+ && !(toActivity.type == 'branchingEdge' && !toActivity.isStart)) {
+ alert('Transition to this activity already exists');
+ return;
}
- if (toActivity.toTransition) {
- toActivity.toTransition.remove();
+
+ // user chose to create outbound transition from an activity that already has one
+ if (!redraw
+ && fromActivity.transitions.from.length > 0
+ && !(fromActivity.type == 'branchingEdge' && fromActivity.isStart)
+ && !(toActivity.type == 'branchingEdge' && toActivity.isStart)) {
+ if (confirm('Transition from this activity already exists.\n' +
+ 'Do you want to create branching here?')) {
+ ActivityLib.addBranching(fromActivity, toActivity);
+ }
+ return;
}
+ // remove the existing transition
+ $.each(fromActivity.transitions.from, function(index) {
+ if (this.toActivity == toActivity) {
+ ActivityLib.removeTransition(this);
+ return false;
+ }
+ });
+
// calculate middle points of each activity
- var fromActivityBox = fromActivity.items.shape.getBBox();
- var toActivityBox = toActivity.items.shape.getBBox();
- var startX = fromActivityBox.x + fromActivityBox.width / 2;
- var startY = fromActivityBox.y + fromActivityBox.height / 2;
- var endX = toActivityBox.x + toActivityBox.width / 2;
- var endY = toActivityBox.y + toActivityBox.height / 2;
+ var points = ActivityLib.findTransitionPoints(fromActivity, toActivity);
// do the actual drawing
paper.setStart();
- paper.path('M ' + startX + ' ' + startY + ' L ' + endX + ' ' + endY)
- .attr({
- 'stroke' : layout.colors.transition,
+ paper.path(Raphael.format('M {0} {1} L {2} {3}', points.startX, points.startY, points.endX, points.endY))
+ .attr({
+ 'stroke' : layout.colors.transition,
'stroke-width' : 2
- });
+ });
// draw the arrow and turn it in the same direction as the line
- var angle = 90 + Math.atan2(endY - startY, endX - startX) * 180 / Math.PI;
- var arrowX = (startX + (endX - startX)/2);
- var arrowY = (startY + (endY - startY)/2);
- var arrowPath = Raphael.transformPath('M ' + arrowX + ' ' + arrowY + layout.defs.transArrow,
- 'R ' + angle + ' ' + arrowX + ' ' + arrowY);
+ var angle = 90 + Math.atan2(points.endY - points.startY, points.endX - points.startX) * 180 / Math.PI;
+ var arrowPath = Raphael.transformPath(Raphael.format('M {0} {1}' + layout.defs.transArrow, points.middleX, points.middleY),
+ Raphael.format('R {0} {1} {2}', angle, points.middleX, points.middleY));
paper.path(arrowPath)
.attr({
'stroke' : layout.colors.transition,
'fill' : layout.colors.transition
});
- transition = paper.setFinish();
+ var transition = paper.setFinish();
+ transition.data('transition', transition);
// set up references in activities and the transition
+ fromActivity.transitions.from.push(transition);
+ toActivity.transitions.to.push(transition);
transition.fromActivity = fromActivity;
transition.toActivity = toActivity;
- fromActivity.fromTransition = transition;
- toActivity.toTransition = transition;
transition.toBack();
- transition.mousedown(function(event, x, y){
- // allow transition dragging
- var mouseupHandler = function(){
- HandlerLib.dragTransitionEndHandler(transition);
- };
- HandlerLib.dragItemsStartHandler(transition, this, mouseupHandler, event, x, y)
- });
+ transition.mousedown(HandlerLib.transitionMousedownHandler);
+ if (fromActivity.type == 'branchingEdge' && fromActivity.isStart) {
+ // create a new branch
+ var branch = new ActivityLib.BranchActivity(null, fromActivity.branchingActivity, transition);
+ fromActivity.branchingActivity.branches.push(branch);
+ transition.data('branch', branch);
+ }
+
// add grouping effect if previous activity is of grouping type
if (fromActivity.type == 'group' && toActivity.type != 'gate') {
ActivityLib.addGroupingEffect(toActivity);
@@ -295,16 +327,82 @@
*/
removeTransition : function(transition) {
if (transition.toActivity.items.groupingEffect) {
+ // if toActivity had a grouping effect, remove it
transition.toActivity.items.groupingEffect.remove();
transition.toActivity.items.groupingEffect = null;
}
- transition.fromActivity.fromTransition = null;
- transition.toActivity.toTransition = null;
+
+ // find the transition and remove it
+ var transitions = transition.fromActivity.transitions.from;
+ transitions.splice(transitions.indexOf(transition), 1);
+ transitions = transition.toActivity.transitions.to;
+ transitions.splice(transitions.indexOf(transition), 1);
+
+ var branch = transition[0].data('branch');
+ if (branch) {
+ var branches = branch.branchingActivity.branches;
+ branches.splice(branches.indexOf(branch), 1);
+ }
+
transition.remove();
},
/**
+ * Adds branching activity when user draws an extra outbout transition from.
+ */
+ addBranching : function(fromActivity, toActivity1) {
+ // find the other toActivity
+ var existingTransition = fromActivity.transitions.from[0],
+ toActivity2 = existingTransition.toActivity,
+ branchingEdgeStart = null,
+ branchingEdgeEnd = null,
+ convergeActivity1 = toActivity1,
+ convergeActivity2 = toActivity2;
+ // find converge activity of the new branch
+ while (convergeActivity1.transitions.from.length > 0) {
+ convergeActivity1 = convergeActivity1.transitions.from[0].toActivity;
+ };
+
+ if (toActivity2.type == 'branchingEdge' && toActivity2.isStart) {
+ // there is already a branching activity, reuse existing items
+ branchingEdgeStart = toActivity2;
+ branchingEdgeEnd = toActivity2.branchingActivity.end;
+ } else {
+ // add new branching
+ ActivityLib.removeTransition(existingTransition);
+
+ // calculate position of branching point
+ var branchPoints1 = ActivityLib.findTransitionPoints(fromActivity, toActivity1),
+ branchPoints2 = ActivityLib.findTransitionPoints(fromActivity, toActivity2),
+ branchEdgeStartX = branchPoints1.middleX + (branchPoints2.middleX - branchPoints1.middleX)/2,
+ branchEdgeStartY = branchPoints1.middleY + (branchPoints2.middleY - branchPoints1.middleY)/2,
+ branchingEdgeStart = new ActivityLib.BranchingEdgeActivity(null, branchEdgeStartX,
+ branchEdgeStartY, null);
+ activities.push(branchingEdgeStart);
+
+ // find last activities in subsequences and make an converge point between them
+ while (convergeActivity2.transitions.from.length > 0) {
+ convergeActivity2 = convergeActivity2.transitions.from[0].toActivity;
+ };
+
+ var convergePoints = ActivityLib.findTransitionPoints(convergeActivity1, convergeActivity2),
+ branchingEdgeEnd = new ActivityLib.BranchingEdgeActivity(null, convergePoints.middleX,
+ convergePoints.middleY, branchingEdgeStart.branchingActivity);
+ activities.push(branchingEdgeEnd);
+
+ // draw all required transitions
+ ActivityLib.drawTransition(fromActivity, branchingEdgeStart);
+ ActivityLib.drawTransition(branchingEdgeStart, toActivity2);
+ ActivityLib.drawTransition(convergeActivity2, branchingEdgeEnd);
+ }
+
+ ActivityLib.drawTransition(branchingEdgeStart, toActivity1);
+ ActivityLib.drawTransition(convergeActivity1, branchingEdgeEnd);
+ },
+
+
+ /**
* Draws an extra border around the selected activity.
*/
addSelectEffect : function (activity) {
@@ -331,6 +429,22 @@
},
+ removeSelectEffect : function() {
+ var selectedActivity = layout.items.selectedActivity;
+ // does selection exist at all?
+ if (selectedActivity) {
+ if (selectedActivity.items.selectEffect) {
+ selectedActivity.items.selectEffect.remove();
+ selectedActivity.items.selectEffect = null;
+ }
+
+ // no selected activity = no properties dialog
+ layout.items.propertiesDialog.dialog('close');
+ layout.items.selectedActivity = null;
+ }
+ },
+
+
/**
* Adds visual grouping effect on an activity.
*/
@@ -349,5 +463,151 @@
.toBack();
activity.items.push(activity.items.groupingEffect);
}
+ },
+
+
+ /**
+ * Drop the dragged activity on the canvas.
+ */
+ dropActivity : function(activity) {
+ // finally transform the dragged elements
+ var transformation = activity.items.shape.attr('transform');
+ activity.items.transform('');
+ if (transformation.length > 0) {
+ activity.items.forEach(function(elem) {
+ // some elements (rectangles) have "x", some are paths
+ if (elem.attr('x')) {
+ elem.attr({
+ 'x' : elem.attr('x') + transformation[0][1],
+ 'y' : elem.attr('y') + transformation[0][2]
+ });
+ } else {
+ var path = elem.attr('path');
+ elem.attr('path', Raphael.transformPath(path, transformation));
+ }
+ });
+ }
+
+ if (activity.items.groupingEffect) {
+ activity.items.groupingEffect.toBack();
+ }
+
+ // redraw transitions
+ $.each(activity.transitions.from.slice(), function(){
+ ActivityLib.drawTransition(activity, this.toActivity, true);
+ });
+ $.each(activity.transitions.to.slice(), function(){
+ ActivityLib.drawTransition(this.fromActivity, activity, true);
+ });
+ },
+
+
+ /**
+ * Open separate window with activity authoring on double click.
+ */
+ openActivityAuthoring : function(activity){
+ // fetch authoring URL for a Tool Activity
+ if (!activity.authorURL && activity.toolID) {
+ $.ajax({
+ async : false,
+ cache : false,
+ url : LAMS_URL + "authoring/author.do",
+ dataType : 'json',
+ data : {
+ 'method' : 'createToolContent',
+ 'toolID' : activity.toolID,
+ 'contentFolderID' : contentFolderID
+ },
+ success : function(response) {
+ activity.authorURL = response.authorURL;
+ activity.id = response.toolContentID;
+ if (!contentFolderID) {
+ // if LD did not have contentFolderID, it was just generated
+ // so remember it
+ contentFolderID = response.contentFolderID;
+ }
+ }
+ });
+ }
+
+ if (activity.authorURL) {
+ window.open(activity.authorURL, 'activityAuthoring' + activity.id,
+ "HEIGHT=800,WIDTH=1024,resizable=yes,scrollbars=yes,status=false," +
+ "menubar=no,toolbar=no");
+ }
+ },
+
+
+ /**
+ * Drop the dragged transition.
+ */
+ dropTransition : function(transition) {
+ // if the transition was over rubbish bin, remove it
+ transition.transform('');
+ transition.toBack();
+ },
+
+
+ /**
+ * Calculates start, middle and end points of a line between two activities.
+ */
+ findTransitionPoints : function(fromActivity, toActivity) {
+ var fromActivityBox = fromActivity.items.shape.getBBox(),
+ toActivityBox = toActivity.items.shape.getBBox(),
+
+ // find points in the middle of each activity
+ points = {
+ 'startX' : fromActivityBox.x + fromActivityBox.width / 2,
+ 'startY' : fromActivityBox.y + fromActivityBox.height / 2,
+ 'endX' : toActivityBox.x + toActivityBox.width / 2,
+ 'endY' : toActivityBox.y + toActivityBox.height / 2
+ },
+
+ // find intersection points of the temporary transition
+ tempTransition = Raphael.parsePathString(Raphael.format(
+ 'M {0} {1} L {2} {3}', points.startX, points.startY, points.endX, points.endY)),
+ fromIntersect = Raphael.pathIntersection(tempTransition, fromActivity.items.shape.attr('path')),
+ toIntersect = Raphael.pathIntersection(tempTransition, toActivity.items.shape.attr('path'));
+
+ // find points on borders of activities, if they exist
+ if (fromIntersect.length > 0) {
+ points.startX = fromIntersect[0].x;
+ points.startY = fromIntersect[0].y;
+ }
+ if (toIntersect.length > 0) {
+ points.endX = toIntersect[0].x;
+ points.endY = toIntersect[0].y;
+ }
+ // middle point of the transition
+ points.middleX = points.startX + (points.endX - points.startX)/2;
+ points.middleY = points.startY + (points.endY - points.startY)/2;
+
+ return points;
+ },
+
+
+ /**
+ * Crawles through branches setting their lengths and finding the longest one.
+ */
+ updateBranchesLength : function(branchingActivity) {
+ var longestBranchLength = 0;
+ $.each(branchingActivity.branches, function(){
+ // include the first activity
+ var branchLength = 1,
+ activity = this.transitionFrom.toActivity;
+ while (activity.transitions.from.length > 0) {
+ activity = activity.transitions.from[0].toActivity;
+ // check if reached the end of branch
+ if (activity.type != 'branchingEdge') {
+ branchLength++;
+ }
+ };
+ this.branchLength = branchLength;
+ if (branchLength > longestBranchLength) {
+ longestBranchLength = branchLength;
+ }
+ });
+
+ branchingActivity.longestBranchLength = longestBranchLength;
}
};
\ No newline at end of file
Index: lams_central/web/includes/javascript/authoring/authoringGeneral.js
===================================================================
diff -u -rebe1058e6422f0e8ce4d72f37a130316da559d62 -ra3d8ca871cecdad8f45756fdcae6d697bd0e8499
--- lams_central/web/includes/javascript/authoring/authoringGeneral.js (.../authoringGeneral.js) (revision ebe1058e6422f0e8ce4d72f37a130316da559d62)
+++ lams_central/web/includes/javascript/authoring/authoringGeneral.js (.../authoringGeneral.js) (revision a3d8ca871cecdad8f45756fdcae6d697bd0e8499)
@@ -3,23 +3,26 @@
*/
// few publicly visible variables
-var paper = null;
-var canvas = null;
-var activities = [];
+var paper = null,
+ canvas = null,
+ activities = null;
// configuration and storage of various elements
var layout = {
'toolIcons': {},
'conf' : {
- 'activityWidth' : 125,
- 'activityHeight' : 50,
'propertiesDialogDimOpacity' : 0.3,
'propertiesDialogDimThreshold' : 100,
'propertiesDialogDimThrottle' : 100,
- 'dragStartThreshold' : 300
+ 'dragStartThreshold' : 300,
+ 'arrangeHorizontalSpace' : 200,
+ 'arrangeVerticalSpace' : 100,
+ 'arrangeHorizontalPadding' : 40,
+ 'arrangeVerticalPadding' : 50
},
'defs' : {
- 'bin' : 'M 830 680 h -50 l 10 50 h 30 z',
+ 'activity' : ' h 125 v 50 h -125 z',
+ 'bin' : 'M 0 0 h -50 l 10 50 h 30 z',
'transArrow' : ' l 10 15 a 25 25 0 0 0 -20 0 z',
'gate' : ' l-8 8 v14 l8 8 h14 l8 -8 v-14 l-8 -8 z',
'branchingEdgeStart' : ' m -8 0 a 8 8 0 1 0 16 0 a 8 8 0 1 0 -16 0',
@@ -48,8 +51,8 @@
* Initialises the whole Authoring window.
*/
$(document).ready(function() {
- paper = Raphael('canvas');
canvas = $('#canvas');
+ MenuLib.newLearningDesign(true);
initLayout();
initTemplates();
@@ -121,9 +124,6 @@
* Initialises various Authoring widgets.
*/
function initLayout() {
- // draw rubbish bin on canvas
- layout.items.bin = paper.path(layout.defs.bin);
-
// add jQuery UI button functionality
$('.ui-button').button();
$(".split-ui-button").each(function(){
@@ -246,8 +246,6 @@
of: '#canvas'
}
});
-
- HandlerLib.resetCanvasMode();
}
@@ -270,15 +268,10 @@
return;
}
- // reset the canvas
- paper.clear();
- // draw the rubbish bin again
- layout.items.bin = paper.path(layout.defs.bin);
+ MenuLib.newLearningDesign(true);
// create visual representation of the loaded activities
- activities = [];
$.each(ld.activities, function() {
var activity = this;
-
activities.push(new ActivityLib.ToolActivity(activity.activityID,
activity.toolID, activity.xCoord, activity.yCoord,
activity.activityTitle));
@@ -310,4 +303,30 @@
HandlerLib.resetCanvasMode();
}
});
+}
+
+
+function resizePaper(width, height) {
+ if (!paper) {
+ return;
+ }
+
+ if (!width) {
+ width = canvas.width() - 5;
+ }
+ if (!height || (height == canvas.height() - 5)) {
+ height = canvas.height() - 5 - (width > canvas.width() - 5 ? 20 : 0);
+ }
+ paper.setSize(width, height);
+
+ if (layout.items.bin) {
+ layout.items.bin.remove();
+ }
+
+ // draw rubbish bin on canvas
+ var binPath = Raphael.parsePathString(layout.defs.bin);
+ binPath = Raphael.transformPath(binPath, Raphael.format('t {0} {1}', width, height - 50));
+ layout.items.bin = paper.path(binPath);
+
+ HandlerLib.resetCanvasMode();
}
\ No newline at end of file
Index: lams_central/web/includes/javascript/authoring/authoringHandler.js
===================================================================
diff -u -rebe1058e6422f0e8ce4d72f37a130316da559d62 -ra3d8ca871cecdad8f45756fdcae6d697bd0e8499
--- lams_central/web/includes/javascript/authoring/authoringHandler.js (.../authoringHandler.js) (revision ebe1058e6422f0e8ce4d72f37a130316da559d62)
+++ lams_central/web/includes/javascript/authoring/authoringHandler.js (.../authoringHandler.js) (revision a3d8ca871cecdad8f45756fdcae6d697bd0e8499)
@@ -8,10 +8,13 @@
* Default mode for canvas. Run after special mode is no longer needed.
*/
resetCanvasMode : function(){
+ // remove selection if exists
+ ActivityLib.removeSelectEffect();
+
canvas.css('cursor', 'default')
.off('click')
// if clicked anywhere, activity selection is gone
- .click(HandlerLib.unselectActivityHandler)
+ .click(HandlerLib.canvasClickHandler)
.off('mouseup')
.off('mousemove')
// when mouse gets closer to properties dialog, make it fully visible
@@ -50,81 +53,22 @@
container.css('opacity', opacity);
}
},
-
-
+
/**
- * Show selection border around the clicked activity.
- */
- selectActivityHandler : function(event, activity) {
- if (activity != layout.items.selectedActivity) {
- HandlerLib.unselectActivityHandler(event);
- ActivityLib.addSelectEffect(activity);
- }
- // so canvas handler unselectActivityHandler() is not run
- event.preventDefault();
- },
-
-
- /**
* Remove activity selection when user clicks on canvas.
*/
- unselectActivityHandler : function(event) {
+ canvasClickHandler : function(event) {
// check if user clicked on empty space on canvas
// or on some element on top of it
var defaultPrevented = event.originalEvent ?
event.originalEvent.defaultPrevented : event.defaultPrevented;
if (!defaultPrevented) {
- var selectedActivity = layout.items.selectedActivity;
- // does selection exist at all?
- if (selectedActivity) {
- selectedActivity.items.selectEffect.remove();
- selectedActivity.items.selectEffect = null;
-
- // no selected activity = no properties dialog
- layout.items.propertiesDialog.dialog('close');
- layout.items.selectedActivity = null;
- }
+ ActivityLib.removeSelectEffect();
}
},
/**
- * Open separate window with activity authoring on double click.
- */
- openActivityAuthoringHandler : function(activity){
- // fetch authoring URL for a Tool Activity
- if (!activity.authorURL && activity.toolID) {
- $.ajax({
- async : false,
- cache : false,
- url : LAMS_URL + "authoring/author.do",
- dataType : 'json',
- data : {
- 'method' : 'createToolContent',
- 'toolID' : activity.toolID,
- 'contentFolderID' : contentFolderID
- },
- success : function(response) {
- activity.authorURL = response.authorURL;
- activity.id = response.toolContentID;
- if (!contentFolderID) {
- // if LD did not have contentFolderID, it was just generated
- // so remember it
- contentFolderID = response.contentFolderID;
- }
- }
- });
- }
-
- if (activity.authorURL) {
- window.open(activity.authorURL, 'activityAuthoring' + activity.id,
- "HEIGHT=800,WIDTH=1024,resizable=yes,scrollbars=yes,status=false," +
- "menubar=no,toolbar=no");
- }
- },
-
-
- /**
* Start dragging an activity or transition.
*/
dragItemsStartHandler : function(items, draggedElement, mouseupHandler, event, startX, startY) {
@@ -153,15 +97,15 @@
HandlerLib.dragItemsMoveHandler(items, event, startX, startY);
});
- var mouseup = function(){
+ var mouseup = function(mouseupEvent){
// finish dragging - restore various elements' default state
items.isDragged = false;
items.unmouseup();
HandlerLib.resetCanvasMode();
layout.items.bin.attr('fill', 'transparent');
// do whetver needs to be done with the dragged elements
- mouseupHandler();
+ mouseupHandler(mouseupEvent);
};
// if user moves mouse very quickly, mouseup event can be triggered
@@ -185,71 +129,14 @@
}
// highlight rubbish bin if dragged elements are over it
- if (Raphael.isBBoxIntersect(layout.items.bin.getBBox(), items.getBBox())) {
+ if (HandlerLib.isElemenentBinned(event)) {
layout.items.bin.attr('fill', layout.colors.binActive);
} else {
layout.items.bin.attr('fill', 'transparent');
}
},
-
/**
- * Drop the dragged activity on the canvas.
- */
- dragActivityEndHandler : function(activity) {
- // if the activity was over rubbish bin, remove it
- if (Raphael.isBBoxIntersect(layout.items.bin.getBBox(), activity.items.shape.getBBox())) {
- ActivityLib.removeActivity(activity);
- return;
- }
-
- // finally transform the dragged elements
- var transformation = activity.items.shape.attr('transform');
- activity.items.transform('');
- if (transformation.length > 0) {
- activity.items.forEach(function(elem) {
- // some elements (rectangles) have "x", some are paths
- if (elem.attr('x')) {
- elem.attr({
- 'x' : elem.attr('x') + transformation[0][1],
- 'y' : elem.attr('y') + transformation[0][2]
- });
- } else {
- var path = elem.attr('path');
- elem.attr('path', Raphael.transformPath(path, transformation));
- }
- });
- }
-
- if (activity.items.groupingEffect) {
- activity.items.groupingEffect.toBack();
- }
-
- // redraw transitions
- if (activity.fromTransition) {
- ActivityLib.drawTransition(activity, activity.fromTransition.toActivity);
- }
- if (activity.toTransition) {
- ActivityLib.drawTransition(activity.toTransition.fromActivity, activity);
- }
- },
-
-
- /**
- * Drop the dragged transition.
- */
- dragTransitionEndHandler : function(transition) {
- // if the transition was over rubbish bin, remove it
- if (Raphael.isBBoxIntersect(layout.items.bin.getBBox(), transition.getBBox())) {
- ActivityLib.removeTransition(transition);
- } else {
- // cancel drag
- transition.transform('');
- transition.toBack();
- }
- },
-
- /**
* Start drawing a transition.
*/
drawTransitionStartHandler : function(activity, event, x, y) {
@@ -263,7 +150,8 @@
canvas.mousemove(function(event){
HandlerLib.drawTransitionMoveHandler(activity, event, startX, startY);
- }).mouseup(function(event){
+ })
+ .mouseup(function(event){
HandlerLib.drawTransitionEndHandler(activity, event);
});
},
@@ -302,27 +190,133 @@
* Finalise transition drawing.
*/
drawTransitionEndHandler : function(activity, event) {
+ // prevent triggering event on several activity items; we just need on transition
+ event.stopImmediatePropagation();
HandlerLib.resetCanvasMode();
- //remove the temporary transition
+ //remove the temporary transition (dashed line)
if (activity.tempTransition) {
activity.tempTransition.remove();
activity.tempTransition = null;
}
- var endX = event.pageX - canvas.offset().left;
- var endY = event.pageY - canvas.offset().top;
var endActivity = null;
- // find the target activity
- $.each(activities, function(){
- if (this.items.shape.isPointInside(endX, endY)) {
- endActivity = this;
- return false;
- }
- });
+ var targetElement = paper.getElementByPoint(event.pageX, event.pageY);
+ if (targetElement) {
+ endActivity = targetElement.data('activity');
+ }
- if (endActivity) {
+ if (endActivity && activity != endActivity) {
ActivityLib.drawTransition(activity, endActivity);
}
+ },
+
+
+ /**
+ * Lighthens up branching edges in the same colour for identifictation.
+ */
+ branchingEdgeMouseoverHandler : function() {
+ var branchingActivity = this.data('activity').branchingActivity;
+ var startItems = branchingActivity.start.items;
+ var endItems = branchingActivity.end.items;
+ if (!startItems.isDragged && !endItems.isDragged) {
+ startItems.shape.attr('fill', layout.colors.branchingEdgeMatch);
+ endItems.shape.attr('fill', layout.colors.branchingEdgeMatch);
+ }
+ },
+
+
+ /**
+ * Return branching edges to their normal colours.
+ */
+ branchingEdgeMouseoutHandler : function() {
+ var branchingActivity = this.data('activity').branchingActivity;
+ var startItems = branchingActivity.start.items;
+ var endItems = branchingActivity.end.items;
+ if (!startItems.isDragged && !endItems.isDragged) {
+ startItems.shape.attr('fill', layout.colors.branchingEdgeStart);
+ endItems.shape.attr('fill', layout.colors.branchingEdgeEnd);
+ }
+ },
+
+
+ /**
+ * Starts drawing a transition or dragging an activity.
+ */
+ activityMousedownHandler : function(event, x, y){
+ var activity = this.data('activity');
+ if (event.ctrlKey) {
+ // when CTRL is held down, start drawing a transition
+ HandlerLib.drawTransitionStartHandler(activity, event, x, y);
+ } else {
+ var mouseupHandler = function(event){
+ if (HandlerLib.isElemenentBinned(event)) {
+ // if the activity was over rubbish bin, remove it
+ ActivityLib.removeActivity(activity);
+ } else {
+ ActivityLib.dropActivity(activity);
+ }
+ }
+ // start dragging the activity
+ HandlerLib.dragItemsStartHandler(activity.items, this, mouseupHandler, event, x, y);
+ }
+ },
+
+
+ /**
+ * Selects an activity.
+ */
+ activityClickHandler : function(event) {
+ var activity = this.data('activity');
+ // inform that user wants to select, not drag the activity
+ activity.items.clicked = true;
+ if (activity != layout.items.selectedActivity) {
+ HandlerLib.canvasClickHandler(event);
+ ActivityLib.addSelectEffect(activity);
+ }
+ // so canvas handler unselectActivityHandler() is not run
+ event.preventDefault();
+ },
+
+
+ /**
+ * Opens activity authoring.
+ */
+ activityDblclickHandler : function(event) {
+ var activity = this.data('activity');
+ // inform that user wants to open, not drag the activity
+ activity.items.clicked = true;
+ ActivityLib.openActivityAuthoring(activity);
+ },
+
+
+ /**
+ * Starts dragging a transition.
+ */
+ transitionMousedownHandler : function(event, x, y){
+ var transition = this.data('transition');
+ // allow transition dragging
+ var mouseupHandler = function(event){
+ if (HandlerLib.isElemenentBinned(event)) {
+ // if the transition was over rubbish bin, remove it
+ ActivityLib.removeTransition(transition);
+ } else {
+ ActivityLib.dropTransition(transition);
+ }
+ }
+
+ HandlerLib.dragItemsStartHandler(transition, this, mouseupHandler, event, x, y);
+ },
+
+
+ /**
+ * Checks whether activity or transition is over rubbish bin.
+ */
+ isElemenentBinned : function(event) {
+ var canvasX = event.pageX - canvas.offset().left;
+ var canvasY = event.pageY - canvas.offset().top;
+
+ // highlight rubbish bin if dragged elements are over it
+ return Raphael.isPointInsideBBox(layout.items.bin.getBBox(), canvasX, canvasY);
}
};
\ No newline at end of file
Index: lams_central/web/includes/javascript/authoring/authoringMenu.js
===================================================================
diff -u -rebe1058e6422f0e8ce4d72f37a130316da559d62 -ra3d8ca871cecdad8f45756fdcae6d697bd0e8499
--- lams_central/web/includes/javascript/authoring/authoringMenu.js (.../authoringMenu.js) (revision ebe1058e6422f0e8ce4d72f37a130316da559d62)
+++ lams_central/web/includes/javascript/authoring/authoringMenu.js (.../authoringMenu.js) (revision a3d8ca871cecdad8f45756fdcae6d697bd0e8499)
@@ -15,18 +15,17 @@
var x = event.pageX - canvas.offset().left;
var y = event.pageY - canvas.offset().top;
- var isStart = !branchingActivity;
var branchingEdge = new ActivityLib.BranchingEdgeActivity(null, x, y, branchingActivity);
activities.push(branchingEdge);
- if (isStart) {
- branchingActivity = branchingEdge.branchingActivity;
- dialog.text('Place the converge point');
- } else {
+ if (branchingActivity) {
+ HandlerLib.resetCanvasMode();
+
dialog.text('');
dialog.dialog('close');
-
- HandlerLib.resetCanvasMode();
+ } else {
+ branchingActivity = branchingEdge.branchingActivity;
+ dialog.text('Place the converge point');
}
});
},
@@ -36,13 +35,14 @@
*/
addGrouping : function() {
canvas.css('cursor', 'url("../images/grouping.gif"), move').click(function(event){
+ HandlerLib.resetCanvasMode();
+
// pageX and pageY tell event coordinates relative to the whole page
// we need relative to canvas
var x = event.pageX - canvas.offset().left;
var y = event.pageY - canvas.offset().top;
activities.push(new ActivityLib.GroupingActivity(null, x, y));
- HandlerLib.resetCanvasMode();
});
},
@@ -52,13 +52,14 @@
*/
addGate : function() {
canvas.css('cursor', 'url("../images/stop.gif"), move').click(function(event){
+ HandlerLib.resetCanvasMode();
+
// pageX and pageY tell event coordinates relative to the whole page
// we need relative to canvas
var x = event.pageX - canvas.offset().left;
var y = event.pageY - canvas.offset().top;
activities.push(new ActivityLib.GateActivity(null, x, y));
- HandlerLib.resetCanvasMode();
});
},
@@ -161,5 +162,208 @@
});
return result;
+ },
+
+
+ /**
+ * Sorts activities on canvas.
+ */
+ arrangeActivities : function(){
+ // just to refresh the state of canvas
+ HandlerLib.resetCanvasMode();
+
+ if (activities.length == 0) {
+ // no activities, nothing to do
+ return;
+ }
+
+ // activities are arranged in a grid
+ var row = 0,
+ column = 0,
+ // check how many columns current paper can hold
+ maxColumns = Math.floor((paper.width - layout.conf.arrangeHorizontalPadding)
+ / layout.conf.arrangeHorizontalSpace),
+ // the initial max length of subsequences is limited by paper space
+ subsequenceMaxLength = maxColumns,
+ // check how many rows current paper can hold
+ maxRows = Math.floor((paper.height - layout.conf.arrangeVerticalPadding)
+ / layout.conf.arrangeVerticalSpace),
+ // make a shallow copy of activities array
+ activitiesCopy = activities.slice(),
+ // just to speed up processing when there are only activities with no transitions left
+ onlyDetachedLeft = false;
+
+ // branches will not be broken into few rows; if they are long, paper will be resized
+ // find the longes branch to find the new paper size
+ $.each(activities, function(){
+ if (this.type == 'branchingEdge' && this.isStart) {
+ // refresh branching metadata
+ ActivityLib.updateBranchesLength(this.branchingActivity);
+ // add start and end edges to the result
+ var longestBranchLength = this.branchingActivity.longestBranchLength + 2;
+ if (longestBranchLength > subsequenceMaxLength) {
+ subsequenceMaxLength = longestBranchLength;
+ }
+ }
+ });
+ // resize paper horizontally, if needed
+ if (subsequenceMaxLength > maxColumns) {
+ maxColumns = subsequenceMaxLength;
+ resizePaper(layout.conf.arrangeHorizontalPadding
+ + maxColumns * layout.conf.arrangeHorizontalSpace,
+ paper.height);
+ }
+
+ // main loop; iterate over whatever is left in the array
+ while (activitiesCopy.length > 0) {
+ // resize paper vertically, if needed
+ if (row > maxRows) {
+ maxRows++;
+ resizePaper(paper.width, layout.conf.arrangeVerticalPadding
+ + maxColumns * layout.conf.arrangeVerticalSpace);
+ }
+
+ // look for activities with transitions first; detached ones go to the very end
+ var activity = null;
+ if (!onlyDetachedLeft) {
+ $.each(activitiesCopy, function(){
+ if (this.transitions.to.length > 0) {
+ activity = this;
+ while (activity.transitions.to.length > 0) {
+ // check if previous activity was not drawn already
+ // it can happen for branching edges
+ var activityLookup = activity.transitions.to[0].fromActivity;
+ if (activitiesCopy.indexOf(activityLookup) == -1) {
+ break;
+ }
+ activity = activityLookup;
+ };
+ return false;
+ }
+ });
+ }
+
+ if (!activity) {
+ // no activities with transitions left, take first detached one
+ onlyDetachedLeft = true;
+ activity = activitiesCopy[0];
+ }
+
+ // markers for complex activity processing
+ var branchIndex = null,
+ complexActivityEnd = null;
+
+ // crawl through a sequence of activities
+ while (activity) {
+ if (activity.type == 'branchingEdge') {
+ // draw branching edges straight away and remove them from normall processing
+ branchingActivity = activity.branchingActivity;
+ var start = branchingActivity.start,
+ end = branchingActivity.end,
+ complexActivityEnd = end,
+ // edge points go to middle of rows with branches
+ branchingRow = row + 1 + Math.floor(branchingActivity.branches.length / 2);
+
+ activitiesCopy.splice(activitiesCopy.indexOf(start), 1);
+ activitiesCopy.splice(activitiesCopy.indexOf(end), 1);
+
+ // start point goes to very left, end goes wherever the longes branch ends
+ start.draw(layout.conf.arrangeHorizontalPadding + 62,
+ layout.conf.arrangeVerticalPadding + branchingRow * layout.conf.arrangeVerticalSpace + 25);
+ end.draw(layout.conf.arrangeHorizontalPadding + (activity.branchingActivity.longestBranchLength + 1)
+ * layout.conf.arrangeHorizontalSpace + 62,
+ layout.conf.arrangeVerticalPadding + branchingRow * layout.conf.arrangeVerticalSpace + 25);
+
+ row++;
+ if (branchingActivity.branches.length > 0) {
+ // set up branch drawing
+ branchIndex = 0;
+ activity = branchingActivity.branches[branchIndex].transitionFrom.toActivity;
+ // next activity for normal processing will be first one from the first branch
+ continue;
+ } else {
+ // no branches, nothing to do, carry on with normall activity processing
+ activity = complexActivityEnd;
+ complexActivityEnd = null;
+ // this will be incremented in the same iteration by normal activity processing
+ column = 1;
+ }
+ } else {
+ // it is a simple activity, so redraw it
+ var x = layout.conf.arrangeHorizontalPadding + column * layout.conf.arrangeHorizontalSpace,
+ y = layout.conf.arrangeVerticalPadding + row * layout.conf.arrangeVerticalSpace;
+
+ activity.draw(x, y);
+ // remove the activity so we do not process it twice
+ activitiesCopy.splice(activitiesCopy.indexOf(activity), 1);
+ }
+
+ // find the next row and column
+ column = (column + 1) % maxColumns;
+ if (column == 0) {
+ row++;
+ }
+
+ // does the activity has further activities?
+ if (activity.transitions.from.length > 0) {
+ activity = activity.transitions.from[0].toActivity;
+ } else {
+ activity = null;
+ }
+
+ if (complexActivityEnd && (!activity || activity == complexActivityEnd)) {
+ // end of branch
+ branchIndex++;
+ row++;
+ if (complexActivityEnd.branchingActivity.branches.length > branchIndex) {
+ // there is another branch to process
+ activity = complexActivityEnd.branchingActivity.branches[branchIndex].transitionFrom.toActivity;
+ // go back to left side of canvas and draw next branch
+ column = 1;
+ continue;
+ } else {
+ // no more branches, return to normal activity processing
+ activity = complexActivityEnd;
+ branchIndex = null;
+ complexActivityEnd = null;
+ column = 0;
+ if (activity.transitions.from.length == 0) {
+ break;
+ }
+ }
+ }
+
+ if (!activity || activitiesCopy.indexOf(activity) == -1) {
+ // next activity was already processed, so stop crawling
+ break;
+ }
+ };
+ };
+
+ // redraw transitions one by one
+ $.each(activities, function(){
+ $.each(this.transitions.from.slice(), function(){
+ ActivityLib.drawTransition(this.fromActivity, this.toActivity, true);
+ });
+ });
+ },
+
+
+ /**
+ * Removes existing activities and prepares canvas for a new sequence.
+ */
+ newLearningDesign : function(force){
+ if (!force && activities.length > 0 && !confirm('Are you sure you want to remove all existing activities?')){
+ return;
+ }
+
+ activities = [];
+ if (paper) {
+ paper.clear();
+ } else {
+ paper = Raphael('canvas');
+ }
+
+ resizePaper();
}
};
\ No newline at end of file