diff options
Diffstat (limited to 'sca-cpp/trunk/hosting/server/htdocs/graph/index.html')
-rw-r--r-- | sca-cpp/trunk/hosting/server/htdocs/graph/index.html | 865 |
1 files changed, 387 insertions, 478 deletions
diff --git a/sca-cpp/trunk/hosting/server/htdocs/graph/index.html b/sca-cpp/trunk/hosting/server/htdocs/graph/index.html index 34b7ead90e..6f73aec5ec 100644 --- a/sca-cpp/trunk/hosting/server/htdocs/graph/index.html +++ b/sca-cpp/trunk/hosting/server/htdocs/graph/index.html @@ -17,42 +17,11 @@ * specific language governing permissions and limitations * under the License. --> -<div id="bodydiv" class="bodydiv" style="overflow: visible;"> +<div id="bodydiv" class="body"> -<table style="width: 100%;"> -<tr> -<td><h2><span id="appNameHeader"></span></h2></td> -<td style="vertical-align: middle; text-align: right; padding-right: 8px;"><span id="status" style="font-weight: bold; color: #808080;"></span></td> -</tr> -</table> - -<table id="compValueBackground" style="width: 2500px; position: absolute; top: 59px; left: 0px; z-index: -1;"> -<tr> -<th class="thr thl"><span style="display: inline-block; padding-top: 0px; padding-bottom: 0px; height: 24px;"></span></th> -</tr> -</table> - -<table id="compValueTable" style="width: 100%;"> -<tr> -<td class="thl thr" style="text-align: right; padding-right: 2px; vertical-align: top;"> -<span id="deleteCompButton" title="Delete a component" class="graybutton" style="font-weight: bold; font-size: 16px; color: #808080; display: inline-block; width: 24px; height: 20px; padding-top: 0px; padding-bottom: 0px; text-align: center; margin-left: 0px; margin-right: 0px;">-</span> - -<span id="copyCompButton" title="Copy a component" class="graybutton" style="font-weight: bold; font-size: 16px; color: #808080; display: inline-block; width: 24px; height: 20px; padding-top: 0px; padding-bottom: 0px; text-align: center; margin-left: 0px; margin-right: 0px;">c</span> - -<span id="addCompButton" title="Add a component" class="graybutton" style="font-weight: bold; font-size: 16px; display: inline-block; width: 24px; height: 20px; padding-top: 0px; padding-bottom: 0px; text-align: center; margin-left: 0px; margin-right: 0px;">+</span> - -<span id="playCompButton" title="View component value" class="graybutton" style="font-weight: bold; font-size: 16px; color: #808080; display: inline-block; width: 24px; height: 20px; padding-top: 0px; padding-bottom: 0px; text-align: center; margin-left: 0px; margin-right: 0px;">></span> -</td> - -<td class="thl thr" style="padding-left: 2px; padding-right: 2px; vertical-align: top; width: 100%"> -<input id="compValue" type="text" value="" title="Component value" autocapitalize="off" placeholder="Value" style="position: relative; visibility: hidden; width: 100%;"/> -</td> -</tr> -</table> - -<div id="contentdiv" style="margin-top: 4px; width: 2500px;"> -<div id="playdiv" style="position: relative; top: 0x; left: 0px; right: 0px; width: 2500px; height: 5000px; visibility: hidden"> -</div> +<div id="contentdiv" class="viewcontent" style="width: 2500px;"> +<div id="graphdiv" class="graphdiv" style="top: 0px; left: -2500px; width: 5000px; height: 5000px;"></div> +<div id="playdiv" style="position: absolute; top: 0x; left: 0px; width: 2500px; height: 5000px; visibility: hidden"></div> </div> <script type="text/javascript"> @@ -68,36 +37,35 @@ if (isNil(appname)) { ispalette = true; } -// Set page titles -document.title = ui.windowtitle(location.hostname) + ' - ' + (isNil(config.compose)? 'Composition' : config.compose) + ' - ' + appname; -$('appNameHeader').innerHTML = '<a href=\"/' + appname + '/\" target=\"' + '_blank' + '\">' + appname + '</a>'; +// Set page title +document.title = ui.windowtitle(location.hostname) + ' - ' + config.logic + ' - ' + appname; + +// Set header div +$('viewhead').innerHTML = '<span id="appTitle" class="cmenu">' + appname + '</span>' + +'<input type="button" id="deleteCompButton" title="Delete a component" class="graybutton redbutton plusminus" style="position: absolute; top: 4px; left: 5px;" disabled="true" value="-"/>' + +'<span style="position: absolute; top: 0px; left: 45px; right: 115px; padding: 0px; background: transparent;"><input id="compValue" type="text" value="" class="flatentry" title="Component value" autocapitalize="off" placeholder="Value" style="position: absolute; left: 0px; top: 4px; width: 100%; visibility: hidden;" readonly="readonly"/></span>' + +'<input type="button" id="playCompButton" title="View component value" class="graybutton plusminus" style="position: absolute; top: 4px; right: 75px;" disabled="true" value=">"/>' + +'<input type="button" id="copyCompButton" title="Copy a component" class="graybutton bluebutton" style="position: absolute; top: 4px; right: 40px;" disabled="true" value="C"/>' + +'<input type="button" id="addCompButton" title="Add a component" class="graybutton bluebutton plusminus" style="position: absolute; top: 4px; right: 5px;" disabled="true" value="+"/>'; + +/** + * Track the current app composite, author, and saved XML content. + */ +var author = ''; +var editable = false; +var composite; +var savedcomposxml = ''; /** * Component value field, add, delete and play buttons. */ var cvalue = $('compValue'); +var atitle = $('appTitle'); var cadd = $('addCompButton'); var cdelete = $('deleteCompButton'); var ccopy = $('copyCompButton'); var cplay = $('playCompButton'); -// Position background divs -var cvbackground = $('compValueBackground'); -var cvtable = $('compValueTable'); -cvbackground.style.top = ui.pixpos(cvtable.offsetTop); - -/** - * Adjust component value field size. - */ -function resizeFields() { - cvalue.style.width = '0px'; - cvalue.style.width = ui.pixpos(cvalue.parentNode.clientWidth - 18); - return true; -} - -resizeFields(); -window.onresize = resizeFields; - // Init componnent references var editWidget = sca.component("EditWidget"); var palettes = sca.reference(editWidget, "palettes"); @@ -107,7 +75,7 @@ var composites = sca.reference(editWidget, ispalette? "palettes" : "composites") //rconsole = sca.defun(sca.reference(editWidget, "log"), "log"); /** - * SVG composite rendering functions. + * Composite rendering functions. */ var graph = {}; @@ -128,7 +96,7 @@ graph.colors.purple = '#800080'; graph.colors.red = '#ff0000'; graph.colors.white = '#ffffff'; graph.colors.yellow = '#ffff00'; -graph.colors.link = '#598edd'; +graph.colors.link = '#357ae8'; graph.colors.orange1 = '#ffd666'; graph.colors.green1 = '#bbe082'; @@ -173,51 +141,36 @@ graph.buttoncy = 23; graph.curvsz = 4; graph.tabsz = 2; graph.titlex = 4; -graph.titley = 11; -graph.titlew = ui.isMobile()? -2 : 0; +graph.titley = 0; /** - * SVG rendering functions. + * Make a composite graph editor. */ - -graph.svgns='http://www.w3.org/2000/svg'; - -/** - * Make an SVG graph. - */ -graph.mkgraph = function(cdiv, pos, cvalue, cadd, ccopy, cdelete) { - - // Create a div element to host the graph - var div = document.createElement('div'); - div.id = 'svgdiv'; - div.style.position = 'absolute'; - div.style.left = ui.pixpos(pos.xpos() + cdiv.offsetLeft); - div.style.top = ui.pixpos(pos.ypos() + cdiv.offsetTop); - cdiv.appendChild(div); - - // Create SVG element - var svg = document.createElementNS(graph.svgns, 'svg'); - svg.style.height = ui.pixpos(5000); - svg.style.width = ui.pixpos(5000); - div.appendChild(svg); +graph.mkedit = function(graphdiv, pos, atitle, cvalue, cadd, ccopy, cdelete, onchange, onselect) { // Track element dragging and selection graph.dragging = null; graph.dragged = false; - graph.moverenderer = null; graph.selected = null; - cvalue.disabled = true; + cvalue.readOnly = true; cvalue.style.visibility = 'hidden'; + atitle.style.visibility = 'visible'; ccopy.disabled = true; cdelete.disabled = true; + cadd.disabled = !editable; + + // Register event listeners + graph.oncomposchange = onchange; + graph.oncompselect = onselect; /** * Find the first draggable element in a hierarchy of elements. */ function draggable(n) { - if (n == div || n == svg || n == null) + //debug('draggable', n); + if (n == graphdiv || n == null) return null; - if (n.nodeName == 'g' && !isNil(n.id) && n.id != '') + if (n.className == 'g' && !isNil(n.id) && n.id != '') return n; return draggable(n.parentNode); } @@ -255,27 +208,14 @@ graph.mkgraph = function(cdiv, pos, cvalue, cadd, ccopy, cdelete) { }; if (!ui.isMobile()) { - div.onmousedown = function(e) { - //log('onmousedown'); - var suspend = svg.suspendRedraw(10); - var r = onmousedown(e); - svg.unsuspendRedraw(suspend); - return r; + graphdiv.onmousedown = function(e) { + //debug('onmousedown'); + return onmousedown(e); } } else { - div.ontouchstart = function(e) { - //log('ontouchstart'); - - // Clear current move renderer if it's running - if (!isNil(graph.moverenderer)) { - clearInterval(graph.moverenderer); - graph.moverenderer = null; - } - - var suspend = svg.suspendRedraw(10); - var r = onmousedown(e); - svg.unsuspendRedraw(suspend); - return r; + graphdiv.ontouchstart = function(e) { + //debug('ontouchstart'); + return onmousedown(e); } } @@ -298,28 +238,28 @@ graph.mkgraph = function(cdiv, pos, cvalue, cadd, ccopy, cdelete) { return true; } - if (graph.dragging.parentNode == svg && graph.dragging.id.substring(0, 8) != 'palette:') { + if (graph.dragging.parentNode == graphdiv && graph.dragging.id.substring(0, 8) != 'palette:') { // Add new dragged component to the composite if (isNil(graph.dragging.compos)) { - var compos = scdl.composite(svg.compos); + var compos = scdl.composite(graphdiv.compos); setElement(compos, graph.sortcompos(graph.addcomps(mklist(graph.dragging.comp), compos))); - graph.dragging.compos = svg.compos; + graph.dragging.compos = graphdiv.compos; } // Update component position - setElement(graph.dragging.comp, graph.movecomp(graph.dragging.comp, graph.abspos(graph.dragging, svg))); + setElement(graph.dragging.comp, graph.movecomp(graph.dragging.comp, graph.abspos(graph.draggingg))); // Wire component to neighboring reference if (!isNil(graph.dragging.svcpos)) { - var compos = scdl.composite(svg.compos); - setElement(compos, graph.sortcompos(graph.clonerefs(graph.wire(graph.dragging, compos, svg)))); + var compos = scdl.composite(graphdiv.compos); + setElement(compos, graph.sortcompos(graph.clonerefs(graph.wire(graph.dragging, compos, graphdiv)))); } // Snap top level component position to grid - if (graph.dragging.parentNode == svg) { + if (graph.dragging.parentNode == graphdiv) { var gpos = graph.relpos(graph.dragging); - setElement(graph.dragging.comp, graph.movecomp(graph.dragging.comp, graph.mkpath().pos(graph.gridsnap(gpos.xpos()), graph.gridsnap(gpos.ypos())))); + setElement(graph.dragging.comp, graph.movecomp(graph.dragging.comp, graph.mkpath().pos(graph.gridsnap(gpos.x), graph.gridsnap(gpos.y)))); } } @@ -328,45 +268,32 @@ graph.mkgraph = function(cdiv, pos, cvalue, cadd, ccopy, cdelete) { graph.dragged = false; // Refresh the composite - //log('onmouseup refresh'); - var nodes = graph.refresh(svg); + //debug('onmouseup refresh'); + var nodes = graph.refresh(graphdiv); - // Reselected the previously selected component + // Reselect the previously selected component if (!isNil(graph.selected)) { graph.selected = graph.findcompnode(scdl.name(graph.selected.comp), nodes); - graph.compselect(graph.selected, true, cvalue, ccopy, cdelete); + graph.compselect(graph.selected, true, atitle, cvalue, ccopy, cdelete); // Trigger component select event - svg.oncompselect(graph.selected); + graph.oncompselect(graph.selected); } // Trigger composite change event - svg.oncomposchange(false); + graph.oncomposchange(false); return true; }; if (!ui.isMobile()) { - div.onmouseup = function(e) { - //log('onmouseup'); - var suspend = svg.suspendRedraw(10); - var r = onmouseup(e); - svg.unsuspendRedraw(suspend); - return r; + graphdiv.onmouseup = function(e) { + //debug('onmouseup'); + return onmouseup(e); } } else { - div.ontouchend = function(e) { - //log('ontouchend'); - - // Clear current move renderer if it's running - if (!isNil(graph.moverenderer)) { - clearInterval(graph.moverenderer); - graph.moverenderer = null; - } - - var suspend = svg.suspendRedraw(10); - var r = onmouseup(e); - svg.unsuspendRedraw(suspend); - return r; + graphdiv.ontouchend = function(e) { + //debug('ontouchend'); + return onmouseup(e); } } @@ -374,7 +301,7 @@ graph.mkgraph = function(cdiv, pos, cvalue, cadd, ccopy, cdelete) { * Handle a mouse or touch click event. */ function onclick(e) { - //log('onclick logic'); + //debug('onclick logic'); // Find selected component var selected = draggable(e.target); @@ -382,82 +309,78 @@ graph.mkgraph = function(cdiv, pos, cvalue, cadd, ccopy, cdelete) { if (graph.selected != null) { // Reset current selection - graph.compselect(graph.selected, false, cvalue, ccopy, cdelete); + graph.compselect(graph.selected, false, atitle, cvalue, ccopy, cdelete); graph.selected = null; // Trigger component select event - svg.oncompselect(null); + graph.oncompselect(null); } // Dismiss the palette - if (e.target == div || e.target == svg && ui.numpos(div.style.left) != (graph.palcx * -1)) - div.style.left = ui.pixpos(graph.palcx * -1); + if (e.target == graphdiv && ui.numpos(graphdiv.style.left) != (graph.palcx * -1)) + graphdiv.style.left = ui.pixpos(graph.palcx * -1); return true; } - // Ignore multiple click events + + // Ignore duplicate click events if (selected == graph.selected) return true; - if (selected.id.substring(0, 8) == 'palette:' && ui.numpos(div.style.left) != 0) + if (selected.id.substring(0, 8) == 'palette:' && ui.numpos(graphdiv.style.left) != 0) return true; // Deselect previously selected component - graph.compselect(graph.selected, false, cvalue, ccopy, cdelete); + graph.compselect(graph.selected, false, atitle, cvalue, ccopy, cdelete); // Clone component from the palette if (selected.id.substring(0, 8) == 'palette:') { - var compos = scdl.composite(svg.compos); - var comp = graph.clonepalette(selected, compos, svg); + var compos = scdl.composite(graphdiv.compos); + var comp = graph.clonepalette(selected, compos); setElement(compos, graph.sortcompos(graph.addcomps(mklist(comp), compos))); // Move into the editing area and hide the palette - div.style.left = ui.pixpos(graph.palcx * -1); + graphdiv.style.left = ui.pixpos(graph.palcx * -1); // Refresh the composite - //log('onclick refresh'); - var nodes = graph.refresh(svg); + //debug('onclick refresh'); + var nodes = graph.refresh(graphdiv); // Reselect the previously selected component graph.selected = graph.findcompnode(scdl.name(comp), nodes); - graph.compselect(graph.selected, true, cvalue, ccopy, cdelete); + graph.compselect(graph.selected, true, atitle, cvalue, ccopy, cdelete); // Trigger component select event - svg.oncompselect(graph.selected); + graph.oncompselect(graph.selected); // Trigger composite change event - svg.oncomposchange(true); + graph.oncomposchange(true); } else { graph.selected = selected; // Select the component - graph.compselect(graph.selected, true, cvalue, ccopy, cdelete); + graph.compselect(graph.selected, true, atitle, cvalue, ccopy, cdelete); // Trigger component select event - svg.oncompselect(graph.selected); + graph.oncompselect(graph.selected); } - //log('comp selected'); + //debug('comp selected'); e.preventDefault(); return true; } if (!ui.isMobile()) { - div.onclick = function(e) { - //log('div onclick'); - var suspend = svg.suspendRedraw(10); - var r = onclick(e); - svg.unsuspendRedraw(suspend); - return r; + graphdiv.onclick = function(e) { + //debug('onclick'); + return onclick(e); } - svg.onclick = function(e) { - //log('svg onclick'); - var suspend = svg.suspendRedraw(10); - var r = onclick(e); - svg.unsuspendRedraw(suspend); - return r; + } else { + graphdiv.onclick = function(e) { + //debug('onclick'); + return onclick(e); } } @@ -476,18 +399,18 @@ graph.mkgraph = function(cdiv, pos, cvalue, cadd, ccopy, cdelete) { graph.dragged = true; // Cut wire to component - if (graph.dragging.parentNode != svg) { - var compos = scdl.composite(svg.compos); - setElement(compos, graph.sortcompos(graph.cutwire(graph.dragging, compos, svg))); + if (graph.dragging.parentNode != graphdiv) { + var compos = scdl.composite(graphdiv.compos); + setElement(compos, graph.sortcompos(graph.cutwire(graph.dragging, compos, graphdiv))); // Bring component to the top - graph.bringtotop(graph.dragging, svg); + graph.bringtotop(graph.dragging, graphdiv); } // Calculate new position of dragged element var gpos = graph.relpos(graph.dragging); - var newX = gpos.xpos() + (graph.moveX - graph.dragX); - var newY = gpos.ypos() + (graph.moveY - graph.dragY); + var newX = gpos.x + (graph.moveX - graph.dragX); + var newY = gpos.y + (graph.moveY - graph.dragY); if (newX >= graph.palcx) graph.dragX = graph.moveX else @@ -497,9 +420,6 @@ graph.mkgraph = function(cdiv, pos, cvalue, cadd, ccopy, cdelete) { else newY = 0; - // Detach child elements to speedup rendering - graph.compoutline(graph.dragging, true); - // Move the dragged element graph.move(graph.dragging, graph.mkpath().pos(newX, newY)); @@ -508,20 +428,17 @@ graph.mkgraph = function(cdiv, pos, cvalue, cadd, ccopy, cdelete) { if (!ui.isMobile()) { window.onmousemove = function(e) { - //log('onmousemove'); + //debug('onmousemove'); // Remember mouse position graph.moveX = e.screenX; graph.moveY = e.screenY; - var suspend = svg.suspendRedraw(10); - var r = onmousemove(e); - svg.unsuspendRedraw(suspend); - return r; + return onmousemove(e); } } else { - div.ontouchmove = function(e) { - //log('ontouchmove'); + graphdiv.ontouchmove = function(e) { + //debug('ontouchmove'); // Remember touch position var pos = e.touches[0]; @@ -532,15 +449,7 @@ graph.mkgraph = function(cdiv, pos, cvalue, cadd, ccopy, cdelete) { if (graph.moveX == graph.dragX && graph.moveY == graph.dragY) return true; - // Start async move renderer - if (graph.moverenderer == null) { - graph.moverenderer = setInterval(function() { - var suspend = svg.suspendRedraw(10); - onmousemove(e); - svg.unsuspendRedraw(suspend); - }, 10); - } - return true; + return onmousemove(e); } } @@ -550,29 +459,29 @@ graph.mkgraph = function(cdiv, pos, cvalue, cadd, ccopy, cdelete) { function onvaluechange() { if (graph.selected == null) return false; - if (g.parentNode.style.visibility == 'hidden') + if (graphdiv.parentNode.style.visibility == 'hidden') return false; // Change component name and refactor references to it function changename() { - var compos = scdl.composite(svg.compos); + var compos = scdl.composite(graphdiv.compos); cvalue.value = graph.ucid(cvalue.value, compos, false); graph.selected.id = cvalue.value; setElement(compos, graph.sortcompos(graph.renamecomp(graph.selected.comp, compos, cvalue.value))); // Refresh the composite - //log('onchangename refresh'); - var nodes = graph.refresh(svg); + //debug('onchangename refresh'); + var nodes = graph.refresh(graphdiv); // Reselected the previously selected component graph.selected = graph.findcompnode(scdl.name(graph.selected.comp), nodes); - graph.compselect(graph.selected, true, cvalue, ccopy, cdelete); + graph.compselect(graph.selected, true, atitle, cvalue, ccopy, cdelete); // Trigger component select event - svg.oncompselect(graph.selected); + graph.oncompselect(graph.selected); // Trigger composite change event - svg.oncomposchange(true); + graph.oncomposchange(true); return false; } @@ -580,23 +489,24 @@ graph.mkgraph = function(cdiv, pos, cvalue, cadd, ccopy, cdelete) { function changeprop() { graph.setproperty(graph.selected.comp, cvalue.value); var hasprop = graph.hasproperty(graph.selected.comp); - cvalue.disabled = hasprop? false : true; + cvalue.readOnly = (hasprop? false : true) || !editable; cvalue.style.visibility = hasprop? 'visible' : 'hidden'; + atitle.style.visibility = hasprop? 'hidden' : 'visible'; cvalue.value = graph.property(graph.selected.comp); // Refresh the composite - //log('onchangeprop refresh'); - var nodes = graph.refresh(svg); + //debug('onchangeprop refresh'); + var nodes = graph.refresh(graphdiv); // Reselected the previously selected component graph.selected = graph.findcompnode(scdl.name(graph.selected.comp), nodes); - graph.compselect(graph.selected, true, cvalue, ccopy, cdelete); + graph.compselect(graph.selected, true, atitle, cvalue, ccopy, cdelete); // Trigger component select event - svg.oncompselect(graph.selected); + graph.oncompselect(graph.selected); // Trigger composite change event - svg.oncomposchange(true); + graph.oncomposchange(true); return false; } @@ -604,10 +514,7 @@ graph.mkgraph = function(cdiv, pos, cvalue, cadd, ccopy, cdelete) { }; cvalue.onchange = function() { - var suspend = svg.suspendRedraw(10); - var r = onvaluechange(); - svg.unsuspendRedraw(suspend); - return r; + return onvaluechange(); } // Handle delete event @@ -617,33 +524,30 @@ graph.mkgraph = function(cdiv, pos, cvalue, cadd, ccopy, cdelete) { if (graph.selected.id.substring(0, 8) != 'palette:') { // Remove selected component - var compos = scdl.composite(svg.compos); + var compos = scdl.composite(graphdiv.compos); if (isNil(graph.selected.compos)) - setElement(compos, graph.sortcompos(graph.cutwire(graph.selected, compos, svg))); + setElement(compos, graph.sortcompos(graph.cutwire(graph.selected, compos, graphdiv))); setElement(compos, graph.sortcompos(graph.clonerefs(graph.gcollect(graph.removecomp(graph.selected.comp, compos))))); // Reset current selection - graph.compselect(graph.selected, false, cvalue, ccopy, cdelete); + graph.compselect(graph.selected, false, atitle, cvalue, ccopy, cdelete); graph.selected = null; // Refresh the composite - //log('ondelete refresh'); - graph.refresh(svg); + //debug('ondelete refresh'); + graph.refresh(graphdiv); // Trigger component select event - svg.oncompselect(null); + graph.oncompselect(null); // Trigger composite change event - svg.oncomposchange(true); + graph.oncomposchange(true); } return false; }; cdelete.onclick = function() { - var suspend = svg.suspendRedraw(10); - var r = ondeleteclick(); - svg.unsuspendRedraw(suspend); - return r; + return ondeleteclick(); }; // Handle copy event @@ -654,51 +558,50 @@ graph.mkgraph = function(cdiv, pos, cvalue, cadd, ccopy, cdelete) { return false; // Clone the selected component - var compos = scdl.composite(svg.compos); - var comps = graph.clonecomp(graph.selected, compos, svg); + var compos = scdl.composite(graphdiv.compos); + var comps = graph.clonecomp(graph.selected, compos); setElement(compos, graph.sortcompos(graph.addcomps(comps, compos))); // Refresh the composite - //log('onclick refresh'); - var nodes = graph.refresh(svg); + //debug('oncopyclick refresh'); + var nodes = graph.refresh(graphdiv); // Select the component clone graph.selected = graph.findcompnode(scdl.name(car(comps)), nodes); - graph.compselect(graph.selected, true, cvalue, ccopy, cdelete); + graph.compselect(graph.selected, true, atitle, cvalue, ccopy, cdelete); // Trigger component select event - svg.oncompselect(graph.selected); + graph.oncompselect(graph.selected); // Trigger composite change event - svg.oncomposchange(true); + graph.oncomposchange(true); return false; }; ccopy.onclick = function() { - var suspend = svg.suspendRedraw(10); - var r = oncopyclick(); - svg.unsuspendRedraw(suspend); - return r; + return oncopyclick(); }; // Handle add event cadd.onclick = function() { // Show the palette - div.style.left = ui.pixpos(0); + graphdiv.style.left = ui.pixpos(0); return false; }; // Create a hidden SVG element to help compute the width // of component and reference titles - graph.svgtitles = document.createElementNS(graph.svgns, 'svg'); - graph.svgtitles.style.visibility = 'hidden'; - graph.svgtitles.style.height = ui.pixpos(0); - graph.svgtitles.style.width = ui.pixpos(0); - div.appendChild(graph.svgtitles); - - return svg; + graph.offtitles = document.createElement('span'); + graph.offtitles.style.visibility = 'hidden'; + graph.offtitles.position = 'absolute'; + graph.offtitles.top = -500; + graph.offtitles.width = 500; + graph.offtitles.height = 50; + graphdiv.appendChild(graph.offtitles); + + return graphdiv; }; /** @@ -708,12 +611,6 @@ graph.Point = function(x, y) { this.x = x; this.y = y; }; -graph.Point.prototype.xpos = function() { - return this.x; -}; -graph.Point.prototype.ypos = function() { - return this.y; -}; graph.mkpoint = function(x, y) { return new graph.Point(x, y); @@ -723,21 +620,25 @@ graph.mkpoint = function(x, y) { * Path class. */ graph.Path = function() { - this.path = ''; this.x = 0; this.y = 0; + this.xmin = null; + this.xmax = null; + this.xmin = -8; + this.ymax = null; + this.draw = function(ctx) { + return ctx; + }; } graph.Path.prototype.pos = function(x, y) { this.x = x; this.y = y; + if (this.xmin == null || x < this.xmin) this.xmin = x; + if (this.xmax == null || x > this.xmax) this.xmax = x; + if (this.ymin == null || y < this.ymin) this.ymin = y; + if (this.ymax == null || y > this.ymax) this.ymax = y; return this; }; -graph.Path.prototype.xpos = function() { - return this.x; -}; -graph.Path.prototype.ypos = function() { - return this.y; -}; graph.Path.prototype.rmove = function(x, y) { return this.move(this.x + x, this.y + y); }; @@ -747,44 +648,111 @@ graph.Path.prototype.rline = function(x, y) { graph.Path.prototype.rcurve = function(x1, y1, x, y) { return this.curve(this.x + x1, this.y + y1, this.x + x1 + x, this.y + y1 + y); }; -graph.Path.prototype.str = function() { - return this.path; -}; graph.Path.prototype.clone = function() { - return graph.mkpath().pos(this.xpos(), this.ypos()); + return graph.mkpath().pos(this.x, this.y); }; graph.Path.prototype.move = function(x, y) { - this.path += 'M' + x + ',' + y + ' '; + var d = this.draw; + this.draw = function(ctx) { + d(ctx); + ctx.moveTo(x, y); + return ctx; + }; return this.pos(x, y); }; graph.Path.prototype.line = function(x, y) { - this.path += 'L' + x + ',' + y + ' '; + var d = this.draw; + this.draw = function(ctx) { + d(ctx); + ctx.lineTo(x, y); + return ctx; + }; return this.pos(x, y); }; graph.Path.prototype.curve = function(x1, y1, x, y) { - this.path += 'Q' + x1 + ',' + y1 + ' ' + x + ',' + y + ' '; + var d = this.draw; + this.draw = function(ctx) { + d(ctx); + ctx.quadraticCurveTo(x1, y1, x, y); + return ctx; + }; return this.pos(x, y); }; graph.Path.prototype.end = function() { - this.path += 'Z'; + var d = this.draw; + this.draw = function(ctx) { + ctx.beginPath(); + d(ctx); + ctx.fill(); + ctx.beginPath(); + d(ctx); + ctx.stroke(); + }; return this; }; +graph.Path.prototype.bounds = function() { + var width = this.xmin == null || this.xmax == null? 0 : this.xmax - this.xmin + 1; + var height = this.ymin == null || this.ymax == null? 0 : this.ymax - this.ymin + 1; + return graph.mkpath().pos(width, height); +}; graph.mkpath = function() { return new graph.Path(); }; /** + * Translate the position of an element. + */ +graph.translate = function(g, x, y) { + var t = 'translate(' + ui.pixpos(x) + ',' + ui.pixpos(y) + ')'; + g.style.setProperty('-webkit-transform', t, null); + g.style.setProperty('-moz-transform', t, null); + g.style.setProperty('-o-transform', t, null); + g.style.setProperty('transform', t, null); + g.ctmx = x; + g.ctmy = y; + return g; +}; + +/** + * Apply a path to an element. + */ +graph.drawshape = function(g) { + // Set shape element size + var b = g.path.bounds(); + g.width = b.x + 4; + g.height = b.y + 4; + + // Get canvas context + var ctx = g.getContext('2d'); + ctx.save(); + + // Apply translation + ctx.translate((g.path.xmin * -1) + 2, (g.path.ymin * -1) + 2); + + // Draw the shape + ctx.fillStyle = g.fillStyle; + ctx.strokeStyle = !isNil(g.strokeStyle)? g.strokeStyle : graph.colors.gray; + ctx.lineWidth = !isNil(g.lineWidth)? g.lineWidth : 1; + g.path.draw(ctx); + + // Reset canvas context + ctx.restore(); + return g; +} + +/** * Return an element representing a title. */ graph.mktitle = function(t, x, y) { - var title = document.createElementNS(graph.svgns, 'text'); - title.setAttribute('x', x); - title.setAttribute('y', y); - title.setAttribute('class', 'svgtitle'); - title.setAttribute('pointer-events', 'none'); + var title = document.createElement('span'); + title.className = 'gtitle'; + title.style.left = ui.pixpos(x); + title.style.top = ui.pixpos(y); title.appendChild(document.createTextNode(t)); - graph.svgtitles.appendChild(title); + graph.offtitles.appendChild(title); + title.style.width = ui.pixpos(title.clientWidth + 2); + title.style.height = ui.pixpos(title.clientHeight + 2); return title; }; @@ -808,34 +776,38 @@ graph.comptitlewidth = function(comp) { var title = graph.comptitle(comp); if (isNil(title)) return 0; - return title.getBBox().width + graph.titlew; + return title.clientWidth; }; /** * Draw a component shape selection. */ -graph.compselect = function(g, s, cvalue, ccopy, cdelete) { +graph.compselect = function(g, s, atitle, cvalue, ccopy, cdelete) { if (isNil(g) || !s) { cvalue.value = ''; - cvalue.disabled = true; + cvalue.readOnly = true; cvalue.style.visibility = 'hidden'; + atitle.style.visibility = 'visible'; ccopy.disabled = true; cdelete.disabled = true; if (isNil(g)) return true; - g.shape.setAttribute('stroke', graph.colors.gray); - g.shape.setAttribute('stroke-width', '1'); + g.shape.strokeStyle = null; + g.shape.lineWidth = null; + graph.drawshape(g.shape); return true; } cvalue.value = graph.hasproperty(g.comp)? graph.property(g.comp) : g.id; - cvalue.disabled = false; + cvalue.readOnly = false || !editable; cvalue.style.visibility = 'visible'; - ccopy.disabled = false; - cdelete.disabled = false; + atitle.style.visibility = 'hidden'; + ccopy.disabled = false || !editable; + cdelete.disabled = false || !editable; - g.shape.setAttribute('stroke', graph.colors.link); - g.shape.setAttribute('stroke-width', '2'); + g.shape.strokeStyle = graph.colors.link; + g.shape.lineWidth = 2; + graph.drawshape(g.shape); g.parentNode.appendChild(g); return true; }; @@ -847,84 +819,54 @@ graph.paletteselect = function(g, s) { if (isNil(g)) return true; if (!s) { - g.shape.setAttribute('stroke', graph.colors.gray); - g.shape.setAttribute('stroke-width', '1'); + g.shape.strokeStyle = null; + g.shape.lineWidth = null; + graph.drawshape(g.shape); return true; } - g.shape.setAttribute('stroke', graph.colors.link); - g.shape.setAttribute('stroke-width', '2'); + g.shape.strokeStyle = graph.colors.link; + g.shape.lineWidth = 2; + graph.drawshape(g.shape); g.parentNode.appendChild(g); return true; }; /** - * Draw a component outline for faster rendering. - */ -graph.compoutline = function(g, s) { - if (s == (isNil(g.outlined)? false : g.outlined)) - return true; - g.outlined = s; - - if (s) { - g.shape.setAttribute('fill', 'none'); - if (!isNil(g.title)) - g.removeChild(g.title); - } else { - g.shape.setAttribute('fill', graph.color(g.comp)); - if (!isNil(g.title)) - g.appendChild(g.title); - } - - map(function(r) { - var n = caddr(r); - if (isNil(n)) - return r; - graph.compoutline(n, s); - return r; - }, g.refpos); - return true; -}; - -/** * Return a node representing a component. */ -graph.compnode = function(comp, cassoc, pos, parentg) { +graph.compnode = function(comp, cassoc, pos) { + //debug('compnode', graph.title(comp)); + + // Create the component shape + var shape = document.createElement('canvas'); + shape.className = 'path'; + shape.fillStyle = graph.color(comp); + shape.path = graph.comppath(comp, cassoc); + graph.drawshape(shape); // Make the component title element var title = graph.comptitle(comp); - // Compute the path of the component shape - var path = graph.comppath(comp, cassoc); - - // Create the main component shape - var shape = document.createElementNS(graph.svgns, 'path'); - shape.setAttribute('d', path.str()); - shape.setAttribute('fill', graph.color(comp)); - //shape.setAttribute('fill-opacity', '0.6'); - shape.setAttribute('stroke', graph.colors.gray); - shape.setAttribute('stroke-width', '1'); - shape.setAttribute('pointer-events', 'visible'); - - // Create an svg group and add the shape and title to it - var g = document.createElementNS(graph.svgns, 'g'); + // Create a span group element and add the shape and title to it + var g = document.createElement('span'); + g.className = 'g'; g.comp = comp; g.id = scdl.name(comp); - g.setAttribute('transform', 'translate(' + pos.xpos() + ',' + pos.ypos() + ')'); + graph.translate(g, pos.x, pos.y); g.pos = pos.clone(); g.appendChild(shape); g.shape = shape; + g.style.width = ui.pixpos(shape.width); + g.style.height = ui.pixpos(shape.height); if (!isNil(title)) { + title.style.left = ui.pixpos(shape.path.xmin * -1); g.appendChild(title); - g.title = title; } - // Store the the positions of the services and references - g.refpos = reverse(path.refpos); - g.svcpos = reverse(path.svcpos); - - // Handle onclick events - g.onclick = parentg.onclick; + // Store the positions of the services and references + g.refpos = reverse(shape.path.refpos); + g.svcpos = reverse(shape.path.svcpos); return g; }; @@ -949,8 +891,9 @@ graph.findcompnode = function(name, nodes) { * Return a graphical group. */ graph.mkgroup = function(pos) { - var g = document.createElementNS(graph.svgns, 'g'); - g.setAttribute('transform', 'translate(' + pos.xpos() + ',' + pos.ypos() + ')'); + var g = document.createElement('div'); + g.className = 'g'; + graph.translate(g, pos.x, pos.y); g.pos = pos.clone(); return g; }; @@ -960,24 +903,20 @@ graph.mkgroup = function(pos) { */ graph.mkbutton = function(t, pos) { + // Create the main button shape + var shape = document.createElement('canvas'); + shape.className = 'path'; + shape.fillStyle = graph.colors.lightgray1; + shape.path = graph.buttonpath(); + graph.drawshape(shape); + // Make the button title var title = graph.mktitle(t, graph.titlex, graph.titley); - // Compute the path of the button shape - var path = graph.buttonpath().str(); - - // Create the main button shape - var shape = document.createElementNS(graph.svgns, 'path'); - shape.setAttribute('d', path); - shape.setAttribute('fill', graph.colors.lightgray1); - //shape.setAttribute('fill-opacity', '0.6'); - shape.setAttribute('stroke', graph.colors.gray); - shape.setAttribute('stroke-width', '1'); - shape.setAttribute('pointer-events', 'visible'); - - // Create a group and add the button shape to it - var g = document.createElementNS(graph.svgns, 'g'); - g.setAttribute('transform', 'translate(' + pos.xpos() + ',' + pos.ypos() + ')'); + // Create a group and add the button shape and title to it + var g = document.createElement('span'); + g.className = 'g'; + graph.translate(g, pos.x, pos.y); g.pos = pos.clone(); g.appendChild(shape); g.appendChild(title); @@ -989,33 +928,32 @@ graph.mkbutton = function(t, pos) { }; /** - * Return the relative position of a node. + * Return the position of a node relative to its parent. */ -graph.relpos = function(e) { - var pmatrix = e.parentNode != null? e.parentNode.getCTM() : null; - var matrix = e.getCTM(); - var curX = pmatrix != null? (Number(matrix.e) - Number(pmatrix.e)): Number(matrix.e); - var curY = pmatrix != null? (Number(matrix.f) - Number(pmatrix.f)): Number(matrix.f); +graph.relpos = function(g) { + var curX = g.ctmx? g.ctmx : 0; + var curY = g.ctmy? g.ctmy : 0; return graph.mkpath().pos(curX, curY); }; /** * Move a node. */ -graph.move = function(e, pos) { - e.setAttribute('transform', 'translate(' + pos.xpos() + ',' + pos.ypos() + ')'); - e.pos = pos.clone(); +graph.move = function(g, pos) { + g.pos = pos.clone(); + graph.translate(g, g.pos.x, g.pos.y); + return g; }; /** * Return the absolute position of a component node. */ -graph.abspos = function(e, g) { - if (e == g) +graph.abspos = function(e) { + if (isNil(e) || e == graphdiv) return graph.mkpath(); var gpos = graph.relpos(e); - var pgpos = graph.abspos(e.parentNode, g); - return graph.mkpath().pos(gpos.xpos() + pgpos.xpos(), gpos.ypos() + pgpos.ypos()); + var pgpos = graph.abspos(e.parentNode); + return graph.mkpath().pos(gpos.x + pgpos.x, gpos.y + pgpos.y); }; /** @@ -1024,7 +962,7 @@ graph.abspos = function(e, g) { graph.bringtotop = function(n, g) { if (n == g) return null; - graph.move(n, graph.abspos(n, g)); + graph.move(n, graph.abspos(n)); g.appendChild(n); } @@ -1211,12 +1149,12 @@ graph.rrefpath = function(ref, cassoc, path, maxheight) { var height = graph.rrefheight(ref, cassoc); // Record reference position in the path - var xpos = path.xpos(); - var ypos = path.ypos(); + var xpos = path.x; + var ypos = path.y; path.refpos = cons(mklist(ref, graph.mkpath().pos(xpos, ypos + (graph.tabsz * 5))), path.refpos); // Compute the reference path - return path.rline(0,graph.tabsz * 2).rcurve(0,graph.tabsz,-graph.tabsz,0).rcurve(-graph.tabsz,0,0,-graph.tabsz/2.0).rcurve(0,-graph.tabsz/2.0,-graph.tabsz,0).rcurve(-graph.tabsz,0,0,graph.tabsz/2.0).rline(0,graph.tabsz * 3).rcurve(0,graph.tabsz/2.0,graph.tabsz,0).rcurve(graph.tabsz,0,0,-graph.tabsz/2.0).rcurve(0,-graph.tabsz/2.0,graph.tabsz,0).rcurve(graph.tabsz,0,0,graph.tabsz).line(path.xpos(), Math.min(ypos + height, maxheight)); + return path.rline(0,graph.tabsz * 2).rcurve(0,graph.tabsz,-graph.tabsz,0).rcurve(-graph.tabsz,0,0,-graph.tabsz/2.0).rcurve(0,-graph.tabsz/2.0,-graph.tabsz,0).rcurve(-graph.tabsz,0,0,graph.tabsz/2.0).rline(0,graph.tabsz * 3).rcurve(0,graph.tabsz/2.0,graph.tabsz,0).rcurve(graph.tabsz,0,0,-graph.tabsz/2.0).rcurve(0,-graph.tabsz/2.0,graph.tabsz,0).rcurve(graph.tabsz,0,0,graph.tabsz).line(path.x, Math.min(ypos + height, maxheight)); }; /** @@ -1226,12 +1164,12 @@ graph.lsvcpath = function(svc, cassoc, path, minheight) { var height = graph.tabsz * 8; // Record service position in the path - var xpos = path.xpos(); - var ypos = path.ypos(); + var xpos = path.x; + var ypos = path.y; path.svcpos = cons(mklist(svc, graph.mkpath().pos(xpos, ypos - (graph.tabsz * 6))), path.svcpos); // Compute the service path - return path.rline(0, -(graph.tabsz * 2)).rcurve(0,-graph.tabsz,-graph.tabsz,0).rcurve(-graph.tabsz,0,0,graph.tabsz/2.0).rcurve(0,graph.tabsz/2.0,-graph.tabsz,0).rcurve(-graph.tabsz,0,0,-graph.tabsz/2.0).rline(0,-(graph.tabsz * 3)).rcurve(0,-graph.tabsz/2.0,graph.tabsz,0).rcurve(graph.tabsz,0,0,graph.tabsz/2.0).rcurve(0,graph.tabsz/2.0,graph.tabsz,0).rcurve(graph.tabsz,0,0,-graph.tabsz).line(path.xpos(), Math.max(ypos - height, minheight)); + return path.rline(0, -(graph.tabsz * 2)).rcurve(0,-graph.tabsz,-graph.tabsz,0).rcurve(-graph.tabsz,0,0,graph.tabsz/2.0).rcurve(0,graph.tabsz/2.0,-graph.tabsz,0).rcurve(-graph.tabsz,0,0,-graph.tabsz/2.0).rline(0,-(graph.tabsz * 3)).rcurve(0,-graph.tabsz/2.0,graph.tabsz,0).rcurve(graph.tabsz,0,0,graph.tabsz/2.0).rcurve(0,graph.tabsz/2.0,graph.tabsz,0).rcurve(graph.tabsz,0,0,-graph.tabsz).line(path.x, Math.max(ypos - height, minheight)); }; /** @@ -1260,17 +1198,17 @@ graph.comppath = function(comp, cassoc) { // Render the references on the right side of the component var rrefs = graph.rrefs(comp); - path = path.line(width - graph.curvsz,path.ypos()).rcurve(graph.curvsz,0,0,graph.curvsz); + path = path.line(width - graph.curvsz,path.y).rcurve(graph.curvsz,0,0,graph.curvsz); path = renderpath(rrefs, graph.rrefpath, cassoc, path, height - graph.curvsz); // Render the references on the bottom side of the component var boffset = graph.curvsz; - path = path.line(path.xpos(),height - graph.curvsz).rcurve(0,graph.curvsz,graph.curvsz * -1,0).line(boffset, path.ypos()); + path = path.line(path.x,height - graph.curvsz).rcurve(0,graph.curvsz,graph.curvsz * -1,0).line(boffset, path.y); // Render the services on the left side of the component var lsvcs = graph.lsvcs(comp); var loffset = graph.curvsz + (length(lsvcs) * (graph.tabsz * 8)); - path = path.line(graph.curvsz,path.ypos()).rcurve(graph.curvsz * -1,0,0,graph.curvsz * -1).line(path.xpos(), loffset); + path = path.line(graph.curvsz,path.y).rcurve(graph.curvsz * -1,0,0,graph.curvsz * -1).line(path.x, loffset); path = renderpath(lsvcs, graph.lsvcpath, cassoc, path, graph.curvsz); // Close the component node path @@ -1285,7 +1223,7 @@ graph.comppath = function(comp, cassoc) { graph.comppos = function(comp, pos) { var x = scdl.x(comp); var y = scdl.y(comp); - return graph.mkpath().pos(x != null? Number(x) + graph.palcx : pos.xpos(), y != null? Number(y) : pos.ypos()); + return graph.mkpath().pos(x != null? Number(x) + graph.palcx : pos.x, y != null? Number(y) : pos.y); }; /** @@ -1293,9 +1231,9 @@ graph.comppos = function(comp, pos) { */ graph.buttonpath = function(t) { var path = graph.mkpath().move(graph.curvsz,0); - path = path.line(graph.buttoncx - graph.curvsz,path.ypos()).rcurve(graph.curvsz,0,0,graph.curvsz); - path = path.line(path.xpos(),graph.buttoncy - graph.curvsz).rcurve(0,graph.curvsz,-graph.curvsz,0).line(graph.curvsz, path.ypos()); - path = path.line(graph.curvsz,path.ypos()).rcurve(-graph.curvsz,0,0,-graph.curvsz).line(path.xpos(), graph.curvsz); + path = path.line(graph.buttoncx - graph.curvsz,path.y).rcurve(graph.curvsz,0,0,graph.curvsz); + path = path.line(path.x,graph.buttoncy - graph.curvsz).rcurve(0,graph.curvsz,-graph.curvsz,0).line(graph.curvsz, path.y); + path = path.line(graph.curvsz,path.y).rcurve(-graph.curvsz,0,0,-graph.curvsz).line(path.x, graph.curvsz); path = path.line(0,graph.curvsz).rcurve(0,-graph.curvsz,graph.curvsz,0); return path.end(); }; @@ -1303,7 +1241,7 @@ graph.buttonpath = function(t) { /** * Render a SCDL composite into a list of component nodes. */ -graph.composite = function(compos, pos, aspalette, g) { +graph.composite = function(compos, pos, aspalette) { var name = scdl.name(scdl.composite(compos)); var comps = scdl.components(compos); var cassoc = scdl.nameToElementAssoc(comps); @@ -1355,7 +1293,7 @@ graph.composite = function(compos, pos, aspalette, g) { } // Compute the component shape - var gcomp = graph.compnode(comp, cassoc, pos, g); + var gcomp = graph.compnode(comp, cassoc, pos); // Render the components wired to the component references var rrefs = graph.rrefs(comp); @@ -1424,7 +1362,7 @@ graph.composite = function(compos, pos, aspalette, g) { return map(function(r) { r.id = 'palette:' + r.id; var gpos = r.pos; - graph.move(r, graph.mkpath().pos(gpos.xpos() - graph.palcx, gpos.ypos())); + graph.move(r, graph.mkpath().pos(gpos.x - graph.palcx, gpos.y)); return r; }, rproms); @@ -1470,7 +1408,7 @@ graph.ucid = function(prefix, compos1, compos2, clone) { /** * Clone a palette component node. */ -graph.clonepalette = function(e, compos, g) { +graph.clonepalette = function(e, compos) { // Clone the SCDL component and give it a unique name var wcomp = append(mklist(element, "'component", mklist(attribute, "'name", graph.ucid(scdl.name(e.comp), compos, compos, true))), @@ -1480,7 +1418,7 @@ graph.clonepalette = function(e, compos, g) { var comp = car(scdl.components(mklist(rcompos))); // Update component position - setElement(comp, graph.movecomp(comp, graph.abspos(e, g).rmove(graph.palcx, 0))); + setElement(comp, graph.movecomp(comp, graph.abspos(e).rmove(graph.palcx, 0))); return comp; }; @@ -1492,7 +1430,7 @@ graph.movecomp = function(comp, pos) { if (isNil(pos)) return append(mklist(element, "'component"), filter(function(e) { return !(isAttribute(e) && (attributeName(e) == "'x" || attributeName(e) == "'y")); }, elementChildren(comp))); - return append(mklist(element, "'component", mklist(attribute, "'x", '' + (pos.xpos() - graph.palcx)), mklist(attribute, "'y", '' + pos.ypos())), + return append(mklist(element, "'component", mklist(attribute, "'x", '' + (pos.x - graph.palcx)), mklist(attribute, "'y", '' + pos.y)), filter(function(e) { return !(isAttribute(e) && (attributeName(e) == "'x" || attributeName(e) == "'y")); }, elementChildren(comp))); }; @@ -1506,7 +1444,7 @@ graph.gridsnap = function(x) { /** * Clone a component node and all the components it references. */ -graph.clonecomp = function(e, compos, g) { +graph.clonecomp = function(e, compos) { // Write the component and the components it references to XML function collectcomp(e) { @@ -1546,7 +1484,7 @@ graph.clonecomp = function(e, compos, g) { // Update the top component position var comp = car(comps); - setElement(comp, graph.movecomp(comp, graph.abspos(e, g).rmove(10, 10))); + setElement(comp, graph.movecomp(comp, graph.abspos(e).rmove(10, 10))); return comps; }; @@ -1731,7 +1669,7 @@ graph.wire = function(n, compos, g) { // Compute position of the component's service node var spos = cadr(car(n.svcpos)); - var aspos = graph.abspos(n, g).rmove(spos.xpos(), spos.ypos()); + var aspos = graph.abspos(n).rmove(spos.x, spos.y); /** * Find closest unwired reference node among all the references @@ -1754,9 +1692,9 @@ graph.wire = function(n, compos, g) { return closerefs(npos, cdr(refs), spos, cref); // Compute distance between service node and reference node - var rpos = cadr(ref).clone().rmove(npos.xpos(), npos.ypos()); - var dx = Math.pow(rpos.xpos() - spos.xpos(), 2); - var dy = Math.pow(rpos.ypos() - spos.ypos(), 2); + var rpos = cadr(ref).clone().rmove(npos.x, npos.y); + var dx = Math.pow(rpos.x - spos.x, 2); + var dy = Math.pow(rpos.y - spos.y, 2); // Check for proximity threshold var rdist = (dx < (graph.proxcx * graph.proxcx) && dy < (graph.proxcy * graph.proxcy))? Math.sqrt(dx + dy) : 25000000; @@ -1774,7 +1712,7 @@ graph.wire = function(n, compos, g) { return closecomprefs(cdr(nodes), spos, cref); // Compute the component absolute position - var npos = graph.abspos(node, g); + var npos = graph.abspos(node); // Go through all the components and their references return closecomprefs(append(nodeList(node.childNodes), cdr(nodes)), spos, closerefs(npos, node.refpos, spos, cref)); @@ -1800,13 +1738,10 @@ graph.wire = function(n, compos, g) { /** * Display a list of graphical nodes. */ -graph.display = function(nodes, g, svg) { - var suspend = svg.suspendRedraw(10); +graph.display = function(nodes, g) { // Append the nodes to the graphical canvas appendNodes(nodes, g); - - svg.unsuspendRedraw(suspend); return nodes; }; @@ -1824,13 +1759,13 @@ graph.hide = function(g) { * Refresh a graph. */ graph.refresh = function(g) { - //log('refresh'); + //debug('refresh'); // Remove existing nodes from the graph map(function(n) { if (!isNil(n.comp) && n.id.substr(0, 8) != 'palette:') { g.removeChild(n); } return n; }, nodeList(g.childNodes)); // Redisplay the composite associated with the graph - var nodes = graph.composite(g.compos, graph.mkpath().pos(graph.palcx,0), false, g); + var nodes = graph.composite(g.compos, graph.mkpath().pos(graph.palcx,0), false); appendNodes(nodes, g); return nodes; }; @@ -1839,51 +1774,29 @@ graph.refresh = function(g) { * Display and enable editing of a composite and the graphical * nodes that represent it. */ -graph.edit = function(appname, compos, nodes, onchange, onselect, g) { - var suspend = g.suspendRedraw(10); +graph.edit = function(appname, compos, nodes, g) { - // Store the appname and composite in the graphical canvas - g.appname = appname; + // Store the composite elements, and sort them to allow for change detection later g.compos = compos; - - // Sort the composite elements now to allow for change detection later var scompos = scdl.composite(g.compos); setElement(scompos, graph.sortcompos(scompos)); - // Store event listeners - g.oncomposchange = onchange; - g.oncompselect = onselect; - // Remove existing nodes from the graph map(function(n) { if (!isNil(n.comp) && n.id.substr(0, 8) != 'palette:') { g.removeChild(n); } return n; }, nodeList(g.childNodes)); // Display the composite nodes appendNodes(nodes, g); - - g.unsuspendRedraw(suspend); return nodes; }; /** - * Track the current app composite and corresponding saved XML content. - */ -var savedcomposxml = ''; -var composite; - -/** * Track the composition graph, whether it's visible or not and the selected component. */ -var g; -var gdiv; -var bg; var gvisible = true; var gcomp = null; var cdiv = $('contentdiv'); var pdiv = $('playdiv'); - -// Position play div inside the content div -pdiv.style.position = 'absolute'; -pdiv.style.top = cdiv.offsetTop + 'px'; +var graphdiv = $('graphdiv'); /** * Track the palettes. @@ -1893,20 +1806,7 @@ var spalette = 'control'; var bpalette = null; /** - * Return the composite in an ATOM entry. - */ -function atomcomposite(doc) { - var entry = atom.readATOMEntry(mklist(doc)); - if (isNil(entry)) - return mklist(); - var content = namedElementChild("'content", car(entry)); - if (content == null) - return mklist(); - return elementChildren(content); -} - -/** - * Get and display an app. + * Get and display an application composite. */ function getapp(name, g) { if (isNil(name)) @@ -1917,12 +1817,14 @@ function getapp(name, g) { // Stop now if we didn't get a composite if (doc == null) { - showStatus('No data'); + showError('App not available'); return false; } - showStatus(defaultStatus()); - composite = atomcomposite(doc); + // Get the composite from the ATOM entry + var composentry = car(atom.readATOMEntry(mklist(doc))); + var content = namedElementChild("'content", composentry); + composite = isNil(content)? mklist() : elementChildren(content); if (isNil(composite)) { // Create a default empty composite if necessary @@ -1932,10 +1834,16 @@ function getapp(name, g) { } // Display the composite - graph.edit(name, composite, graph.composite(composite, graph.mkpath().move(graph.palcx,0), false, g), oncomposchange, oncompselect, g); + graph.edit(name, composite, graph.composite(composite, graph.mkpath().move(graph.palcx,0), false, g), g); // Track the saved composite XML savedcomposxml = car(writeXML(composite, false)); + + // Enable author to edit the composite + author = elementValue(namedElementChild("'author", composentry)); + editable = author == username; + cadd.disabled = !editable; + showStatus(editable? defaultStatus() : 'Read only'); return true; }); } @@ -1943,19 +1851,22 @@ function getapp(name, g) { /** * Display a palette. Get it from the server if needed. */ -function displaypalette(name, g, svg, palette, gpalettes) { +function displaypalette(name, g, palette, gpalettes) { if (isNil(name)) return; if (isNil(gpalettes[name])) { // Get the palette from the server palettes.get(name, function(doc) { - gpalettes[name] = graph.composite(atomcomposite(doc), graph.mkpath().move(2580,0), true, g); - graph.display(gpalettes[name], g, svg); + var entry = car(atom.readATOMEntry(mklist(doc))); + var content = namedElementChild("'content", entry); + var compos = isNil(content)? mklist() : elementChildren(content); + gpalettes[name] = graph.composite(compos, graph.mkpath().move(2580,0), true, g); + graph.display(gpalettes[name], g); }); return true; } - graph.display(gpalettes[name], g, svg); + graph.display(gpalettes[name], g); return true; } @@ -1965,16 +1876,16 @@ function displaypalette(name, g, svg, palette, gpalettes) { */ function installpalette(name, pos, g, bg, palette, gpalettes) { var b = graph.mkbutton(name, pos); - graph.display(mklist(b), g, g); + graph.display(mklist(b), g); b.onclick = function(e) { // Swap the selected palette graph.paletteselect(bpalette, false); - displaypalette(spalette, bg, g, palette, gpalettes); + displaypalette(spalette, bg, palette, gpalettes); bpalette = b; graph.paletteselect(b, true); spalette = name; - return displaypalette(spalette, g, g, palette, gpalettes); + return displaypalette(spalette, g, palette, gpalettes); }; if (name != spalette) { @@ -1986,7 +1897,7 @@ function installpalette(name, pos, g, bg, palette, gpalettes) { // Display the selected palette graph.paletteselect(b, true); - displaypalette(name, g, g, palette, gpalettes); + displaypalette(name, g, palette, gpalettes); return b; } @@ -1998,8 +1909,8 @@ function save(savexml) { showStatus('Saving'); savedcomposxml = savexml; var entry = '<?xml version="1.0" encoding="UTF-8"?>\n' + '<entry xmlns="http://www.w3.org/2005/Atom">' + - '<title type="text">' + appname + '</title><id>' + appname + '</id><content type="application/xml">' + - savedcomposxml + '</content></entry>'; + '<title type="text">' + appname + '</title><id>' + appname + '</id><author><email>' + author + '</email></author>' + + '<content type="application/xml">' + savedcomposxml + '</content></entry>'; composites.put(appname, entry, function(e) { if (e) { showStatus('Local copy'); @@ -2015,6 +1926,9 @@ function save(savexml) { * Handle a composite change event. */ function oncomposchange(prop) { + if (!editable) + return false; + var newxml = car(writeXML(composite, false)); if (savedcomposxml == newxml) return false; @@ -2059,13 +1973,9 @@ function oncompselect(gsel) { return true; gcomp = gsel; - function updateButton(b, v) { - b.style.color = v? '#000000' : '#808080'; - } - - updateButton(cdelete, !isNil(gsel)); - updateButton(ccopy, !isNil(gsel)); - updateButton(cplay, !isNil(gsel)); + cdelete.disabled = isNil(gsel) || !editable; + ccopy.disabled = isNil(gsel) || !editable; + cplay.disabled = isNil(gsel); return true; } @@ -2078,7 +1988,7 @@ function showdata(gcomp) { if (isNil(gcomp)) return true; cvalue.value = complink(appname, gcomp.id); - cplay.innerHTML = '<'; + cplay.value = '<'; gvisible = false; pdiv.innerHTML = ''; pdiv.style.visibility = 'visible'; @@ -2115,7 +2025,7 @@ function showdata(gcomp) { }); setTimeout(function() { - gdiv.style.visibility = 'hidden' + graphdiv.style.visibility = 'hidden' }, 0); return true; } @@ -2126,10 +2036,10 @@ function showdata(gcomp) { function showgraph(gcomp) { if (gvisible) return true; - cplay.innerHTML = '>'; - gdiv.style.visibility = 'visible' + cplay.value = '>'; + graphdiv.style.visibility = 'visible' gvisible = true; - graph.compselect(gcomp, true, cvalue, ccopy, cdelete); + graph.compselect(gcomp, true, atitle, cvalue, ccopy, cdelete); setTimeout(function() { pdiv.style.visibility = 'hidden'; pdiv.innerHTML = ''; @@ -2149,29 +2059,28 @@ cplay.onclick = function() { } // Create editor graph area -g = graph.mkgraph(cdiv, graph.mkpath().move(-2500,0), cvalue, cadd, ccopy, cdelete); -gdiv = g.parentNode; -bg = graph.mkgroup(graph.mkpath()); +graph.mkedit(graphdiv, graph.mkpath().move(-2500,0), atitle, cvalue, cadd, ccopy, cdelete, oncomposchange, oncompselect); // Install the palettes +var bg = graph.mkgroup(graph.mkpath()); var pos = graph.mkpath().move(0, 0); -bpalette = installpalette('control', pos.rmove(5,2), g, bg, spalette, gpalettes); -installpalette('values', pos.rmove(0,28), g, bg, spalette, gpalettes); -installpalette('lists', pos.rmove(0, 28), g, bg, spalette, gpalettes); -installpalette('transform', pos.rmove(0, 28), g, bg, spalette, gpalettes); -installpalette('text', pos.rmove(0, 28), g, bg, spalette, gpalettes); -installpalette('http', pos.rmove(0, 28), g, bg, spalette, gpalettes); -installpalette('animation', pos.rmove(0, 28), g, bg, spalette, gpalettes); -installpalette('talk', pos.rmove(0, 28), g, bg, spalette, gpalettes); -installpalette('social', pos.rmove(0, 28), g, bg, spalette, gpalettes); -installpalette('search', pos.rmove(0, 28), g, bg, spalette, gpalettes); -installpalette('database', pos.rmove(0, 28), g, bg, spalette, gpalettes); -installpalette('logic', pos.rmove(0, 28), g, bg, spalette, gpalettes); -installpalette('math', pos.rmove(0, 28), g, bg, spalette, gpalettes); -installpalette('python', pos.rmove(0, 28), g, bg, spalette, gpalettes); +bpalette = installpalette('control', pos.rmove(5,2), graphdiv, bg, spalette, gpalettes); +installpalette('values', pos.rmove(0,28), graphdiv, bg, spalette, gpalettes); +installpalette('lists', pos.rmove(0, 28), graphdiv, bg, spalette, gpalettes); +installpalette('transform', pos.rmove(0, 28), graphdiv, bg, spalette, gpalettes); +installpalette('text', pos.rmove(0, 28), graphdiv, bg, spalette, gpalettes); +installpalette('http', pos.rmove(0, 28), graphdiv, bg, spalette, gpalettes); +installpalette('animation', pos.rmove(0, 28), graphdiv, bg, spalette, gpalettes); +installpalette('talk', pos.rmove(0, 28), graphdiv, bg, spalette, gpalettes); +installpalette('social', pos.rmove(0, 28), graphdiv, bg, spalette, gpalettes); +installpalette('search', pos.rmove(0, 28), graphdiv, bg, spalette, gpalettes); +installpalette('database', pos.rmove(0, 28), graphdiv, bg, spalette, gpalettes); +installpalette('logic', pos.rmove(0, 28), graphdiv, bg, spalette, gpalettes); +installpalette('math', pos.rmove(0, 28), graphdiv, bg, spalette, gpalettes); +installpalette('python', pos.rmove(0, 28), graphdiv, bg, spalette, gpalettes); // Get and display the current app -getapp(appname, g); +getapp(appname, graphdiv); </script> |