diff options
Diffstat (limited to 'sca-cpp/trunk/modules/edit/htdocs/graph')
-rw-r--r-- | sca-cpp/trunk/modules/edit/htdocs/graph/graph.html | 326 | ||||
-rw-r--r-- | sca-cpp/trunk/modules/edit/htdocs/graph/graph.js | 1358 | ||||
-rw-r--r-- | sca-cpp/trunk/modules/edit/htdocs/graph/index.html | 312 |
3 files changed, 757 insertions, 1239 deletions
diff --git a/sca-cpp/trunk/modules/edit/htdocs/graph/graph.html b/sca-cpp/trunk/modules/edit/htdocs/graph/graph.html deleted file mode 100644 index 1b927de48d..0000000000 --- a/sca-cpp/trunk/modules/edit/htdocs/graph/graph.html +++ /dev/null @@ -1,326 +0,0 @@ -<!-- - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. ---> -<html> -<head> -<link rel="stylesheet" type="text/css" href="/ui.css"> -<script type="text/javascript" src="/config.js"></script> -<script type="text/javascript" src="/util.js"></script> -<script type="text/javascript" src="/elemutil.js"></script> -<script type="text/javascript" src="/xmlutil.js"></script> -<script type="text/javascript" src="/atomutil.js"></script> -<script type="text/javascript" src="/scdl.js"></script> -<script type="text/javascript" src="/ui.js"></script> -<script type="text/javascript" src="/component.js"></script> -<script type="text/javascript" src="graph.js"></script> -</head> -<body class="delayed"> - -<div id="bodydiv" style="position: absolute; top: 0px; left: 0px; right: 0px;"> - -<table style="width: 100%;"> -<tr> -<th class="thl" style="width: 225px; min-width: 225px;">Palette</th> - -<th class="thr" style="padding-left: 4px; padding-top: 0px; padding-bottom: 0px;"> -<input id="compName" type="text" value="component name" title="Component name" style="position: relative; width: 200px;"/> -<input id="propValue" type="text" value="property value" title="Component property value" style="position: relative; width: 300px;"/> -<input type="button" id="autoplayButton" title="Turn preview on/off" style="font-weight: bold;" Value="Preview is on"/> -<span id="compValue" style="position: relative; font-weight: normal;"></span> -<span id="compDebug" style="position: relative; font-weight: normal;"></span> -</th> - -<th class="thl thr" style="padding-top: 0px; padding-bottom: 0px; padding-right: 0px; text-align: right;"> -<input type="button" id="saveButton" title="Save the app" style="font-weight: bold;" Value="Saved"/> -</th> -</tr> - -<tr style="height: 5000px;"><td class="tdl"></td><td class="tdr" colspan="2"> -</td></tr> -</table> - -<div style="position:absolute; top: 40px; left: 240px; right: 0px; height: 5000px;"> -<iframe id="dataFrame" class="databg" style="position: relative; height: 5000px; width: 100%; border: 0px;" scrolling="no" frameborder="0"></iframe> -</div> - -</div> - -<script type="text/javascript"> -if (ui.isIE()) $('bodydiv').style.right = -20; - -var editWidget = sca.component("EditWidget"); -var palettes = sca.reference(editWidget, "palettes"); -var apps = sca.reference(editWidget, "apps"); - -// Setup remote log -//rconsole = sca.defun(sca.reference(editWidget, "log"), "log"); - -/** - * The current app and component names. - */ -var appname = ui.queryParams()['app']; -var compname = ''; - -/** - * The current app composite and corresponding saved XML content. - */ -var savedcomposxml = ''; -var composite; - -/** - * 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. - */ -function getapp(name, g) { - if (isNil(name)) - return; - apps.get(name, function(doc) { - composite = atomcomposite(doc); - if (isNil(composite)) { - - // Create a default empty composite if necessary - var x = '<composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912" xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"' + - 'targetNamespace="http://' + name + '" ' + - 'name="' + name + '">' + - '</composite>'; - composite = readXML(mklist(x)); - } - graph.edit(name, composite, graph.composite(composite, graph.mkpath().move(palcx,0)), oncomposchange, oncompselect, g); - - // Track the saved composite XML - savedcomposxml = car(writeXML(composite, false)); - - // Show the page - ui.showbody(); - }); -} - -/** - * Get and display a palette of components. - */ -function getpalette(name, g, bg, palette, gpalettes) { - if (isNil(name)) - return; - palettes.get(name, function(doc) { - gpalettes[name] = graph.composite(atomcomposite(doc), graph.mkpath().move(80,0)); - graph.display(gpalettes[name], name == spalette? g : bg); - }); -} - -/** - * Install a palette, including a button to select the palette, and - * the palette content. - */ -function installpalette(name, pos, g, bg, palette, gpalettes) { - var b = graph.mkbutton(name, pos); - graph.display(mklist(b), g); - b.onclick = function() { - - // Display the selected palette - spalette = name; - for (var pn in gpalettes) - graph.display(gpalettes[pn], pn == spalette? g : bg); - } - getpalette(name, g, bg, palette, gpalettes); -} - -/** - * Handle save button click event. - */ -$('saveButton').onclick = function(e) { - return save(); -}; - -/** - * Save the current composite. - */ -function save() { - $('saveButton').value = 'Saving'; - savedcomposxml = car(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">' + - savedcomposxml + '</content></entry>'; - apps.put(appname, entry, function() { - if (savedcomposxml == car(writeXML(composite, false))) - $('saveButton').value = 'Saved'; - return true; - }); - return true; -} - -/** - * Handle a composite change event. - */ -function oncomposchange(prop) { - if (savedcomposxml == car(writeXML(composite, false))) - return false; - $('saveButton').value = 'Save now'; - - // Save property changes right away - if (prop) - return save(); - - // Autosave other changes after 3 seconds - $('saveButton').value = 'Save now'; - setTimeout(function() { - if (savedcomposxml == car(writeXML(composite, false))) - return false; - return save(); - }, 3000); - return true; -} - -/** - * Return the link to a component value. - */ -function compvaluelink(appname, cname) { - if (cname == '' || isNil(cname)) - return ''; - var protocol = window.location.protocol; - var host = window.location.hostname; - var port = ':' + window.location.port; - if (port == ':80' || port == ':443' || port == ':') - port = ''; - var link = protocol + '//' + appname + '.' + host + port + '/data/?component=' + cname; - return link; -} - -/** - * Return the link to a component raw data. - */ -function compdebuglink(appname, cname) { - if (cname == '' || isNil(cname)) - return ''; - var protocol = window.location.protocol; - var host = window.location.hostname; - var port = ':' + window.location.port; - if (port == ':80' || port == ':443' || port == ':') - port = ''; - var link = protocol + '//' + appname + '.' + host + port + '/components/' + cname; - return link; -} - -/** - * Track whether we're always showing the result data of the selected component. - */ -var autoplay = true; - -/** - * Show the result data of a component. - */ -function showData(cname) { - var rframe = $('dataFrame'); - if (cname == '') { - rframe.src = ''; - return true; - } - rframe.src = compvaluelink(appname, cname); - return true; -} - -/** - * Handle a component select event. - */ -function oncompselect(appname, cname) { - if (cname == compname) - return true; - compname = cname; - var link = compvaluelink(appname, cname); - $('compValue').innerHTML = link != ''? '<input type="button" id="playButton" title="View the component value" style="font-weight: bold;" value="View" onclick="playcomp()"/>' : ''; - $('compDebug').innerHTML = link != ''? '<input type="button" id="debugButton" title="View the component raw data" style="font-weight: bold;" value="URL" onclick="debugcomp()"/>' : ''; - - if (autoplay) - return showData(cname); - return true; -} - -/** - * Play the current component. - */ -function playcomp() { - var link = compvaluelink(appname, compname); - return window.open(link, '_' + appname + '_' + compname); -} - -/** - * Debug the current component. - */ -function debugcomp() { - var link = compdebuglink(appname, compname); - return window.open(link, '_' + appname + '_' + compname); -} - -/** - * Handle autoplay on/off click event. - */ -$('autoplayButton').onclick = function(e) { - if (autoplay) { - autoplay = false; - showData(''); - $('autoplayButton').value = 'Preview is off'; - return true; - } - autoplay = true; - showData(compname); - $('autoplayButton').value = 'Preview is on'; - return true; -}; - -// Init the play app button - - -// Create editor graph area -var g = graph.mkgraph(graph.mkpath().move(0,40), $('compName'), $('propValue')); -var bg = graph.mkgroup(graph.mkpath()); - -// Install the palettes -var gpalettes = new Array(); -var spalette = 'control'; -var pos = graph.mkpath(); -installpalette('control', pos.rmove(0,0), g, bg, spalette, gpalettes); -installpalette('values', pos.rmove(0,40), g, bg, spalette, gpalettes); -installpalette('lists', pos.rmove(0, 40), g, bg, spalette, gpalettes); -installpalette('transform', pos.rmove(0, 40), g, bg, spalette, gpalettes); -installpalette('text', pos.rmove(0, 40), g, bg, spalette, gpalettes); -installpalette('http', pos.rmove(0, 40), g, bg, spalette, gpalettes); -installpalette('talk', pos.rmove(0, 40), g, bg, spalette, gpalettes); -installpalette('social', pos.rmove(0, 40), g, bg, spalette, gpalettes); -installpalette('search', pos.rmove(0, 40), g, bg, spalette, gpalettes); -installpalette('database', pos.rmove(0, 40), g, bg, spalette, gpalettes); -installpalette('logic', pos.rmove(0, 40), g, bg, spalette, gpalettes); -installpalette('math', pos.rmove(0, 40), g, bg, spalette, gpalettes); -installpalette('python', pos.rmove(0, 40), g, bg, spalette, gpalettes); - -// Get and display the current app -getapp(appname, g); - -</script> -</body> -</html> diff --git a/sca-cpp/trunk/modules/edit/htdocs/graph/graph.js b/sca-cpp/trunk/modules/edit/htdocs/graph/graph.js index 38909756dc..2de6a40d6c 100644 --- a/sca-cpp/trunk/modules/edit/htdocs/graph/graph.js +++ b/sca-cpp/trunk/modules/edit/htdocs/graph/graph.js @@ -53,15 +53,15 @@ graph.colors.lightgray1 = '#dcdcdc' /** * Default positions and sizes. */ -var palcx = 250; -var trashcx = 230; +var palcx = 2500; +var trashcx = 2480; var proxcx = 20; var proxcy = 20; var buttoncx = 65; var buttoncy = 30; var curvsz = 6; var tabsz = 2; -var fontsz = ''; +var fontsz = '11px'; /** * Base path class. @@ -103,986 +103,520 @@ graph.BasePath = function() { }; /** - * Rendering functions that work both with VML and SVG. + * SVG rendering functions. */ +graph.svgns='http://www.w3.org/2000/svg'; + /** - * VML rendering. + * Make an SVG graph. */ -if (ui.isIE()) { - - graph.vmlns='urn:schemas-microsoft-com:vml'; - document.write('<xml:namespace ns="urn:schemas-microsoft-com:vml" prefix="v" />'); +graph.mkgraph = function(pos, cvalue, cadd, 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()); + div.style.top = ui.pixpos(pos.ypos()); + div.style.overflow = 'hidden'; + document.body.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); + + // Track element dragging and selection + graph.dragging = null; + graph.selected = null; + cvalue.disabled = true; + cdelete.disabled = true; /** - * Make a VML graph. + * Find the first draggable element in a hierarchy of elements. */ - graph.mkgraph = function(pos, cname, pvalue) { - - // 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); - - // Track element dragging and selection - graph.dragging = null; - graph.selected = null; - cname.disabled = true; - pvalue.disabled = true; - - /** - * Find the first draggable element in a hierarchy of elements. - */ - function draggable(n) { - if (n == vmlg) - return null; - if (n.nodeName == 'group' && n.id != '') - return n; - return draggable(n.parentNode); - } - - /** - * Handle a mousedown event. - */ - vmlg.onmousedown = function() { - window.event.returnValue = false; - - // Find draggable element - graph.dragging = draggable(window.event.srcElement); - graph.selected = graph.dragging; - if (graph.dragging == null) { - - // Reset current selection - cname.value = ''; - cname.disabled = true; - pvalue.value = ''; - pvalue.disabled = true; - - // Trigger component select event - vmlg.oncompselect(''); - return false; - } - - // Clone component from the palette - var compos = scdl.composite(vmlg.compos); - if (graph.dragging.id.substring(0, 8) == 'palette:') { - graph.dragging = graph.clonepalette(graph.dragging, compos); - graph.selected = graph.dragging; - } - - // Cut wire to component - if (graph.dragging.parentNode != vmlg) - setElement(compos, graph.cutwire(graph.dragging, compos, vmlg)); + function draggable(n) { + if (n == div || n == svg || n == null) + return null; + if (n.nodeName == 'g' && !isNil(n.id) && n.id != '') + return n; + return draggable(n.parentNode); + } - // Bring component to the top - graph.bringtotop(graph.dragging, vmlg); + /** + * Handle a mouse down event. + */ + div.onmousedown = function(e) { - // Remember mouse position - graph.dragX = window.event.clientX; - graph.dragY = window.event.clientY; - vmlg.setCapture(); + // Find draggable component + graph.dragging = draggable(e.target); + graph.selected = graph.dragging; + if (graph.dragging == null) { - // Update the component name and property value fields - cname.value = graph.selected.id; - cname.disabled = false; - pvalue.value = graph.property(graph.selected.comp); - pvalue.disabled = !graph.hasproperty(graph.selected.comp); + // Reset current selection + cvalue.value = ''; + cvalue.disabled = true; + cdelete.disabled = true; // Trigger component select event - vmlg.oncompselect(vmlg.appname, graph.selected.id); - 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:') { - var gpos = graph.relpos(graph.dragging); - if (gpos.xpos() >= trashcx) { - - // If component close enough to editing area, move it there - if (gpos.xpos() < palcx) - graph.move(graph.dragging, graph.mkpath().move(palcx, gpos.ypos())); - - // Add new dragged component to the composite - if (isNil(graph.dragging.compos)) { - var compos = scdl.composite(vmlg.compos); - setElement(compos, graph.addcomp(graph.dragging.comp, compos)); - graph.dragging.compos = vmlg.compos; - } - - // Update component position - setElement(graph.dragging.comp, graph.movecomp(graph.dragging.comp, graph.abspos(graph.dragging, vmlg))); - - // Wire component to neighboring reference - if (!isNil(graph.dragging.svcpos)) { - var compos = scdl.composite(vmlg.compos); - setElement(compos, grah.clonerefs(graph.wire(graph.dragging, compos, vmlg))); - } - - } else { - - // Discard component dragged out of composite - vmlg.removeChild(graph.dragging); - if (!isNil(graph.dragging.compos)) { - var compos = scdl.composite(vmlg.compos); - setElement(compos, graph.clonerefs(graph.gcollect(graph.removecomp(graph.dragging.comp, compos)))); - } - - // Reset current selection - graph.selected = null; - cname.value = ''; - cname.disabled = true; - pvalue.value = ''; - pvalue.disabled = true; - - // Trigger component select event - vmlg.oncompselect(''); - } - - // Trigger composite change event - vmlg.oncomposchange(false); - } - - // Forget current dragged component - graph.dragging = null; - vmlg.releaseCapture(); - - // Refresh the composite - graph.refresh(vmlg); - return false; - }; + svg.oncompselect(''); + return true; + } - /** - * Handle a mousemove event. - */ - vmlg.onmousemove = function() { - if (graph.dragging == null) - return false; + // Clone component from the palette + var compos = scdl.composite(svg.compos); + if (graph.dragging.id.substring(0, 8) == 'palette:') { + graph.dragging = graph.clonepalette(graph.dragging, compos); + graph.selected = graph.dragging; - // Calculate new position of dragged element + // Move into the editing area and hide the palette var gpos = graph.relpos(graph.dragging); - var newX = gpos.xpos() + (window.event.clientX - graph.dragX); - var newY = gpos.ypos() + (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; - - // Move the dragged element - graph.move(graph.dragging, graph.mkpath().move(newX, newY)); + graph.move(graph.dragging, graph.mkpath().move(gpos.xpos() + palcx, gpos.ypos())); + div.style.left = ui.pixpos(palcx * -1); + } - return false; - }; + // Cut wire to component + if (graph.dragging.parentNode != svg) + setElement(compos, graph.sortcompos(graph.cutwire(graph.dragging, compos, svg))); - /** - * Handle field on change events. - */ - cname.onchange = function() { - if (graph.selected == null) - return false; + // Bring component to the top + graph.bringtotop(graph.dragging, svg); - // Change component name and refactor references to it - var compos = scdl.composite(vmlg.compos); - cname.value = graph.ucid(cname.value, compos); - cname.disabled = false; - graph.selected.id = cname.value; - setElement(compos, graph.renamecomp(graph.selected.comp, compos, cname.value)); + // Remember current mouse position + var pos = typeof e.touches != "undefined" ? e.touches[0] : e; + graph.dragX = pos.screenX; + graph.dragY = pos.screenY; - // Trigger component select event - vmlg.oncompselect(vmlg.appname, graph.selected.id); + // Update the component name and property value fields + cvalue.value = graph.hasproperty(graph.selected.comp)? graph.property(graph.selected.comp) : graph.selected.id; + cvalue.disabled = false; + cdelete.disabled = false; + + // Trigger component select event + svg.oncompselect(graph.selected.id); + + if (e.preventDefault) + e.preventDefault(); + else + e.returnValue = false; + return true; + }; - // Refresh the composite - graph.refresh(vmlg); + // Support touch devices + div.ontouchstart = div.onmousedown; - // Trigger composite change event - vmlg.oncomposchange(true); - return false; - }; + /** + * Handle a mouse up event. + */ + div.onmouseup = function(e) { + if (graph.dragging == null) + return true; - pvalue.onchange = function() { - if (graph.selected == null) - return false; + if (graph.dragging.parentNode == svg && graph.dragging.id.substring(0, 8) != 'palette:') { + var gpos = graph.relpos(graph.dragging); + if (gpos.xpos() >= trashcx) { - // Change the component property value - graph.setproperty(graph.selected.comp, pvalue.value); - pvalue.value = graph.property(graph.selected.comp); - pvalue.disabled = !graph.hasproperty(graph.selected.comp); + // If component close enough to editing area, move it there + if (gpos.xpos() < palcx) + graph.move(graph.dragging, graph.mkpath().move(palcx, gpos.ypos())); - // Refresh the composite - graph.refresh(vmlg); + // Add new dragged component to the composite + if (isNil(graph.dragging.compos)) { + var compos = scdl.composite(svg.compos); + setElement(compos, graph.sortcompos(graph.addcomp(graph.dragging.comp, compos))); + graph.dragging.compos = svg.compos; + } - // Trigger composite change event - vmlg.oncomposchange(true); - return false; - }; + // Update component position + setElement(graph.dragging.comp, graph.movecomp(graph.dragging.comp, graph.abspos(graph.dragging, svg))); - // Create hidden spans to help compute the width of - // component, reference and property titles - graph.comptitlewidthdiv = document.createElement('span'); - graph.comptitlewidthdiv.style.visibility = 'hidden' - if (fontsz != '') - graph.comptitlewidthdiv.style.fontSize = fontsz; - div.appendChild(graph.comptitlewidthdiv); - - graph.reftitlewidthdiv = document.createElement('span'); - graph.reftitlewidthdiv.style.visibility = 'hidden' - if (fontsz != '') - graph.comptitlewidthdiv.style.fontSize = fontsz; - div.appendChild(graph.reftitlewidthdiv); - - graph.proptitlewidthdiv = document.createElement('span'); - graph.proptitlewidthdiv.style.visibility = 'hidden' - if (fontsz != '') - graph.comptitlewidthdiv.style.fontSize = fontsz; - div.appendChild(graph.proptitlewidthdiv); - - return vmlg; - }; + // 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)))); + } - /** - * Make a shape path. - */ - graph.mkpath = function() { - function Path() { - this.BasePath = graph.BasePath; - this.BasePath(); - - this.clone = function() { - return graph.mkpath().pos(this.xpos(), this.ypos()); - }; - - this.move = function(x, y) { - this.path += 'M ' + x + ',' + y + ' '; - return this.pos(x, y); - }; - - this.line = function(x, y) { - this.path += 'L ' + x + ',' + y + ' '; - return this.pos(x, y); - }; - - this.curve = function(x1, y1, x, y) { - this.path += 'QB ' + x1 + ',' + y1 + ',' + x + ',' + y + ' '; - return this.pos(x, y); - }; - - this.end = function() { - this.path += 'X E'; - return this; - }; - } + } else { - return new Path(); - }; + // Discard component dragged out of composite + svg.removeChild(graph.dragging); + if (!isNil(graph.dragging.compos)) { + var compos = scdl.composite(svg.compos); + setElement(compos, graph.sortcompos(graph.clonerefs(graph.gcollect(graph.removecomp(graph.dragging.comp, compos))))); + } - /** - * Return an element representing a title. - */ - graph.mktitle = function(t, style, pos) { - var title = document.createElement('v:textbox'); - title.style.position = 'absolute'; - title.style.left = pos.xpos() + 2; - title.style.top = pos.ypos(); - title.inset = '' + 6 + 'px ' + pos.ypos() + 'px 0px 0px'; - if (style != '') - title.style.cssText = style; - if (fontsz != '') - title.style.fontSize = fontsz; - var tnode = document.createTextNode(t); - title.appendChild(tnode); - return title; - }; + // Reset current selection + graph.selected = null; + cvalue.value = ''; + cvalue.disabled = true; + cdelete.disabled = true; - /** - * Return an element representing the title of a component. - */ - graph.comptitle = function(comp) { - var tsvcs = graph.tsvcs(comp); - var lsvcs = graph.lsvcs(comp); - var pos = graph.mkpath().move(isNil(lsvcs)? tabsz : (tabsz * 5), isNil(tsvcs)? tabsz : (tabsz * 5)); - return graph.mktitle(graph.title(comp), graph.compstyle(comp), pos); - }; + // Trigger component select event + svg.oncompselect(''); + } + } - /** - * Return the width of the title of a component. - */ - graph.comptitlewidth = function(comp) { - var t = graph.title(comp); - graph.comptitlewidthdiv.innerHTML = t; - var twidth = graph.comptitlewidthdiv.offsetWidth + 2; - graph.comptitlewidthdiv.innerHTML = ''; - return twidth; - }; + // Forget current dragged component + graph.dragging = null; - /** - * Return an element representing the value of a property. - */ - graph.proptitle = function(comp) { - var tsvcs = graph.tsvcs(comp); - var lsvcs = graph.lsvcs(comp); - var pos = graph.mkpath().move(graph.comptitlewidth(comp) + 7 + (isNil(lsvcs)? tabsz : (tabsz * 5)), isNil(tsvcs)? tabsz : (tabsz * 5)); - return graph.mktitle(graph.propertytitle(comp), graph.propstyle(comp), pos); - }; + // Refresh the composite + graph.refresh(svg); - /** - * Return the width of the value of a property. - */ - graph.proptitlewidth = function(comp) { - var t = graph.proptitle(comp); - graph.proptitlewidthdiv.innerHTML = t; - var twidth = graph.proptitlewidthdiv.offsetWidth + 4; - graph.proptitlewidthdiv.innerHTML = ''; - return twidth; + // Trigger composite change event + svg.oncomposchange(false); + return true; }; - /** - * Return an element representing the title of a reference. - */ - graph.reftitle = function(ref) { - return graph.mktitle(graph.title(ref), graph.refstyle(ref), graph.mkpath().move(25,25)); - }; + // Support touch devices + div.ontouchend = div.onmouseup; - /** - * Return the width of the title of a reference. - */ - graph.reftitlewidth = function(ref) { - var t = graph.title(ref); - graph.reftitlewidthdiv.innerHTML = t; - var twidth = graph.reftitlewidthdiv.offsetWidth; - graph.reftitlewidthdiv.innerHTML = ''; - return twidth; - }; + // Handle a mouse click event. + div.onclick = function(e) { + if (graph.dragging == null && (e.target == div || e.target == svg)) { - /** - * Return a node representing a component. - */ - graph.compnode = function(comp, cassoc, pos) { - - // Make the component and property title elements - var title = graph.comptitle(comp); - var prop = graph.proptitle(comp); - - // Compute the component shape path - var path = graph.comppath(comp, cassoc); - var d = path.str(); - - // Create the main component 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.color(comp); - shape.stroked = 'false'; - - // Create an overlay contour shape - var contour = document.createElement('v:shape'); - contour.style.width = 5000; - contour.style.height = 5000; - contour.coordsize = '5000,5000'; - contour.path = d; - contour.filled = 'false'; - contour.strokecolor = graph.colors.gray; - contour.strokeweight = '1'; - contour.style.left = 1; - contour.style.top = 1; - var stroke = document.createElement('v:stroke'); - 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; - g.style.height = 5000; - g.coordsize = '5000,5000'; - g.style.left = pos.xpos(); - g.style.top = pos.ypos(); - g.appendChild(shape); - shape.appendChild(title); - shape.appendChild(prop); - g.appendChild(contour) - - // Store the component and the positions of its services - // and references in the component shape - g.comp = comp; - g.refpos = reverse(path.refpos); - g.svcpos = reverse(path.svcpos); - - return g; - }; + // Dismiss the palette + if (ui.numpos(div.style.left) != (palcx * -1)) + div.style.left = ui.pixpos(palcx * -1); + } + return true; + } /** - * Return a graphical group. + * Handle a mouse move event. */ - graph.mkgroup = function(pos) { - var g = document.createElement('v:group'); - g.style.left = pos.xpos(); - g.style.top = pos.ypos(); - return g; - }; + window.onmousemove = function(e) { + if (graph.dragging == null) + return true; - /** - * Return a node representing a button. - */ - graph.mkbutton = function(t, pos) { - - // Make the title element - var title = graph.mktitle(t, '', graph.mkpath().move(4,4)); - - // Compute the path of the button shape - var path = 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 = path; - shape.fillcolor = graph.colors.lightgray; - shape.stroked = 'false'; - - // Create an overlay contour shape - var contour = document.createElement('v:shape'); - contour.style.width = 5000; - contour.style.height = 5000; - contour.coordsize = '5000,5000'; - contour.path = path; - contour.filled = 'false'; - contour.strokecolor = graph.colors.gray; - contour.strokeweight = '1'; - contour.style.left = 1; - contour.style.top = 1; - var stroke = document.createElement('v:stroke'); - 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; - g.coordsize = '5000,5000'; - g.style.left = pos.xpos(); - g.style.top = pos.ypos(); - g.appendChild(shape); - shape.appendChild(title); - g.appendChild(contour) - return g; - }; + // Calculate new position of dragged element + var gpos = graph.relpos(graph.dragging); + var pos = typeof e.touches != "undefined" ? e.touches[0] : e; + var newX = gpos.xpos() + (pos.screenX - graph.dragX); + var newY = gpos.ypos() + (pos.screenY - graph.dragY); + if (newX >= 0) + graph.dragX = pos.screenX; + else + newX = 0; + if (newY >= 0) + graph.dragY = pos.screenY; + else + newY = 0; - /** - * Return the relative position of a node. - */ - graph.relpos = function(e) { - var curX = ui.csspos(e.style.left); - var curY = ui.csspos(e.style.top); - return graph.mkpath().move(curX, curY); - }; + // Move the dragged element + graph.move(graph.dragging, graph.mkpath().move(newX, newY)); - /** - * Move a node. - */ - graph.move = function(e, pos) { - e.style.left = pos.xpos(); - e.style.top = pos.ypos(); + return true; }; -} else { - - /** - * SVG rendering. - */ - graph.svgns='http://www.w3.org/2000/svg'; + // Support touch devices + div.ontouchmove = window.onmousemove; /** - * Make an SVG graph. + * Handle field on change events. */ - graph.mkgraph = function(pos, cname, pvalue) { - - // Create a div element to host the graph - var div = document.createElement('div'); - div.id = 'svgdiv'; - div.style.position = 'absolute'; - div.style.left = pos.xpos(); - div.style.top = pos.ypos(); - // -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); - - // Track element dragging and selection - graph.dragging = null; - graph.selected = null; - cname.disabled = true; - pvalue.disabled = true; - - /** - * Find the first draggable element in a hierarchy of elements. - */ - function draggable(n) { - if (n == svg) - return null; - if (n.nodeName == 'g' && n.id != '') - return n; - return draggable(n.parentNode); - } - - /** - * Handle a mouse down event. - */ - svg.onmousedown = function(e) { - if (e.preventDefault) - e.preventDefault(); - else - e.returnValue = false; - - // Find draggable component - graph.dragging = draggable(e.target); - graph.selected = graph.dragging; - if (graph.dragging == null) { - - // Reset current selection - cname.value = ''; - cname.disabled = true; - pvalue.value = ''; - pvalue.disabled = true; - - // Trigger component select event - svg.oncompselect(''); - return false; - } + cvalue.onchange = function() { + if (graph.selected == null) + return false; - // Clone component from the palette + // Change component name and refactor references to it + function changename() { var compos = scdl.composite(svg.compos); - if (graph.dragging.id.substring(0, 8) == 'palette:') { - graph.dragging = graph.clonepalette(graph.dragging, compos); - graph.selected = graph.dragging; - } + cvalue.value = graph.ucid(cvalue.value, compos); + graph.selected.id = cvalue.value; + setElement(compos, graph.sortcompos(graph.renamecomp(graph.selected.comp, compos, cvalue.value))); - // Cut wire to component - if (graph.dragging.parentNode != svg) - setElement(compos, graph.cutwire(graph.dragging, compos, svg)); - - // Bring component to the top - graph.bringtotop(graph.dragging, svg); - - // Remember current mouse position - var pos = typeof e.touches != "undefined" ? e.touches[0] : e; - graph.dragX = pos.screenX; - graph.dragY = pos.screenY; - - // Update the component name and property value fields - cname.value = graph.selected.id; - cname.disabled = false; - pvalue.value = graph.property(graph.selected.comp); - pvalue.disabled = !graph.hasproperty(graph.selected.comp); - // Trigger component select event - svg.oncompselect(svg.appname, graph.selected.id); - 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 gpos = graph.relpos(graph.dragging); - if (gpos.xpos() >= trashcx) { - - // If component close enough to editing area, move it there - if (gpos.xpos() < palcx) - graph.move(graph.dragging, graph.mkpath().move(palcx, gpos.ypos())); - - // Add new dragged component to the composite - if (isNil(graph.dragging.compos)) { - var compos = scdl.composite(svg.compos); - setElement(compos, graph.addcomp(graph.dragging.comp, compos)); - graph.dragging.compos = svg.compos; - } - - // Update component position - setElement(graph.dragging.comp, graph.movecomp(graph.dragging.comp, graph.abspos(graph.dragging, svg))); - - // Wire component to neighboring reference - if (!isNil(graph.dragging.svcpos)) { - var compos = scdl.composite(svg.compos); - setElement(compos, graph.clonerefs(graph.wire(graph.dragging, compos, svg))); - } - - } else { - - // Discard component dragged out of composite - svg.removeChild(graph.dragging); - if (!isNil(graph.dragging.compos)) { - var compos = scdl.composite(svg.compos); - setElement(compos, graph.clonerefs(graph.gcollect(graph.removecomp(graph.dragging.comp, compos)))); - } - - // Reset current selection - graph.selected = null; - cname.value = ''; - cname.disabled = true; - pvalue.value = ''; - pvalue.disabled = true; - - // Trigger component select event - svg.oncompselect(''); - } - } - - // Forget current dragged component - graph.dragging = null; + svg.oncompselect(graph.selected.id); // Refresh the composite graph.refresh(svg); // Trigger composite change event - svg.oncomposchange(false); + svg.oncomposchange(true); return false; - }; + } - // Support touch devices - window.top.onmouseup = window.onmouseup; - window.ontouchend = window.onmouseup; - window.gestureend = window.onmouseup; - window.top.gestureend = window.onmouseup; - window.top.ontouchend = window.onmouseup; - window.ontouchcancel = window.onmouseup; - window.top.ontouchcancel = window.onmouseup; + // Change the component property value + function changeprop() { + graph.setproperty(graph.selected.comp, cvalue.value); + cvalue.value = graph.property(graph.selected.comp); + cvalue.disabled = !graph.hasproperty(graph.selected.comp); - /** - * Handle a mouse move event. - */ - window.onmousemove = function(e) { - if (graph.dragging == null) - return false; - if (e.preventDefault) - e.preventDefault(); - else - e.returnValue = false; - - // Calculate new position of dragged element - var gpos = graph.relpos(graph.dragging); - var pos = typeof e.touches != "undefined" ? e.touches[0] : e; - var newX = gpos.xpos() + (pos.screenX - graph.dragX); - var newY = gpos.ypos() + (pos.screenY - graph.dragY); - if (newX >= 0) - graph.dragX = pos.screenX; - else - newX = 0; - if (newY >= 0) - graph.dragY = pos.screenY; - else - newY = 0; - - // Move the dragged element - graph.move(graph.dragging, graph.mkpath().move(newX, newY)); + // Refresh the composite + graph.refresh(svg); + // Trigger composite change event + svg.oncomposchange(true); return false; - }; - - // Support touch devices - window.top.onmousemove = window.onmousemove; - window.ontouchmove = window.onmousemove; - window.top.ontouchmove = window.onmousemove; + } - /** - * Handle field on change events. - */ - cname.onchange = function() { - if (graph.selected == null) - return false; + return graph.hasproperty(graph.selected.comp)? changeprop() : changename(); + }; + + // Handle delete event + cdelete.onclick = function() { + if (graph.selected == null) + return false; + if (graph.selected.id.substring(0, 8) != 'palette:' && !isNil(graph.selected.compos)) { - // Change component name and refactor references to it + // Remove selected component var compos = scdl.composite(svg.compos); - cname.value = graph.ucid(cname.value, compos); - graph.selected.id = cname.value; - setElement(compos, graph.renamecomp(graph.selected.comp, compos, cname.value)); + setElement(compos, graph.sortcompos(graph.clonerefs(graph.gcollect(graph.removecomp(graph.selected.comp, compos))))); - // Trigger component select event - svg.oncompselect(svg.appname, graph.selected.id); + // Reset current selection + graph.selected = null; + cvalue.value = ''; + cvalue.disabled = true; + cdelete.disabled = true; // Refresh the composite graph.refresh(svg); + // Trigger component select event + svg.oncompselect(''); + // Trigger composite change event svg.oncomposchange(true); - return false; - }; - - pvalue.onchange = function() { - if (graph.selected == null) - return false; + } + return false; + }; - // Change the component property value - graph.setproperty(graph.selected.comp, pvalue.value); - pvalue.value = graph.property(graph.selected.comp); - pvalue.disabled = !graph.hasproperty(graph.selected.comp); + // Handle add event + cadd.onclick = function() { - // Refresh the composite - graph.refresh(svg); + // Show the palette + div.style.left = ui.pixpos(0); + return false; + }; - // Trigger composite change event - svg.oncomposchange(true); - return false; + // 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 = ui.pixpos(0); + graph.titlewidthsvg.style.width = ui.pixpos(0); + div.appendChild(graph.titlewidthsvg); + + return svg; +}; + +/** + * Make a path. + */ +graph.mkpath = function() { + function Path() { + this.BasePath = graph.BasePath; + this.BasePath(); + + this.clone = function() { + return graph.mkpath().pos(this.xpos(), this.ypos()); }; - // 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; - graph.titlewidthsvg.style.width = 0; - div.appendChild(graph.titlewidthsvg); + this.move = function(x, y) { + this.path += 'M' + x + ',' + y + ' '; + return this.pos(x, y); + }; - return svg; - }; + this.line = function(x, y) { + this.path += 'L' + x + ',' + y + ' '; + return this.pos(x, y); + }; - /** - * Make a path. - */ - graph.mkpath = function() { - function Path() { - this.BasePath = graph.BasePath; - this.BasePath(); - - this.clone = function() { - return graph.mkpath().pos(this.xpos(), this.ypos()); - }; - - this.move = function(x, y) { - this.path += 'M' + x + ',' + y + ' '; - return this.pos(x, y); - }; - - this.line = function(x, y) { - this.path += 'L' + x + ',' + y + ' '; - return this.pos(x, y); - }; - - this.curve = function(x1, y1, x, y) { - this.path += 'Q' + x1 + ',' + y1 + ' ' + x + ',' + y + ' '; - return this.pos(x, y); - }; - - this.end = function() { - this.path += 'Z'; - return this; - }; - } + this.curve = function(x1, y1, x, y) { + this.path += 'Q' + x1 + ',' + y1 + ' ' + x + ',' + y + ' '; + return this.pos(x, y); + }; - return new Path(); - }; + this.end = function() { + this.path += 'Z'; + return this; + }; + } - /** - * Return an element representing a title. - */ - graph.mktitle = function(t, style) { - var title = document.createElementNS(graph.svgns, 'text'); - title.setAttribute('x', 5); - title.setAttribute('y', 15); - title.setAttribute('text-anchor', 'start'); - if (style != '') - title.style.cssText = style; - if (fontsz != '') - title.style.fontSize = fontsz; - title.appendChild(document.createTextNode(t)); - return title; - }; + return new Path(); +}; - /** - * Return an element representing the title of a component. - */ - graph.comptitle = function(comp) { - return graph.mktitle(graph.title(comp), graph.compstyle(comp)); - }; +/** + * Return an element representing a title. + */ +graph.mktitle = function(t, style) { + var title = document.createElementNS(graph.svgns, 'text'); + title.setAttribute('x', 5); + title.setAttribute('y', 15); + title.setAttribute('text-anchor', 'start'); + if (style != '') + title.style.cssText = style; + if (fontsz != '') + title.style.fontSize = fontsz; + title.style.cursor = 'default'; + title.appendChild(document.createTextNode(t)); + return title; +}; - /** - * Return the width of the title of a component. - */ - graph.comptitlewidth = function(comp) { - var title = graph.comptitle(comp); - graph.titlewidthsvg.appendChild(title); - var width = title.getBBox().width + 2; - graph.titlewidthsvg.removeChild(title); - return width; - }; +/** + * Return an element representing the title of a component. + */ +graph.comptitle = function(comp) { + return graph.mktitle(graph.title(comp), graph.compstyle(comp)); +}; - /** - * Return an element representing the title of a reference. - */ - graph.reftitle = function(ref) { - return graph.mktitle(graph.title(ref), graph.refstyle(ref)); - }; +/** + * Return the width of the title of a component. + */ +graph.comptitlewidth = function(comp) { + var title = graph.comptitle(comp); + graph.titlewidthsvg.appendChild(title); + var width = title.getBBox().width + 2; + graph.titlewidthsvg.removeChild(title); + return width; +}; - /** - * Return the width of the title of a reference. - */ - graph.reftitlewidth = function(ref) { - var title = graph.reftitle(ref); - graph.titlewidthsvg.appendChild(title); - var width = title.getBBox().width; - graph.titlewidthsvg.removeChild(title); - return width; - }; +/** + * Return an element representing the title of a reference. + */ +graph.reftitle = function(ref) { + return graph.mktitle(graph.title(ref), graph.refstyle(ref)); +}; - /** - * Return an element representing the value of a property. - */ - graph.proptitle = function(comp) { - var title = graph.mktitle(graph.propertytitle(comp), graph.propstyle(comp)); - title.setAttribute('x', graph.comptitlewidth(comp) + 7); - return title; - }; +/** + * Return the width of the title of a reference. + */ +graph.reftitlewidth = function(ref) { + var title = graph.reftitle(ref); + graph.titlewidthsvg.appendChild(title); + var width = title.getBBox().width; + graph.titlewidthsvg.removeChild(title); + return width; +}; - /** - * Return the width of the title of a property. - */ - graph.proptitlewidth = function(comp) { - var title = graph.proptitle(comp); - graph.titlewidthsvg.appendChild(title); - var width = title.getBBox().width + 4; - graph.titlewidthsvg.removeChild(title); - return width; - }; +/** + * Return an element representing the value of a property. + */ +graph.proptitle = function(comp) { + var title = graph.mktitle(graph.propertytitle(comp), graph.propstyle(comp)); + title.setAttribute('x', graph.comptitlewidth(comp) + 7); + return title; +}; - /** - * Return a node representing a component. - */ - graph.compnode = function(comp, cassoc, pos) { - - // Make the component and property title elements - var title = graph.comptitle(comp); - var prop = graph.proptitle(comp); - - // Compute the path of the component shape - var path = graph.comppath(comp, cassoc); - var d = path.str(); - - // Create the main component shape - var shape = document.createElementNS(graph.svgns, 'path'); - shape.setAttribute('d', d); - shape.setAttribute('fill', graph.color(comp)); - shape.setAttribute('fill-opacity', '0.60'); - - // Create an overlay contour shape - var contour = document.createElementNS(graph.svgns, 'path'); - contour.setAttribute('d', d); - contour.setAttribute('fill', 'none'); - contour.setAttribute('stroke', graph.colors.gray); - contour.setAttribute('stroke-width', '3'); - 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() + ')'); - g.appendChild(shape); - g.appendChild(contour); - g.appendChild(title); - g.appendChild(prop); - - // Store the component and the positions of its services - // and references in the component shape - g.comp = comp; - g.refpos = reverse(path.refpos); - g.svcpos = reverse(path.svcpos); - - return g; - }; +/** + * Return the width of the title of a property. + */ +graph.proptitlewidth = function(comp) { + var title = graph.proptitle(comp); + graph.titlewidthsvg.appendChild(title); + var width = title.getBBox().width + 4; + graph.titlewidthsvg.removeChild(title); + return width; +}; - /** - * Return a graphical group. - */ - graph.mkgroup = function(pos) { - var g = document.createElementNS(graph.svgns, 'g'); - g.setAttribute('transform', 'translate(' + pos.xpos() + ',' + pos.ypos() + ')'); - return g; - }; +/** + * Return a node representing a component. + */ +graph.compnode = function(comp, cassoc, pos) { + + // Make the component and property title elements + var title = graph.comptitle(comp); + var prop = graph.proptitle(comp); + + // Compute the path of the component shape + var path = graph.comppath(comp, cassoc); + var d = path.str(); + + // Create the main component shape + var shape = document.createElementNS(graph.svgns, 'path'); + shape.setAttribute('d', d); + shape.setAttribute('fill', graph.color(comp)); + shape.setAttribute('fill-opacity', '0.60'); + + // Create an overlay contour shape + var contour = document.createElementNS(graph.svgns, 'path'); + contour.setAttribute('d', d); + contour.setAttribute('fill', 'none'); + contour.setAttribute('stroke', graph.colors.gray); + contour.setAttribute('stroke-width', '3'); + 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() + ')'); + g.appendChild(shape); + g.appendChild(contour); + g.appendChild(title); + g.appendChild(prop); + + // Store the component and the positions of its services + // and references in the component shape + g.comp = comp; + g.refpos = reverse(path.refpos); + g.svcpos = reverse(path.svcpos); - /** - * Return a node representing a button. - */ - graph.mkbutton = function(t, pos) { - - // Make the button title - var title = graph.mktitle(t, ''); - - // 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.lightgray); - shape.setAttribute('fill-opacity', '0.60'); - - // Create an overlay contour shape - var contour = document.createElementNS(graph.svgns, 'path'); - contour.setAttribute('d', path); - contour.setAttribute('fill', 'none'); - contour.setAttribute('stroke', graph.colors.gray); - contour.setAttribute('stroke-width', '3'); - 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); - g.appendChild(contour); - g.appendChild(title); - return g; - }; + return g; +}; - /** - * Return the relative position of a node. - */ - graph.relpos = function(e) { - var pmatrix = e.parentNode.getCTM(); - 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); - return graph.mkpath().move(curX, curY); - }; +/** + * Return a graphical group. + */ +graph.mkgroup = function(pos) { + var g = document.createElementNS(graph.svgns, 'g'); + g.setAttribute('transform', 'translate(' + pos.xpos() + ',' + pos.ypos() + ')'); + return g; +}; - /** - * Move a node. - */ - graph.move = function(e, pos) { - e.setAttribute('transform', 'translate(' + pos.xpos() + ',' + pos.ypos() + ')'); - }; +/** + * Return a node representing a button. + */ +graph.mkbutton = function(t, pos) { + + // Make the button title + var title = graph.mktitle(t, ''); + + // 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.lightgray); + shape.setAttribute('fill-opacity', '0.60'); + + // Create an overlay contour shape + var contour = document.createElementNS(graph.svgns, 'path'); + contour.setAttribute('d', path); + contour.setAttribute('fill', 'none'); + contour.setAttribute('stroke', graph.colors.gray); + contour.setAttribute('stroke-width', '3'); + 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); + g.appendChild(contour); + g.appendChild(title); + return g; +}; + +/** + * Return the relative position of a node. + */ +graph.relpos = function(e) { + var pmatrix = e.parentNode.getCTM(); + 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); + return graph.mkpath().move(curX, curY); +}; + +/** + * Move a node. + */ +graph.move = function(e, pos) { + e.setAttribute('transform', 'translate(' + pos.xpos() + ',' + pos.ypos() + ')'); }; /** @@ -1725,11 +1259,46 @@ graph.clonepalette = function(e, compos) { * Move a SCDL component to the given position. */ graph.movecomp = function(comp, pos) { + if (isNil(pos)) + return append(mklist(element, "'component"), + filter(function(e) { return !(isAttribute(e) && (attributeName(e) == "'t:x" || attributeName(e) == "'t:y")); }, elementChildren(comp))); return append(mklist(element, "'component", mklist(attribute, "'t:x", '' + (pos.xpos() - palcx)), mklist(attribute, "'t:y", '' + pos.ypos())), filter(function(e) { return !(isAttribute(e) && (attributeName(e) == "'t:x" || attributeName(e) == "'t:y")); }, elementChildren(comp))); }; /** + * Sort elements of a composite. + */ +graph.sortcompos = function(compos) { + return append(mklist(element, "'composite"), elementChildren(compos).sort(function(a, b) { + + // Sort attributes, place them at the top + var aa = isAttribute(a); + var ba = isAttribute(b); + if (aa && !ba) return -1; + if (!aa && ba) return 1; + if (aa && ba) { + var aan = attributeName(a); + var ban = attributeName(b); + if (aan < ban) return -1; + if (aan > ban) return 1; + return 0; + } + + // Sort elements, place services before components + var aen = elementName(a); + var ben = elementName(b); + if (aen == "'service" && ben == "'component") return -1; + if (aen == "'component" && ben == "'service") return 1; + var an = scdl.name(a); + var bn = scdl.name(b); + if (an < bn) return -1; + if (an > bn) return 1; + return 0; + })); +} + +/** * Add a component to a SCDL composite. */ graph.addcomp = function(comp, compos) { @@ -1865,7 +1434,7 @@ graph.cutwire = function(node, compos, g) { var name = scdl.name(comp); var prom = mklist(element, "'service", mklist(attribute, "'name", name), mklist(attribute, "'promote", name)); return append(mklist(element, "'composite"), - append(filter(function(c) { return !(isElement(c) && scdl.name(c) == name); }, elementChildren(compos)), mklist(prom, comp))); + append(mklist(prom), filter(function(c) { return !(isElement(c) && elementName(c) == "'service" && scdl.name(c) == name); }, elementChildren(compos)))); } /** @@ -1933,6 +1502,7 @@ graph.wire = function(n, compos, g) { // Wire component to that reference, un-promote it, and // update the SCDL reference and composite + setElement(n.comp, graph.movecomp(graph.dragging.comp, null)); n.compos = null; setElement(car(cref), append(mklist(element, "'reference", mklist(attribute, "'target", scdl.name(n.comp))), elementChildren(car(cref)))); var name = scdl.name(n.comp); @@ -1981,6 +1551,10 @@ graph.edit = function(appname, compos, nodes, onchange, onselect, g) { g.appname = appname; 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; diff --git a/sca-cpp/trunk/modules/edit/htdocs/graph/index.html b/sca-cpp/trunk/modules/edit/htdocs/graph/index.html index c86b1ef6c1..942433235c 100644 --- a/sca-cpp/trunk/modules/edit/htdocs/graph/index.html +++ b/sca-cpp/trunk/modules/edit/htdocs/graph/index.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <!-- * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -18,25 +19,50 @@ --> <html> <head> -<title>App</title> +<title></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"/> <link rel="apple-touch-icon" href="/public/touchicon.png"/> -<link rel="stylesheet" type="text/css" href="/ui.css"/> +<link rel="stylesheet" type="text/css" href="/ui-min.css"/> <script type="text/javascript" src="/config.js"></script> -<script type="text/javascript" src="/util.js"></script> -<script type="text/javascript" src="/ui.js"></script> +<script type="text/javascript" src="/all-min.js"></script> +<script type="text/javascript" src="/menu.js"></script> +<script type="text/javascript" src="graph.js"></script> </head> -<body class="delayed"> +<body class="delayed" onorientationchange="ui.reload();"> +<div id="bodydiv" class="devicewidth"> + <div id="menu"></div> -<h1><span id="h1"></span><span id="appNameHeader"></span></h1> -<br/> +<table style="width: 100%;"> +<tr> +<td><h1><span id="h1"></span><span id="appNameHeader"></span></h1></td> +<td style="vertical-align: middle; text-align: right;"><span id="saveStatus" style="font-weight: bold; color: #808080;">Saved</span></td> +</tr> +</table> + +<table style="width: 100%;"> +<tr> +<th class="thr thl" style="padding-left: 2px; padding-right: 2px;"> +<input id="compValue" type="text" value="" title="Component value" placeholder="Name" style="position: relative; width: 170px;"/> +<span id="deleteComponentButton" title="Delete a component" class="redbutton" style="font-weight: bold; font-size: 16px; color: #808080; display: inline-block; width: 24px; height: 20px; padding-top: 0px; padding-bottom: 0px; vertical-align: middle; text-align: center; margin-left: 0px; margin-right: 0px;">-</span> +<span id="addComponentButton" title="Add a component" class="greenbutton" style="font-weight: bold; font-size: 16px; display: inline-block; width: 24px; height: 20px; padding-top: 0px; padding-bottom: 0px; vertical-align: middle; text-align: center; margin-left: 0px; margin-right: 0px;">+</span> +<span id="playComponentButton" title="View component value" class="bluebutton" style="font-weight: bold; font-size: 16px; color: #808080; display: inline-block; width: 24px; height: 20px; padding-top: 0px; padding-bottom: 0px; vertical-align: middle; text-align: center; margin-left: 0px; margin-right: 0px;">></span> +</th> +</tr> +</table> + +<div id="dataDiv" style="position:absolute; top: 95px; left: 0px; right: 0px; height: 5000px; visibility: hidden"> +</div> -<div id="graph"></div> +</div> <script type="text/javascript"> +// Get the app name +var appname = ui.queryParams()['app']; +if (isNil(appname)) + window.open('/', '_self'); /** * Return the link to an app. @@ -51,31 +77,275 @@ function applink(appname) { return link; } -// Get the app name -var appname = ui.queryParams()['app']; - -// Update the window title +// Set page titles document.title = windowtitle(window.location.hostname) + ' - ' + (isNil(config.compose)? 'Composition' : config.compose) + ' - ' + appname; $('h1').innerHTML = hometitle(window.location.hostname); $('appNameHeader').innerHTML = ' - <a href=\"' + applink(appname) + '\" target=\"' + '_blank' + '\">' + appname + '</a>'; // Load the menu bar -ui.loadwidget('menu', '/menu.html?app=' + appname, ui.showbody); +displaymenu(); + +// Show the page +ui.showbody(); + +// Init componnent references +var editWidget = sca.component("EditWidget"); +var palettes = sca.reference(editWidget, "palettes"); +var composites = sca.reference(editWidget, "composites"); + +// Setup remote log +//rconsole = sca.defun(sca.reference(editWidget, "log"), "log"); + +/** + * The current app composite, corresponding saved XML content and component name. + */ +var savedcomposxml = ''; +var composite; +var compname = ''; + +/** + * Track the composition graph and whether it's visible or not. + */ +var g; +var gdiv; +var bg; +var gvisible = true; + +// Track the palettes +var gpalettes = new Array(); +var spalette = 'control'; + +/** + * 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); +} /** - * Display the editor for an app. + * Get and display an app. */ -function editapp(name) { +function getapp(name, g) { + if (isNil(name)) + return false; + return composites.get(name, function(doc) { + composite = atomcomposite(doc); + if (isNil(composite)) { + + // Create a default empty composite if necessary + var x = '<composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912" xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1"' + + 'targetNamespace="http://app" name="app"></composite>'; + composite = readXML(mklist(x)); + } + graph.edit(name, composite, graph.composite(composite, graph.mkpath().move(palcx,0)), oncomposchange, oncompselect, g); + + // Track the saved composite XML + savedcomposxml = car(writeXML(composite, false)); + return true; + }); +} + +/** + * Display a palette. Get it from the server if needed. + */ +function displaypalette(name, g, palette, gpalettes) { if (isNil(name)) return; - $('graph').innerHTML = - '<iframe id="graphFrame" style="height: 5000px; width: 100%; border: 0px;" scrolling="no" frameborder="0" src="graph.html?' + - 'app=' + name + - '"></iframe>'; + if (isNil(gpalettes[name])) { + + // Get the palette from the server + var doc = palettes.get(name); + gpalettes[name] = graph.composite(atomcomposite(doc), graph.mkpath().move(80,0)); + } + graph.display(gpalettes[name], g); + return true; +} + +/** + * Install a palette, including a button to select the palette, and + * the palette content. + */ +function installpalette(name, pos, g, bg, palette, gpalettes) { + var b = graph.mkbutton(name, pos); + graph.display(mklist(b), g); + b.onclick = function(e) { + + // Swap the selected palette + displaypalette(spalette, bg, palette, gpalettes); + spalette = name; + return displaypalette(spalette, g, palette, gpalettes); + }; + + if (name != spalette) { + + // Will get the palette from the server later if needed + gpalettes[name] = null; + return true; + } + + // Display the selected palette + return displaypalette(name, g, palette, gpalettes); +} + +/** + * Save the current composite. + */ +function save(savexml) { + $('saveStatus').innerHTML = 'Saving'; + savedcomposxml = savexml; + var entry = '<entry xmlns="http://www.w3.org/2005/Atom">' + + '<title type="text">' + appname + '</title><id>' + appname + '</id><content type="application/xml">' + + savedcomposxml + '</content></entry>'; + composites.put(appname, entry); + $('saveStatus').innerHTML = 'Saved'; + return true; +} + +/** + * Handle a composite change event. + */ +function oncomposchange(prop) { + var newxml = car(writeXML(composite, false)); + if (savedcomposxml == newxml) + return false; + $('saveStatus').innerHTML = 'Modified'; + + // Save property changes right away + if (prop) + return save(newxml); + + // Autosave other changes after 3 seconds + $('saveStatus').innerHTML = 'Modified'; + setTimeout(function() { + var savexml = car(writeXML(composite, false)); + if (savedcomposxml == savexml) { + $('saveStatus').innerHTML = 'Saved'; + return false; + } + return save(savexml); + }, 1000); + return true; +} + +/** + * Return the link to a component value. + */ +function compvaluelink(appname, cname) { + if (cname == '' || isNil(cname)) + return ''; + var protocol = window.location.protocol; + var host = window.location.hostname; + var port = ':' + window.location.port; + if (port == ':80' || port == ':443' || port == ':') + port = ''; + var link = protocol + '//' + appname + '.' + host + port + '/data/?component=' + cname; + return link; +} + +/** + * Return the link to a component raw data. + */ +function compdebuglink(appname, cname) { + if (cname == '' || isNil(cname)) + return ''; + var protocol = window.location.protocol; + var host = window.location.hostname; + var port = ':' + window.location.port; + if (port == ':80' || port == ':443' || port == ':') + port = ''; + var link = protocol + '//' + appname + '.' + host + port + '/components/' + cname; + return link; +} + +/** + * Handle a component select event. + */ +function oncompselect(cname) { + if (cname == compname) + return true; + compname = cname; + var link = compvaluelink(appname, cname); + + function updateButton(b, v) { + b.style.color = v? '#000000' : '#808080'; + } + + updateButton($('deleteComponentButton'), link != ''); + updateButton($('playComponentButton'), link != ''); + return true; +} + +/** + * Show the result data of a component. + */ +function showdata(cname) { + if (!gvisible) + return true; + gvisible = false; + $('playComponentButton').innerHTML = '<'; + gdiv.style.visibility = 'hidden' + var rdiv = $('dataDiv'); + rdiv.style.visibility = 'visible'; + rdiv.innerHTML = '<iframe id="dataFrame" style="position: relative; height: 5000px; width: 100%; border: 0px;" scrolling="no" frameborder="0" src="' + + compvaluelink(appname, cname) + '"></iframe>'; + return true; +} + +/** + * Show the composition graph. + */ +function showgraph() { + if (gvisible) + return true; + gvisible = true; + $('playComponentButton').innerHTML = '>'; + var rdiv = $('dataDiv'); + rdiv.style.visibility = 'hidden'; + rdiv.innerHTML = ''; + gdiv.style.visibility = 'visible' + return true; } -// Display the editor for the current app -editapp(appname); +/** + * Play the current component. + */ +$('playComponentButton').onclick = function() { + if (compname == '') + return false; + if (!gvisible) + return showgraph(); + return showdata(compname); +} + +// Create editor graph area +g = graph.mkgraph(graph.mkpath().move(-2500,95), $('compValue'), $('addComponentButton'), $('deleteComponentButton')); +gdiv = g.parentNode; +bg = graph.mkgroup(graph.mkpath()); + +// Install the palettes +var pos = graph.mkpath(); +installpalette('control', pos.rmove(5,0), g, bg, spalette, gpalettes); +installpalette('values', pos.rmove(0,35), g, bg, spalette, gpalettes); +installpalette('lists', pos.rmove(0, 35), g, bg, spalette, gpalettes); +installpalette('transform', pos.rmove(0, 35), g, bg, spalette, gpalettes); +installpalette('text', pos.rmove(0, 35), g, bg, spalette, gpalettes); +installpalette('http', pos.rmove(0, 35), g, bg, spalette, gpalettes); +installpalette('talk', pos.rmove(0, 35), g, bg, spalette, gpalettes); +installpalette('social', pos.rmove(0, 35), g, bg, spalette, gpalettes); +installpalette('search', pos.rmove(0, 35), g, bg, spalette, gpalettes); +installpalette('database', pos.rmove(0, 35), g, bg, spalette, gpalettes); +installpalette('logic', pos.rmove(0, 35), g, bg, spalette, gpalettes); +installpalette('math', pos.rmove(0, 35), g, bg, spalette, gpalettes); +installpalette('python', pos.rmove(0, 35), g, bg, spalette, gpalettes); + +// Get and display the current app +getapp(appname, g); </script> |