summaryrefslogtreecommitdiffstats
path: root/sca-cpp/trunk/modules/edit/htdocs/graph
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--sca-cpp/trunk/modules/edit/htdocs/graph/graph.html39
-rw-r--r--sca-cpp/trunk/modules/edit/htdocs/graph/graph.js400
-rw-r--r--sca-cpp/trunk/modules/edit/htdocs/graph/index.html12
3 files changed, 378 insertions, 73 deletions
diff --git a/sca-cpp/trunk/modules/edit/htdocs/graph/graph.html b/sca-cpp/trunk/modules/edit/htdocs/graph/graph.html
index 5eb8c6cc1e..b078901a29 100644
--- a/sca-cpp/trunk/modules/edit/htdocs/graph/graph.html
+++ b/sca-cpp/trunk/modules/edit/htdocs/graph/graph.html
@@ -31,7 +31,7 @@
<body>
<table style="position: absolute; top: 0px; left: 0px;" width="100%">
-<tr><th style="width: 338px;">Palette</th><th style="padding-top: 0px; padding-bottom: 0px;"><span>App</span><span style="position: absolute; top: 2px; right: 8px;"><input type="button" id="saveButton" style="font-weight: bold;" Value="Save"/></span></th></tr>
+<tr><th style="width: 338px;">Palette</th><th style="padding-top: 0px; padding-bottom: 0px;"><span>Composition</span><span style="position: absolute; top: 2px; right: 8px;"><input type="button" id="saveButton" style="font-weight: bold;" Value="Save"/></span></th></tr>
</table>
<script type="text/javascript">
@@ -43,11 +43,14 @@ var apps = sca.reference(editWidget, "apps");
//rconsole = sca.defun(sca.reference(editWidget, "log"), "log");
/**
- * Return the current app name.
+ * The current app name.
*/
-function appname() {
- return ui.queryParams()['app'];
-}
+var appname = ui.queryParams()['app'];
+
+/**
+ * The current app composite.
+ */
+var composite;
/**
* Return the composite in an ATOM entry.
@@ -65,7 +68,8 @@ function getapp(name, g) {
if (isNil(name))
return;
apps.get(name, function(doc) {
- appendNodes(graph.composite(atomcomposite(doc), graph.mkpath().move(350,0)), g);
+ composite = atomcomposite(doc);
+ graph.edit(composite, graph.composite(composite, graph.mkpath().move(350,0)), g);
});
}
@@ -77,7 +81,7 @@ function getpalette(name, g, bg, palette, gpalettes) {
return;
palettes.get(name, function(doc) {
gpalettes[name] = graph.composite(atomcomposite(doc), graph.mkpath().move(150,0));
- appendNodes(gpalettes[name], name == spalette? g : bg);
+ graph.display(gpalettes[name], name == spalette? g : bg);
});
}
@@ -87,16 +91,31 @@ function getpalette(name, g, bg, palette, gpalettes) {
*/
function installpalette(name, pos, g, bg, palette, gpalettes) {
var b = graph.mkbutton(name, pos);
- appendNodes(mklist(b), g);
+ graph.display(mklist(b), g);
b.onclick = function() {
+
// Display the selected palette
spalette = name;
for (var pn in gpalettes)
- appendNodes(gpalettes[pn], pn == spalette? g : bg);
+ graph.display(gpalettes[pn], pn == spalette? g : bg);
}
getpalette(name, g, bg, palette, gpalettes);
}
+/**
+ * Save the current edited page.
+ */
+$('saveButton').onclick = function(e) {
+
+ // Update the page ATOM entry
+ var compxml = writeXML(composite, false);
+ var entry = '<entry xmlns="http://www.w3.org/2005/Atom">' +
+ '<title type="text">' + appname + '</title><id>' + appname + '</id><content type="application/xml"><item>' +
+ compxml + '</item></content></entry>';
+ apps.put(appname, entry, function() {
+ });
+};
+
// Create editor graph area
var g = graph.mkgraph(graph.mkpath().move(0,50));
var bg = graph.mkgroup(graph.mkpath());
@@ -111,7 +130,7 @@ installpalette('social', graph.mkpath().move(0,220), g, bg, spalette, gpalettes)
installpalette('sensors', graph.mkpath().move(0,290), g, bg, spalette, gpalettes);
// Get and display the current app
-getapp(appname(), g);
+getapp(appname, g);
</script>
</body>
diff --git a/sca-cpp/trunk/modules/edit/htdocs/graph/graph.js b/sca-cpp/trunk/modules/edit/htdocs/graph/graph.js
index c391afaf23..dc5b48e76a 100644
--- a/sca-cpp/trunk/modules/edit/htdocs/graph/graph.js
+++ b/sca-cpp/trunk/modules/edit/htdocs/graph/graph.js
@@ -21,12 +21,12 @@
* SVG and VML composite rendering functions.
*/
-var graph = new Object();
+var graph = {};
/**
* Basic colors
*/
-graph.colors = new Object();
+graph.colors = {};
graph.colors.black = '#000000';
graph.colors.blue = '#0000ff';
graph.colors.cyan = '#00ffff';
@@ -40,6 +40,13 @@ graph.colors.red = '#ff0000';
graph.colors.white = '#ffffff';
graph.colors.yellow = '#ffff00';
+graph.colors.orange1 = '#ffbb00';
+graph.colors.green1 = '#96d333';
+graph.colors.blue1 = '#00c3c9';
+graph.colors.red1 = '#d03f41';
+graph.colors.yellow1 = '#fcee21';
+graph.colors.magenta1 = '#c0688a';
+
/**
* Base path class.
*/
@@ -92,21 +99,31 @@ if (ui.isIE()) {
document.write('<xml:namespace ns="urn:schemas-microsoft-com:vml" prefix="v" />');
/**
- * Make a graph.
+ * Make a VML graph.
*/
- graph.mkgraph = function() {
+ graph.mkgraph = function(pos) {
+
+ // Create div element to host the graph
var div = document.createElement('div');
div.id = 'vmldiv';
+ div.style.position = 'absolute';
+ div.style.left = pos.xpos();
+ div.style.top = pos.ypos();
document.body.appendChild(div);
+ // Create a VML group
var vmlg = document.createElement('v:group');
vmlg.style.width = 5000;
vmlg.style.height = 5000;
vmlg.coordsize = '5000,5000';
div.appendChild(vmlg);
+ // Keep track of the current dragged element
graph.dragging = null;
+ /**
+ * Find the first draggable element in a hierarchy of elements.
+ */
function draggable(n) {
if (n == vmlg)
return null;
@@ -115,53 +132,99 @@ if (ui.isIE()) {
return draggable(n.parentNode);
}
- function bringtotop(n) {
- if (n == vmlg)
- return null;
- n.parentNode.appendChild(n);
- return bringtotop(n.parentNode);
- }
-
+ /**
+ * Handle a mousedown event.
+ */
vmlg.onmousedown = function() {
window.event.returnValue = false;
+
+ // Find draggable element
graph.dragging = draggable(window.event.srcElement);
if (graph.dragging == null)
return false;
- bringtotop(graph.dragging);
+
+ // Bring it to the top
+ graph.bringtotop(graph.dragging, vmlg);
+
+ // Remember mouse position
graph.dragX = window.event.clientX;
graph.dragY = window.event.clientY;
vmlg.setCapture();
return false;
};
+ /**
+ * Handle a mouseup event.
+ */
vmlg.onmouseup = function() {
if (graph.dragging == null)
return false;
+
+ if (graph.dragging.parentNode == vmlg && graph.dragging.id.substring(0, 8) != 'palette:') {
+ if (ui.csspos(graph.dragging.style.left) >= 350) {
+
+ // Add dragged component to the edited composite
+ if (!isNil(graph.dragging.comp) && isNil(graph.dragging.compos)) {
+ var compos = scdl.composite(vmlg.compos);
+ setlist(compos, graph.addcomp(graph.dragging.comp, compos));
+ graph.dragging.compos = vmlg.compos;
+ }
+ } else {
+
+ // Discard top level element dragged out of composite area
+ vmlg.removeChild(graph.dragging);
+ if (!isNil(graph.dragging.comp) && !isNil(graph.dragging.compos)) {
+ var compos = scdl.composite(vmlg.compos);
+ setlist(compos, graph.removecomp(graph.dragging.comp, compos));
+ graph.dragging.compos = vmlg.compos;
+ }
+ }
+ }
+
+ // Forget current dragged element
graph.dragging = null;
vmlg.releaseCapture();
return false;
};
+ /**
+ * Handle a mousemove event.
+ */
vmlg.onmousemove = function() {
if (graph.dragging == null)
return false;
- var origX = graph.dragging.coordorigin.X;
- var origY = graph.dragging.coordorigin.Y;
- var newX = origX - (window.event.clientX - graph.dragX);
- var newY = origY - (window.event.clientY - graph.dragY);
- graph.dragX = window.event.clientX;
- graph.dragY = window.event.clientY;
- if (graph.dragging.id.substring(0, 8) == 'palette:') {
- // Clone an element dragged from the palette
- var clone = graph.compshape(graph.dragging.comp, mklist(), graph.mkpath().move(ui.posn(graph.dragging.style.left), ui.posn(graph.dragging.style.top)));
- graph.dragging.parentNode.appendChild(clone);
- graph.dragging = clone;
- }
- graph.dragging.setAttribute('coordorigin', newX + ' ' + newY);
+ // Calculate new position of dragged element
+ var origX = ui.csspos(graph.dragging.style.left);
+ var origY = ui.csspos(graph.dragging.style.top);
+ var newX = origX + (window.event.clientX - graph.dragX);
+ var newY = origY + (window.event.clientY - graph.dragY);
+ if (newX >= 0)
+ graph.dragX = window.event.clientX;
+ else
+ newX = 0;
+ if (newY >= 0)
+ graph.dragY = window.event.clientY;
+ else
+ newY = 0;
+
+ // Clone an element dragged from the palette
+ if (graph.dragging.id.substring(0, 8) == 'palette:')
+ graph.dragging = graph.clonepalette(graph.dragging);
+
+ // Move the dragged element
+ graph.dragging.style.left = newX;
+ graph.dragging.style.top = newY;
+
+ // Update dragged component position
+ if (!isNil(graph.dragging.comp))
+ setlist(graph.dragging.comp, graph.movecomp(graph.dragging.comp, graph.mkpath().move(newX, newY)));
+
return false;
};
+ // Create hidden spans to help compute the width of
+ // component and reference titles
graph.comptitlewidthdiv = document.createElement('span');
graph.comptitlewidthdiv.style.visibility = 'hidden'
graph.comptitlewidthdiv.style.fontWeight = 'bold'
@@ -268,10 +331,14 @@ if (ui.isIE()) {
* Return a shape representing a component.
*/
graph.compshape = function(comp, cassoc, pos) {
+
+ // Make the component title element
var title = graph.comptitle(comp);
+ // Compute the component shape path
var d = graph.comppath(comp, cassoc).str();
+ // Create the main component shape
var shape = document.createElement('v:shape');
shape.style.width = 5000;
shape.style.height = 5000;
@@ -280,6 +347,7 @@ if (ui.isIE()) {
shape.fillcolor = graph.color(comp);
shape.stroked = 'false';
+ // Create an overlay contour shape
var contour = document.createElement('v:shape');
contour.style.width = 5000;
contour.style.height = 5000;
@@ -294,6 +362,7 @@ if (ui.isIE()) {
stroke.opacity = '20%';
contour.appendChild(stroke);
+ // Create a group and add the component and contour shapes to it
var g = document.createElement('v:group');
g.id = scdl.name(comp);
g.style.width = 5000;
@@ -325,17 +394,23 @@ if (ui.isIE()) {
* Return a shape representing a button.
*/
graph.mkbutton = function(t, pos) {
+
+ // Make the title element
var title = graph.mktitle(t, true, pos);
+
+ // Compute the path of the button shape
var d = graph.buttonpath().str();
+ // Create the main button shape
var shape = document.createElement('v:shape');
shape.style.width = 5000;
shape.style.height = 5000;
shape.coordsize = '5000,5000';
shape.path = d;
- shape.fillcolor = graph.colors.blue;
+ shape.fillcolor = graph.colors.blue1;
shape.stroked = 'false';
+ // Create an overlay contour shape
var contour = document.createElement('v:shape');
contour.style.width = 5000;
contour.style.height = 5000;
@@ -350,6 +425,7 @@ if (ui.isIE()) {
stroke.opacity = '20%';
contour.appendChild(stroke);
+ // Create a group and add the button and contour shapes to it
var g = document.createElement('v:group');
g.style.width = 5000;
g.style.height = 5000;
@@ -370,9 +446,11 @@ if (ui.isIE()) {
graph.svgns='http://www.w3.org/2000/svg';
/**
- * Make a graph.
+ * Make an SVG graph.
*/
graph.mkgraph = function(pos) {
+
+ // Create a div element to host the graph
var div = document.createElement('div');
div.id = 'svgdiv';
div.style.position = 'absolute';
@@ -381,13 +459,18 @@ if (ui.isIE()) {
// -webkit-user-select: none;
document.body.appendChild(div);
+ // Create SVG element
var svg = document.createElementNS(graph.svgns, 'svg');
svg.style.height = 5000;
svg.style.width = 5000;
div.appendChild(svg);
+ // Keep track of current dragged element
graph.dragging = null;
+ /**
+ * Find the first draggable element in a hierarchy of elements.
+ */
function draggable(n) {
if (n == svg)
return null;
@@ -396,37 +479,70 @@ if (ui.isIE()) {
return draggable(n.parentNode);
}
- function bringtotop(n) {
- if (n == svg)
- return null;
- n.parentNode.appendChild(n);
- return bringtotop(n.parentNode);
- }
-
+ /**
+ * Handle a mouse down event.
+ */
svg.onmousedown = function(e) {
if (e.preventDefault)
e.preventDefault();
else
e.returnValue = false;
+
+ // Find draggable element
graph.dragging = draggable(e.target);
if (graph.dragging == null)
return false;
- bringtotop(graph.dragging);
+
+ // Bring it to the top
+ graph.bringtotop(graph.dragging, svg);
+
+ // Remember the mouse position
var pos = typeof e.touches != "undefined" ? e.touches[0] : e;
graph.dragX = pos.screenX;
graph.dragY = pos.screenY;
return false;
};
+ // Support touch devices
svg.ontouchstart = svg.onmousedown;
+ /**
+ * Handle a mouse up event.
+ */
window.onmouseup = function(e) {
if (graph.dragging == null)
return false;
+
+ if (graph.dragging.parentNode == svg && graph.dragging.id.substring(0, 8) != 'palette:') {
+ var pmatrix = graph.dragging.parentNode.getCTM();
+ var matrix = graph.dragging.getCTM();
+ var curX = pmatrix != null? (Number(matrix.e) - Number(pmatrix.e)): Number(matrix.e);
+ if (curX >= 350) {
+
+ // Add dragged component to the edited composite
+ if (!isNil(graph.dragging.comp) && isNil(graph.dragging.compos)) {
+ var compos = scdl.composite(svg.compos);
+ setlist(compos, graph.addcomp(graph.dragging.comp, compos));
+ graph.dragging.compos = svg.compos;
+ }
+ } else {
+
+ // Discard top level element dragged out of composite area
+ svg.removeChild(graph.dragging);
+ if (!isNil(graph.dragging.comp) && !isNil(graph.dragging.compos)) {
+ var compos = scdl.composite(svg.compos);
+ setlist(compos, graph.removecomp(graph.dragging.comp, compos));
+ graph.dragging.compos = svg.compos;
+ }
+ }
+ }
+
+ // Forget current dragged element
graph.dragging = null;
return false;
};
+ // Support touch devices
window.top.onmouseup = window.onmouseup;
window.ontouchend = window.onmouseup;
window.gestureend = window.onmouseup;
@@ -435,6 +551,9 @@ if (ui.isIE()) {
window.ontouchcancel = window.onmouseup;
window.top.ontouchcancel = window.onmouseup;
+ /**
+ * Handle a mouse move event.
+ */
window.onmousemove = function(e) {
if (graph.dragging == null)
return false;
@@ -442,6 +561,8 @@ if (ui.isIE()) {
e.preventDefault();
else
e.returnValue = false;
+
+ // Calculate new position of dragged element
var pmatrix = graph.dragging.parentNode.getCTM();
var matrix = graph.dragging.getCTM();
var curX = pmatrix != null? (Number(matrix.e) - Number(pmatrix.e)): Number(matrix.e);
@@ -458,20 +579,27 @@ if (ui.isIE()) {
else
newY = 0;
- if (graph.dragging.id.substring(0, 8) == 'palette:') {
- // Clone an element dragged from the palette
- var clone = graph.compshape(graph.dragging.comp, mklist(), graph.mkpath());
- graph.dragging.parentNode.appendChild(clone);
- graph.dragging = clone;
- }
+ // Clone an element dragged from the palette
+ if (graph.dragging.id.substring(0, 8) == 'palette:')
+ graph.dragging = graph.clonepalette(graph.dragging);
+
+ // Move the dragged element
graph.dragging.setAttribute('transform', 'translate(' + newX + ',' + newY + ')');
+
+ // Update dragged component position
+ if (!isNil(graph.dragging.comp))
+ setlist(graph.dragging.comp, graph.movecomp(graph.dragging.comp, graph.mkpath().move(newX, newY)));
+
return false;
};
+ // Support touch devices
window.top.onmousemove = window.onmousemove;
window.ontouchmove = window.onmousemove;
window.top.ontouchmove = window.onmousemove;
+ // Create a hidden SVG element to help compute the width
+ // of component and reference titles
graph.titlewidthsvg = document.createElementNS(graph.svgns, 'svg');
graph.titlewidthsvg.style.visibility = 'hidden';
graph.titlewidthsvg.style.height = 0;
@@ -571,14 +699,19 @@ if (ui.isIE()) {
* Return a shape representing a component.
*/
graph.compshape = function(comp, cassoc, pos) {
+
+ // Make the component title
var title = graph.comptitle(comp);
+ // Compute the path of the component shape
var d = graph.comppath(comp, cassoc).str();
+ // Create the main component shape
var shape = document.createElementNS(graph.svgns, 'path');
shape.setAttribute('d', d);
shape.setAttribute('fill', graph.color(comp));
+ // Create an overlay contour shape
var contour = document.createElementNS(graph.svgns, 'path');
contour.setAttribute('d', d);
contour.setAttribute('fill', 'none');
@@ -587,6 +720,7 @@ if (ui.isIE()) {
contour.setAttribute('stroke-opacity', '0.20');
contour.setAttribute('transform', 'translate(1,1)');
+ // Create a group and add the component and contour shapes to it.
var g = document.createElementNS(graph.svgns, 'g');
g.id = scdl.name(comp);
g.setAttribute('transform', 'translate(' + pos.xpos() + ',' + pos.ypos() + ')');
@@ -613,13 +747,19 @@ if (ui.isIE()) {
* Return a shape representing a button.
*/
graph.mkbutton = function(t, pos) {
+
+ // Make the button title
var title = graph.mktitle(t, true);
+
+ // Compute the path of the button shape
var d = graph.buttonpath().str();
+ // Create the main button shape
var shape = document.createElementNS(graph.svgns, 'path');
shape.setAttribute('d', d);
- shape.setAttribute('fill', graph.colors.blue);
+ shape.setAttribute('fill', graph.colors.blue1);
+ // Create an overlay contour shape
var contour = document.createElementNS(graph.svgns, 'path');
contour.setAttribute('d', d);
contour.setAttribute('fill', 'none');
@@ -628,6 +768,7 @@ if (ui.isIE()) {
contour.setAttribute('stroke-opacity', '0.20');
contour.setAttribute('transform', 'translate(1,1)');
+ // Create a group and add the button and contour shapes to it
var g = document.createElementNS(graph.svgns, 'g');
g.setAttribute('transform', 'translate(' + pos.xpos() + ',' + pos.ypos() + ')');
g.appendChild(shape);
@@ -638,6 +779,16 @@ if (ui.isIE()) {
}
/**
+ * Bring an element and its parents to the top.
+ */
+graph.bringtotop = function(n, g) {
+ if (n == g)
+ return null;
+ n.parentNode.appendChild(n);
+ return graph.bringtotop(n.parentNode, g);
+}
+
+/**
* Return the title of a SCDL element.
*/
graph.title = function(e) {
@@ -646,7 +797,17 @@ graph.title = function(e) {
};
/**
- * Return the services and references of a component.
+ * Return the color of a component.
+ */
+graph.color = function(comp) {
+ return memo(comp, 'color', function() {
+ var c = scdl.color(comp);
+ return c == null? graph.colors.blue1 : graph.colors[c];
+ });
+};
+
+/**
+ * Return the services on the top side of a component.
*/
graph.tsvcs = function(comp) {
return memo(comp, 'tsvcs', function() {
@@ -658,6 +819,9 @@ graph.tsvcs = function(comp) {
});
};
+/**
+ * Return the services on the left side of a component.
+ */
graph.lsvcs = function(comp) {
return memo(comp, 'lsvcs', function() {
var svcs = scdl.services(comp);
@@ -676,12 +840,18 @@ graph.lsvcs = function(comp) {
});
};
+/**
+ * Return the references on the bottom side of a component.
+ */
graph.brefs = function(comp) {
return memo(comp, 'brefs', function() {
return filter(function(r) { return scdl.align(r) == 'bottom'; }, scdl.references(comp));
});
};
+/**
+ * Return the references on the right side of a component.
+ */
graph.rrefs = function(comp) {
return memo(comp, 'rrefs', function() {
return filter(function(r) { var a = scdl.align(r); return a == null || a == 'right'; }, scdl.references(comp));
@@ -689,16 +859,6 @@ graph.rrefs = function(comp) {
};
/**
- * Return the color of a component.
- */
-graph.color = function(comp) {
- return memo(comp, 'color', function() {
- var c = scdl.color(comp);
- return c == null? graph.colors.blue : graph.colors[c];
- });
-};
-
-/**
* Return the height of a reference on the right side of a component.
*/
graph.rrefheight = function(ref, cassoc) {
@@ -861,33 +1021,43 @@ graph.tsvcpath = function(svc, cassoc, path) {
* Return a path representing a component.
*/
graph.comppath = function(comp, cassoc) {
- var height = graph.compheight(comp, cassoc);
+
+ // Calculate the width and height of the component shape
var width = graph.compwidth(comp, cassoc);
+ var height = graph.compheight(comp, cassoc);
+ /**
+ * Apply a path rendering function to a list of services or references.
+ */
function renderpath(x, f, cassoc, path) {
if (isNil(x))
return path;
return renderpath(cdr(x), f, cassoc, f(car(x), cassoc, path));
}
+ // Render the services on the top side of the component
var tsvcs = graph.tsvcs(comp);
var path = graph.mkpath().move(10,0);
path = renderpath(tsvcs, graph.tsvcpath, cassoc, path);
+ // Render the references on the right side of the component
var rrefs = graph.rrefs(comp);
path = path.line(width - 10,path.ypos()).rcurve(10,0,0,10);
path = renderpath(rrefs, graph.rrefpath, cassoc, path);
+ // Render the references on the bottom side of the component
var brefs = reverse(graph.brefs(comp));
var boffset = 10 + graph.brefswidth(brefs, cassoc);
path = path.line(path.xpos(),height - 10).rcurve(0,10,-10,0).line(boffset, path.ypos());
path = renderpath(brefs, graph.brefpath, cassoc, path);
+ // Render the services on the top side of the component
var lsvcs = graph.lsvcs(comp);
var loffset = 10 + (length(lsvcs) * 60);
path = path.line(10,path.ypos()).rcurve(-10,0,0,-10).line(path.xpos(), loffset);
path = renderpath(lsvcs, graph.lsvcpath, cassoc, path);
+ // Close the component shape path
path = path.line(0,10).rcurve(0,-10,10,0);
return path.end();
};
@@ -915,15 +1085,31 @@ graph.composite = function(compos, pos) {
var cassoc = scdl.nameToElementAssoc(comps);
var proms = scdl.promotions(compos);
+ /**
+ * Render a component.
+ */
function rendercomp(comp, cassoc, pos) {
+
+ /**
+ * Render the references on the right side of a component.
+ */
function renderrrefs(refs, cassoc, pos) {
+
+ /**
+ * Render a reference on the right side of a component.
+ */
function renderrref(ref, cassoc, pos) {
var target = assoc(scdl.target(ref), cassoc);
if (isNil(target))
return mklist();
+
+ // Render the component target of the reference
return rendercomp(cadr(target), cassoc, pos);
}
+ /**
+ * Move the rendering cursor down below a reference.
+ */
function rendermove(ref, cassoc, pos) {
return pos.clone().rmove(0, graph.rrefheight(ref, cassoc));
}
@@ -933,14 +1119,26 @@ graph.composite = function(compos, pos) {
return append(renderrref(car(refs), cassoc, pos), renderrrefs(cdr(refs), cassoc, rendermove(car(refs), cassoc, pos)));
}
+ /**
+ * Render the references on the bottom side of a component.
+ */
function renderbrefs(refs, cassoc, pos) {
+
+ /**
+ * Render a reference on the bottom side of a component.
+ */
function renderbref(ref, cassoc, pos) {
var target = assoc(scdl.target(ref), cassoc);
if (isNil(target))
return mklist();
+
+ // Render the component target of the reference
return rendercomp(cadr(target), cassoc, pos);
}
+ /**
+ * Move the rendering cursor to the right of a reference.
+ */
function rendermove(ref, cassoc, pos) {
return pos.clone().rmove(graph.brefwidth(ref, cassoc), 0);
}
@@ -950,8 +1148,11 @@ graph.composite = function(compos, pos) {
return append(renderbref(car(refs), cassoc, pos), renderbrefs(cdr(refs), cassoc, rendermove(car(refs), cassoc, pos)));
}
+ // Compute the component shape
var gcomp = graph.compshape(comp, cassoc, pos);
+ // Add the shapes of the components wired to its references
+ // as children elements
var rrefs = graph.rrefs(comp);
var rpos = graph.mkpath().rmove(graph.compwidth(comp, cassoc), 0);
appendNodes(renderrrefs(rrefs, cassoc, rpos), gcomp);
@@ -963,7 +1164,14 @@ graph.composite = function(compos, pos) {
return mklist(gcomp);
}
+ /**
+ * Render a list of promoted service components.
+ */
function renderproms(svcs, cassoc, pos) {
+
+ /**
+ * Return the component promoted by a service.
+ */
function promcomp(svc, cassoc) {
var c = assoc(scdl.promote(svc), cassoc);
if (isNil(c))
@@ -971,12 +1179,18 @@ graph.composite = function(compos, pos) {
return cadr(c);
}
+ /**
+ * Return the position of a component.
+ */
function comppos(comp, pos) {
var x = scdl.x(comp);
var y = scdl.y(comp);
- return graph.mkpath().move(x != null? x : pos.xpos(), y != null? y : pos.ypos());
+ return graph.mkpath().move(x != null? Number(x) + 350 : pos.xpos(), y != null? Number(y) : pos.ypos());
}
+ /**
+ * Move the rendering cursor down below a component.
+ */
function rendermove(comp, cassoc, pos) {
return pos.clone().rmove(0, graph.compclosureheight(comp, cassoc) + 40);
}
@@ -984,6 +1198,8 @@ graph.composite = function(compos, pos) {
if (isNil(svcs))
return mklist();
+ // Render the first promoted component in the list
+ // then recurse to render the rest of the list
var comp = promcomp(car(svcs), cassoc);
if (isNil(comp))
return renderproms(cdr(svcs), cassoc, rendermove(car(svcs), cassoc, pos));
@@ -992,13 +1208,85 @@ graph.composite = function(compos, pos) {
return append(rendercomp(comp, cassoc, cpos), renderproms(cdr(svcs), cassoc, rendermove(comp, cassoc, cpos)));
}
+ // Render the promoted service components
var rproms = renderproms(proms, cassoc, pos.clone().rmove(20,20));
- if (name == 'palette')
+ if (name == 'palette') {
+
+ // Prefix ids of palette component elements with 'palette:'
return map(function(r) {
r.id = 'palette:' + r.id;
return r;
}, rproms);
+ } else {
+
+ // Link app component elements to the containing composite
+ return map(function(r) {
+ r.compos = compos;
+ return r;
+ }, rproms);
+ }
return rproms;
};
+/**
+ * Clone a palette element and the component associated with it.
+ */
+graph.clones = 0;
+graph.clonepalette = function(e) {
+
+ // Clone the component and give it a unique name
+ var comp = append(mklist(element, "'component", mklist(attribute, "'name", scdl.name(e.comp) + (++graph.clones))),
+ filter(function(c) { return !(isAttribute(c) && attributeName(c) == "'name")}, elementChildren(e.comp)));
+
+ // Make the component shape element
+ var clone = graph.compshape(comp, mklist(), graph.mkpath());
+ e.parentNode.appendChild(clone);
+ return clone;
+};
+
+/**
+ * Move a component to the given position.
+ */
+graph.movecomp = function(comp, pos) {
+
+ // Add or set the x and y attributes of the component
+ return append(mklist(element, "'component", mklist(attribute, "'t:x", '' + (pos.xpos() - 350)), mklist(attribute, "'t:y", '' + pos.ypos())),
+ filter(function(e) { return !(isAttribute(e) && (attributeName(e) == "'t:x" || attributeName(e) == "'t:y")); }, elementChildren(comp)));
+};
+
+/**
+ * Add a component to a composite.
+ */
+graph.addcomp = function(comp, compos) {
+ var name = scdl.name(comp);
+ var prom = mklist(element, "'service", mklist(attribute, "'name", name), mklist(attribute, "'promote", name));
+ return append(mklist(element, "'composite"), append(elementChildren(compos), mklist(prom, graph.dragging.comp)));
+}
+
+/**
+ * Remove a component from a composite.
+ */
+graph.removecomp = function(comp, compos) {
+ var name = scdl.name(comp);
+ return append(mklist(element, "'composite"),
+ filter(function(c) { return !(isElement(c) && scdl.name(c) == name); }, elementChildren(compos)));
+}
+
+/**
+ * Display a list of graphical nodes.
+ */
+graph.display = function(nodes, g) {
+ appendNodes(nodes, g);
+ return nodes;
+};
+
+/**
+ * Display and enable editing of a composite and the graphical
+ * nodes that represent it.
+ */
+graph.edit = function(compos, nodes, g) {
+ g.compos = compos;
+ return graph.display(nodes, g);
+};
+
diff --git a/sca-cpp/trunk/modules/edit/htdocs/graph/index.html b/sca-cpp/trunk/modules/edit/htdocs/graph/index.html
index aebc0ece68..e1f0bacdeb 100644
--- a/sca-cpp/trunk/modules/edit/htdocs/graph/index.html
+++ b/sca-cpp/trunk/modules/edit/htdocs/graph/index.html
@@ -18,7 +18,7 @@
-->
<html>
<head>
-<title>App Editor</title>
+<title>App Composition Editor</title>
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0"/>
<meta name="apple-mobile-web-app-capable" content="yes"/>
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"/>
@@ -37,14 +37,12 @@
<script type="text/javascript">
/**
- * Return the current app name.
+ * The current app name.
*/
-function appname() {
- return ui.queryParams()['app'];
-}
+var appname = ui.queryParams()['app'];
// Load the menu bar
-ui.loadwidget('menu', '/menu.html?app=' + appname());
+ui.loadwidget('menu', '/menu.html?app=' + appname);
/**
* Display the editor for an app.
@@ -60,7 +58,7 @@ function editapp(name) {
}
// Display the editor for the current app
-editapp(appname());
+editapp(appname);
</script>
</body>