Index: lams_central/web/author2.jsp =================================================================== diff -u -rc051edc3328ffc90c5c902f938370a974a4e26d8 -r06e2eedee66e1ee3087000324a326111dccdbcba --- lams_central/web/author2.jsp (.../author2.jsp) (revision c051edc3328ffc90c5c902f938370a974a4e26d8) +++ lams_central/web/author2.jsp (.../author2.jsp) (revision 06e2eedee66e1ee3087000324a326111dccdbcba) @@ -26,6 +26,7 @@ + @@ -78,6 +79,18 @@
Group
+
+
+
+ Annotate +
+
 
+
+ +
Arrange
@@ -379,5 +392,31 @@ + +
+ + + + + +
+ Title: + + +
+
+ +
+ + + + + +
+ Title: + + +
+
\ No newline at end of file Index: lams_central/web/includes/javascript/authoring/authoringActivity.js =================================================================== diff -u -rc051edc3328ffc90c5c902f938370a974a4e26d8 -r06e2eedee66e1ee3087000324a326111dccdbcba --- lams_central/web/includes/javascript/authoring/authoringActivity.js (.../authoringActivity.js) (revision c051edc3328ffc90c5c902f938370a974a4e26d8) +++ lams_central/web/includes/javascript/authoring/authoringActivity.js (.../authoringActivity.js) (revision 06e2eedee66e1ee3087000324a326111dccdbcba) @@ -13,6 +13,7 @@ this.fromActivity = fromActivity; this.toActivity = toActivity; if (title) { + // only branches have titles this.title = title; this.loadPropertiesDialogContent = PropertyLib.transitionProperties; } @@ -25,6 +26,7 @@ toActivity.transitions.to.push(this); }, + /** * Constructor for a Tool Activity. */ @@ -157,6 +159,7 @@ draw : { transition : function() { + // clear previous canvas elements if (this.items) { this.items.remove(); } @@ -182,11 +185,12 @@ 'fill' : layout.colors.transition }); if (this.title) { - // adjust X & Y depending on the angle, so the lable does not overlap with the transition + // adjust X & Y depending on the angle, so the label does not overlap with the transition; // angle is -90 <= a <= 270 paper.text(points.middleX + ((angle > -45 && angle < 45) || (angle > 135 && angle < 225) ? 20 : 0), points.middleY + ((angle > 45 && angle < 135) || angle > 225 || angle < 45 ? -20 : 0), - this.title); + this.title) + .attr('text-anchor', 'start'); } this.items = paper.setFinish(); @@ -200,7 +204,7 @@ tool : function(x, y) { if (x == undefined || y == undefined) { - // just redraw the activity + // if no new coordinates are given, just redraw the activity x = this.items.shape.getBBox().x; y = this.items.shape.getBBox().y; } @@ -215,6 +219,7 @@ .attr({ 'fill' : layout.colors.activity[layout.toolMetadata[this.toolID].activityCategoryID] }); + // check for icon in the library paper.image(layout.toolMetadata[this.toolID].iconPath, x + 47, y + 2, 30, 30); paper.text(x + 62, y + 40, ActivityLib.shortenActivityTitle(this.title)) .attr({ @@ -440,6 +445,7 @@ branch ? branch.title : null); if (branch) { + // set the corresponding branch (again) branch.transitionFrom = transition; transition.branch = branch; fromActivity.branchingActivity.branches.push(branch); @@ -460,6 +466,7 @@ transitions.splice(transitions.indexOf(transition), 1); if (transition.branch) { + // remove corresponding branch var branches = transition.branch.branchingActivity.branches; branches.splice(branches.indexOf(transition.branch), 1); } @@ -523,13 +530,31 @@ /** - * Draws an extra border around the selected activity. + * Highlights the selected canvas element. */ - addSelectEffect : function (object) { + addSelectEffect : function (object, markSelected) { // do not draw twice if (!object.items.selectEffect) { - if (object instanceof ActivityLib.Transition) { - // show only if Transition is selectable, i.e. has a title + // different effects for different types of objects + if (object instanceof DecorationLib.Region) { + object.items.shape.attr({ + 'stroke' : layout.colors.selectEffect, + 'stroke-dasharray' : '-' + }); + object.items.resizeButton.show(); + object.items.selectEffect = true; + + // also select encapsulated activities + var childActivities = DecorationLib.getChildActivities(object.items.shape); + if (childActivities.length > 0) { + object.items.fitButton.show(); + + $.each(childActivities, function(){ + ActivityLib.addSelectEffect(this, false); + }); + } + } else if (object instanceof ActivityLib.Transition) { + // show only if Transition is selectable, i.e. is a branch, has a title if (object.loadPropertiesDialogContent) { object.items.attr({ 'stroke' : layout.colors.selectEffect, @@ -539,6 +564,7 @@ object.items.selectEffect = true; } } else { + // this goes for Activities and Labels var box = object.items.getBBox(); // a simple rectange a bit wider than the actual activity boundaries @@ -554,7 +580,8 @@ object.items.push(object.items.selectEffect); } - if (object.items.selectEffect){ + // make it officially marked? + if (markSelected && object.items.selectEffect){ layout.items.selectedObject = object; // show the properties dialog for the selected object if (object.loadPropertiesDialogContent) { @@ -570,18 +597,33 @@ }, - removeSelectEffect : function() { - var selectedObject = layout.items.selectedObject; - // does selection exist at all? - if (selectedObject) { - if (selectedObject.items.selectEffect) { - if (selectedObject instanceof ActivityLib.Transition) { - // just redraw, it's easier - selectedObject.draw(); + removeSelectEffect : function(object) { + // remove the effect from the given object or the selected one, whatever it is + if (!object) { + object = layout.items.selectedObject; + } + + if (object) { + if (object.items.selectEffect) { + if (object instanceof DecorationLib.Region) { + object.items.shape.attr({ + 'stroke' : 'black', + 'stroke-dasharray' : '' + }); + object.items.fitButton.hide(); + object.items.resizeButton.hide(); + + var childActivities = DecorationLib.getChildActivities(object.items.shape); + $.each(childActivities, function(){ + ActivityLib.removeSelectEffect(this); + }); + } else if (object instanceof ActivityLib.Transition) { + // just redraw the transition, it's easier + object.draw(); } else { - selectedObject.items.selectEffect.remove(); + object.items.selectEffect.remove(); } - selectedObject.items.selectEffect = null; + object.items.selectEffect = null; } // no selected activity = no properties dialog @@ -611,7 +653,7 @@ activity.items.push(activity.items.groupingEffect); // this is needed, for some reason, otherwise the activity can not be selected - HandlerLib.resetCanvasMode(); + HandlerLib.resetCanvasMode(true); } }, @@ -620,16 +662,6 @@ * 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) { - // find new X and Y and redraw the activity - var activityBox = activity.items.shape.getBBox(); - activity.draw(activityBox.x + transformation[0][1], - activityBox.y + transformation[0][2]); - } - // redraw transitions $.each(activity.transitions.from.slice(), function(){ ActivityLib.addTransition(activity, this.toActivity, true); Index: lams_central/web/includes/javascript/authoring/authoringDecoration.js =================================================================== diff -u --- lams_central/web/includes/javascript/authoring/authoringDecoration.js (revision 0) +++ lams_central/web/includes/javascript/authoring/authoringDecoration.js (revision 06e2eedee66e1ee3087000324a326111dccdbcba) @@ -0,0 +1,202 @@ +/** + * This file contains methods for Decoration manipulation on canvas. + */ + +var DecorationLib = { + + /** + * Constructor for region annotation. + */ + Region : function(x, y, width, height, color, title) { + this.title = title; + + this.draw = DecorationLib.methods.region.draw; + this.fit = DecorationLib.methods.region.fit; + this.loadPropertiesDialogContent = PropertyLib.regionProperties; + + this.draw(x, y, width, height, color); + }, + + + /** + * Constructor for label annotation. + */ + Label : function(x, y, title){ + // set a default title, if none provided + this.title = title || 'Label'; + + this.draw = DecorationLib.methods.label.draw; + this.loadPropertiesDialogContent = PropertyLib.labelProperties; + + this.draw(x, y); + }, + + + methods : { + + /** + * Region methods + */ + region : { + draw : function(x, y, x2, y2, color, title){ + // check for new coordinates or just take them from the existing shape + var box = this.items && this.items.shape ? this.items.shape.getBBox() : null, + x = x ? x : box.x, + y = y ? y : box.y, + // take into account minimal size of rectangle + x2 = x2 ? (x2 < x + 20 ? x + 20 : x2) : x + box.width, + y2 = y2 ? (y2 < y + 20 ? y + 20 : y2) : y + box.height, + color = color ? color : this.items.shape.attr('fill'); + + if (box) { + this.items.remove(); + } + + // the label + this.items = paper.set(); + if (this.title) { + var label = paper.text(x + 7, y + 10, this.title) + .attr('text-anchor', 'start') + .toBack(); + this.items.push(label); + } + + // the rectangle + this.items.shape = paper.path('M {0} {1} L {2} {1} L {2} {3} L {0} {3} z', x, y, x2, y2) + .attr({ + 'fill' : color, + 'cursor' : 'pointer' + }) + .mousedown(HandlerLib.regionMousedownHandler) + .click(HandlerLib.itemClickHandler) + .toBack(); + this.items.push(this.items.shape); + + this.items.fitButton = paper.circle(x2 - 10, y + 10, 5) + .attr({ + 'stroke' : null, + 'fill' : 'blue', + 'cursor' : 'pointer', + 'title' : 'Fit' + }) + .click(function(event){ + event.stopImmediatePropagation(); + var region = this.data('parentObject'); + region.fit(); + ActivityLib.addSelectEffect(region, true); + }) + .hide(); + this.items.push(this.items.fitButton); + + this.items.resizeButton = paper.path(Raphael.format('M {0} {1} v {2} h -{2} z', + x2, y2 - 15, 15)) + .attr({ + 'stroke' : null, + 'fill' : 'blue', + 'cursor' : 'se-resize' + }) + .mousedown(HandlerLib.resizeRegionStartHandler) + .hide(); + this.items.push(this.items.resizeButton); + + this.items.data('parentObject', this); + }, + + + /** + * Adjust the annotation so it envelops its child activities and nothing more. + */ + fit : function() { + var childActivities = DecorationLib.getChildActivities(this.items.shape); + if (childActivities.length == 0) { + return; + } + + ActivityLib.removeSelectEffect(this); + + var allElements = paper.set(); + $.each(childActivities, function(){ + allElements.push(this.items.shape); + }); + // big rectangle enveloping all child activities + var box = allElements.getBBox(); + + // add some padding + this.draw(box.x - 20, box.y - 20, box.x2 + 20, box.y2 + 20); + } + }, + + + /** + * Label methods + */ + label : { + draw : function(x, y) { + var x = x ? x : this.items.shape.getBBox().x, + // the Y coordinate has to be adjusted; + // it is not perfect and not really cross-browser compliant... + y = y ? y : this.items.shape.getBBox().y + 6; + + if (this.items) { + this.items.remove(); + } + + this.items = paper.set(); + this.items.shape = paper.text(x, y, this.title) + .attr({ + 'text-anchor' : 'start', + 'cursor' : 'pointer' + }) + .mousedown(HandlerLib.labelMousedownHandler) + .click(HandlerLib.itemClickHandler); + this.items.push(this.items.shape); + + this.items.data('parentObject', this); + } + } + }, + + + addRegion : function(x, y, x2, y2) { + var region = new DecorationLib.Region(x, y, x2, y2, layout.colors.annotation); + layout.regions.push(region); + return region; + }, + + + removeRegion : function(region) { + layout.regions.splice(layout.regions.indexOf(region), 1); + region.items.remove(); + }, + + + /** + * Get activities enveloped by given shape (usually annotation region) + */ + getChildActivities : function(shape){ + var result = []; + $.each(layout.activities, function(){ + var activityBox = this.items.shape.getBBox(); + + if (shape.isPointInside(activityBox.x, activityBox.y) + && shape.isPointInside(activityBox.x2, activityBox.y2)) { + result.push(this); + } + }); + + return result; + }, + + + addLabel : function(x, y, title) { + var label = new DecorationLib.Label(x, y, title); + layout.labels.push(label); + return label; + }, + + + removeLabel : function(label) { + layout.labels.splice(layout.labels.indexOf(label), 1); + label.items.remove(); + } +}; \ No newline at end of file Index: lams_central/web/includes/javascript/authoring/authoringGeneral.js =================================================================== diff -u -rc051edc3328ffc90c5c902f938370a974a4e26d8 -r06e2eedee66e1ee3087000324a326111dccdbcba --- lams_central/web/includes/javascript/authoring/authoringGeneral.js (.../authoringGeneral.js) (revision c051edc3328ffc90c5c902f938370a974a4e26d8) +++ lams_central/web/includes/javascript/authoring/authoringGeneral.js (.../authoringGeneral.js) (revision 06e2eedee66e1ee3087000324a326111dccdbcba) @@ -11,6 +11,8 @@ 'drawMode' : false, // 'isZoomed' : false, 'activities' : null, + 'regions' : null, + 'labels' : null, 'items' : { 'bin' : null, @@ -62,7 +64,8 @@ 'branchingEdgeMatch' : 'blue', 'transition' : 'rgb(119,126,157)', 'binActive' : 'red', - 'selectEffect' : 'blue' + 'selectEffect' : 'blue', + 'annotation' : 'yellow' }, }; @@ -658,7 +661,7 @@ } else if (resizeNeeded) { resizePaper(paperWidth, paperHeight); } else { - HandlerLib.resetCanvasMode(); + HandlerLib.resetCanvasMode(true); } } }); @@ -905,5 +908,5 @@ binPath = Raphael.transformPath(binPath, Raphael.format('t {0} {1}', width, height - 50)); layout.items.bin = paper.path(binPath); - HandlerLib.resetCanvasMode(); + HandlerLib.resetCanvasMode(true); } \ No newline at end of file Index: lams_central/web/includes/javascript/authoring/authoringHandler.js =================================================================== diff -u -rc051edc3328ffc90c5c902f938370a974a4e26d8 -r06e2eedee66e1ee3087000324a326111dccdbcba --- lams_central/web/includes/javascript/authoring/authoringHandler.js (.../authoringHandler.js) (revision c051edc3328ffc90c5c902f938370a974a4e26d8) +++ lams_central/web/includes/javascript/authoring/authoringHandler.js (.../authoringHandler.js) (revision 06e2eedee66e1ee3087000324a326111dccdbcba) @@ -7,20 +7,24 @@ /** * Default mode for canvas. Run after special mode is no longer needed. */ - resetCanvasMode : function(){ - layout.drawMode = false; + resetCanvasMode : function(init){ + // so elements understand that no events should be triggered, i.e. canvas is "dead" + layout.drawMode = !init; // remove selection if exists ActivityLib.removeSelectEffect(); - canvas.css('cursor', 'default') .off('click') - // if clicked anywhere, activity selection is gone - .click(HandlerLib.canvasClickHandler) + .off('mousedown') .off('mouseup') .off('mousemove') - // when mouse gets closer to properties dialog, make it fully visible - .mousemove(HandlerLib.approachPropertiesDialogHandler); + + if (init) { + // if clicked anywhere, activity selection is gone + canvas.click(HandlerLib.canvasClickHandler) + // when mouse gets closer to properties dialog, make it fully visible + .mousemove(HandlerLib.approachPropertiesDialogHandler); + } }, @@ -96,6 +100,8 @@ items.clicked = false; return; } + + HandlerLib.resetCanvasMode(); items.isDragged = true; items.attr('cursor', 'move'); @@ -107,11 +113,11 @@ // 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(mouseupEvent); + HandlerLib.resetCanvasMode(true); }; // if user moves mouse very quickly, mouseup event can be triggered @@ -152,6 +158,8 @@ return; } + HandlerLib.resetCanvasMode(); + var startX = x + canvas.scrollLeft() - canvas.offset().left, startY = y + canvas.scrollTop() - canvas.offset().top; @@ -197,7 +205,6 @@ // prevent triggering event on several activity items; we just need it on transition event.stopImmediatePropagation(); event.preventDefault(); - HandlerLib.resetCanvasMode(); //remove the temporary transition (dashed line) if (activity.tempTransition) { @@ -214,10 +221,123 @@ if (endActivity && activity != endActivity) { ActivityLib.addTransition(activity, endActivity); } + + HandlerLib.resetCanvasMode(true); }, /** + * Start drawing a region. + */ + drawRegionStartHandler : function(startEvent) { + HandlerLib.resetCanvasMode(); + + // remember what were the drawing start coordinates + var translatedEvent = ActivityLib.translateEventOnCanvas(startEvent), + data = { + 'startX' : translatedEvent[0], + 'startY' : translatedEvent[1] + }; + + canvas.mousemove(function(event){ + HandlerLib.drawRegionMoveHandler(data, event); + }) + .mouseup(function(event){ + HandlerLib.drawRegionEndHandler(data); + }); + }, + + + /** + * Keep drawing a region. + */ + drawRegionMoveHandler : function(data, event) { + var translatedEvent = ActivityLib.translateEventOnCanvas(event), + x = translatedEvent[0], + y = translatedEvent[1]; + + if (data.shape) { + // remove the previous rectangle + data.shape.remove(); + } + + data.shape = paper.path(Raphael.format('M {0} {1} h {2} v {3} h -{2} z', + x < data.startX ? x : data.startX, + y < data.startY ? y : data.startY, + Math.abs(x - data.startX), + Math.abs(y - data.startY))) + .attr({ + 'fill' : layout.colors.annotation, + 'opacity' : 0.3 + }); + + // immediatelly show which activities will be enveloped + var childActivities = DecorationLib.getChildActivities(data.shape); + $.each(layout.activities, function(){ + if ($.inArray(this, childActivities) > -1){ + ActivityLib.addSelectEffect(this, false); + } else { + ActivityLib.removeSelectEffect(this); + } + }); + }, + + + /** + * Finalise region drawing. + */ + drawRegionEndHandler : function(data) { + // remove select effect from all activities + $.each(layout.activities, function(){ + ActivityLib.removeSelectEffect(this); + }); + + if (data.shape) { + var box = data.shape.getBBox(), + region = DecorationLib.addRegion(box.x, box.y, box.x2, box.y2); + data.shape.remove(); + ActivityLib.addSelectEffect(region, true); + } + HandlerLib.resetCanvasMode(true); + }, + + + /** + * Start resizing a region. + */ + resizeRegionStartHandler : function(event) { + // otherwise mousedown handler (dragging) can be triggered + event.stopImmediatePropagation(); + event.preventDefault(); + + HandlerLib.resetCanvasMode(); + + var region = this.data('parentObject'); + + canvas.mousemove(function(event){ + HandlerLib.resizeRegionMoveHandler(region, event); + }) + .mouseup(function(){ + HandlerLib.resetCanvasMode(true); + ActivityLib.addSelectEffect(region, true); + }); + }, + + + /** + * Keep resising a region. + */ + resizeRegionMoveHandler : function(region, event){ + var translatedEvent = ActivityLib.translateEventOnCanvas(event), + x = translatedEvent[0], + y = translatedEvent[1]; + + // keep the initial coordinates and adjust end coordinates + region.draw(null, null, x, y); + }, + + + /** * Lighthens up branching edges in the same colour for identifictation. */ branchingEdgeMouseoverHandler : function() { @@ -265,6 +385,7 @@ // if the activity was over rubbish bin, remove it ActivityLib.removeActivity(activity); } else { + HandlerLib.dropObject(activity); ActivityLib.dropActivity(activity); } } @@ -289,8 +410,8 @@ parentObject.items.clicked = true; if (parentObject != layout.items.selectedObject) { HandlerLib.canvasClickHandler(event); - ActivityLib.addSelectEffect(parentObject); - } + ActivityLib.addSelectEffect(parentObject, true); + } // so canvas handler unselectActivityHandler() is not run event.preventDefault(); @@ -328,6 +449,70 @@ /** + * Starts dragging a region + */ + regionMousedownHandler : function(event, x, y){ + if (layout.drawMode || (event.originalEvent ? + event.originalEvent.defaultPrevented : event.defaultPrevented)){ + return; + } + + var region = this.data('parentObject'); + // allow transition dragging + var mouseupHandler = function(event){ + if (HandlerLib.isElemenentBinned(event)) { + // if the region was over rubbish bin, remove it + DecorationLib.removeRegion(region); + } else { + HandlerLib.dropObject(region); + } + } + + HandlerLib.dragItemsStartHandler(region.items, this, mouseupHandler, event, x, y); + }, + + + /** + * Starts dragging a label + */ + labelMousedownHandler : function(event, x, y){ + if (layout.drawMode || (event.originalEvent ? + event.originalEvent.defaultPrevented : event.defaultPrevented)){ + return; + } + + var label = this.data('parentObject'); + // allow transition dragging + var mouseupHandler = function(event){ + if (HandlerLib.isElemenentBinned(event)) { + // if the region was over rubbish bin, remove it + DecorationLib.removeLabel(label); + } else { + HandlerLib.dropObject(label); + } + } + + HandlerLib.dragItemsStartHandler(label.items, this, mouseupHandler, event, x, y); + }, + + + dropObject : function(object) { + // finally transform the dragged elements + var transformation = object.items.shape.attr('transform'); + object.items.transform(''); + if (transformation.length > 0) { + // find new X and Y and redraw the object + var box = object.items.shape.getBBox(), + x = box.x, + // adjust this coordinate for annotation labels + y = box.y + (object instanceof DecorationLib.Label ? 6 : 0); + object.draw(x + transformation[0][1], + y + transformation[0][2]); + } + }, + + + /** * Checks whether activity or transition is over rubbish bin. */ isElemenentBinned : function(event) { Index: lams_central/web/includes/javascript/authoring/authoringMenu.js =================================================================== diff -u -rc051edc3328ffc90c5c902f938370a974a4e26d8 -r06e2eedee66e1ee3087000324a326111dccdbcba --- lams_central/web/includes/javascript/authoring/authoringMenu.js (.../authoringMenu.js) (revision c051edc3328ffc90c5c902f938370a974a4e26d8) +++ lams_central/web/includes/javascript/authoring/authoringMenu.js (.../authoringMenu.js) (revision 06e2eedee66e1ee3087000324a326111dccdbcba) @@ -45,6 +45,7 @@ * Run when branching is selected from menu. Allows placing branching and converge points on canvas. */ addBranching : function(){ + HandlerLib.resetCanvasMode(); var dialog = layout.items.infoDialog.text('Place the branching point'); dialog.dialog('open'); @@ -62,7 +63,7 @@ if (branchingActivity) { // converge point was just place, end of function - HandlerLib.resetCanvasMode(); + HandlerLib.resetCanvasMode(true); dialog.text(''); dialog.dialog('close'); @@ -76,34 +77,86 @@ /** - * Run when grouping is dropped on canvas. Creates a new grouping activity. + * Creates a new grouping activity. */ addGrouping : function() { + HandlerLib.resetCanvasMode(); + canvas.css('cursor', 'url("' + layout.toolMetadata.grouping.iconPath + '"), move') .click(function(event){ - HandlerLib.resetCanvasMode(); - // pageX and pageY tell event coordinates relative to the whole page // we need relative to canvas var translatedEvent = ActivityLib.translateEventOnCanvas(event), x = translatedEvent[0] - 47, y = translatedEvent[1] - 2; layout.activities.push(new ActivityLib.GroupingActivity(null, null, x, y, 'Grouping')); + + HandlerLib.resetCanvasMode(true); }); }, /** - * Run when gate is dropped on canvas. Creates a new gate activity. + * Creates a new annotation Region. */ + addAnnotationRegion : function() { + HandlerLib.resetCanvasMode(); + + var dialog = layout.items.infoDialog.text('Click and hold to start drawing an annotation region'); + dialog.dialog('open'); + + canvas.css('cursor', 'crosshair').mousedown(function(event){ + dialog.text(''); + dialog.dialog('close'); + + var targetElement = paper.getElementByPoint(event.pageX, event.pageY); + + if (targetElement) { + // cancel + HandlerLib.resetCanvasMode(true); + } else { + HandlerLib.drawRegionStartHandler(event); + } + }); + }, + + + /** + * Creates a new annotation label. + */ + addAnnotationLabel : function() { + HandlerLib.resetCanvasMode(); + + var dialog = layout.items.infoDialog.text('Click to add an annotation label'); + dialog.dialog('open'); + + canvas.css('cursor', 'pointer').click(function(event){ + dialog.text(''); + dialog.dialog('close'); + + + var translatedEvent = ActivityLib.translateEventOnCanvas(event), + x = translatedEvent[0], + y = translatedEvent[1]; + + HandlerLib.resetCanvasMode(true); + + DecorationLib.addLabel(x, y); + }); + }, + + + /** + * Creates a new transition. + */ addTransition : function() { + HandlerLib.resetCanvasMode(); + var dialog = layout.items.infoDialog.text('Click on an activity'); dialog.dialog('open'); canvas.css('cursor', 'pointer').click(function(event){ - HandlerLib.resetCanvasMode(); - layout.drawMode = true; dialog.text(''); dialog.dialog('close'); @@ -121,19 +174,21 @@ /** - * Run when gate is dropped on canvas. Creates a new gate activity. + * Creates a new gate activity. */ addGate : function() { + HandlerLib.resetCanvasMode(); + canvas.css('cursor', 'url("' + layout.toolMetadata.gate.iconPath + '"), move').click(function(event){ - HandlerLib.resetCanvasMode(); - // pageX and pageY tell event coordinates relative to the whole page // we need relative to canvas var translatedEvent = ActivityLib.translateEventOnCanvas(event), x = translatedEvent[0], y = translatedEvent[1] + 2; layout.activities.push(new ActivityLib.GateActivity(null, null, x, y)); + + HandlerLib.resetCanvasMode(true); }); }, @@ -253,8 +308,15 @@ * Sorts activities on canvas. */ arrangeActivities : function(){ + if ((layout.regions.length > 0 || layout.labels.length > 0) + && !confirm('There are annotations on the canvas.\n' + + 'They will be not arranged automatically, you will have to adjust them manually later.\n' + + 'Do you want to continue?')) { + return; + } + // just to refresh the state of canvas - HandlerLib.resetCanvasMode(); + HandlerLib.resetCanvasMode(true); if (layout.activities.length == 0) { // no activities, nothing to do @@ -482,7 +544,10 @@ * Removes existing activities and prepares canvas for a new sequence. */ newLearningDesign : function(force, soft){ - if (!force && layout.activities.length > 0 && !confirm('Are you sure you want to remove all existing activities?')){ + if (!force && (layout.activities.length > 0 + || layout.regions.length > 0 + || layout.labels.length > 0) + && !confirm('Are you sure you want to remove all existing elements?')){ return; } @@ -494,6 +559,9 @@ 'maxUIID' : 0 }; layout.activities = []; + layout.regions = []; + layout.labels = []; + if (paper) { paper.clear(); } else { Index: lams_central/web/includes/javascript/authoring/authoringProperty.js =================================================================== diff -u -rc051edc3328ffc90c5c902f938370a974a4e26d8 -r06e2eedee66e1ee3087000324a326111dccdbcba --- lams_central/web/includes/javascript/authoring/authoringProperty.js (.../authoringProperty.js) (revision c051edc3328ffc90c5c902f938370a974a4e26d8) +++ lams_central/web/includes/javascript/authoring/authoringProperty.js (.../authoringProperty.js) (revision 06e2eedee66e1ee3087000324a326111dccdbcba) @@ -405,6 +405,68 @@ /** + * Properties dialog content for regions (annotations). + */ + regionProperties : function() { + var region = this, + content = region.propertiesContent; + if (!content) { + // first run, create the content + content = region.propertiesContent = $('#propertiesContentRegion').clone().attr('id', null) + .show().data('parentObject', region); + $('.propertiesContentFieldTitle', content).val(region.title); + + $('input', content).change(function(){ + // extract changed properties and redraw the transition + var content = $(this).closest('.dialogContainer'), + region = content.data('parentObject'), + redrawNeeded = false, + newTitle = $('.propertiesContentFieldTitle', content).val(); + if (newTitle != region.title) { + region.title = newTitle; + redrawNeeded = true; + } + + if (redrawNeeded) { + region.draw(); + } + }); + } + }, + + + /** + * Properties dialog content for labels (annotations). + */ + labelProperties : function() { + var label = this, + content = label.propertiesContent; + if (!content) { + // first run, create the content + content = label.propertiesContent = $('#propertiesContentLabel').clone().attr('id', null) + .show().data('parentObject', label); + $('.propertiesContentFieldTitle', content).val(label.title); + + $('input', content).change(function(){ + // extract changed properties and redraw the transition + var content = $(this).closest('.dialogContainer'), + label = content.data('parentObject'), + redrawNeeded = false, + newTitle = $('.propertiesContentFieldTitle', content).val(); + if (newTitle != label.title) { + label.title = newTitle; + redrawNeeded = true; + } + + if (redrawNeeded) { + label.draw(); + } + }); + } + }, + + + /** * Find all groupings on canvas and fill dropdown menu with their titles */ fillGroupingDropdown : function(content, grouping) {