diff options
30 files changed, 906 insertions, 222 deletions
diff --git a/sca-cpp/trunk/modules/edit/Makefile.am b/sca-cpp/trunk/modules/edit/Makefile.am index 5b456ea4ca..2007507817 100644 --- a/sca-cpp/trunk/modules/edit/Makefile.am +++ b/sca-cpp/trunk/modules/edit/Makefile.am @@ -17,6 +17,6 @@ moddir = $(prefix)/modules/edit -nobase_dist_mod_DATA = htdocs/*.html htdocs/dash/*.html htdocs/graph/*.html htdocs/graph/*.js htdocs/page/*.html htdocs/page/*.js htdocs/login/*.html htdocs/logout/*.html -EXTRA_DIST = htdocs/*.html htdocs/dash/*.html htdocs/graph/*.html htdocs/graph/*.js htdocs/page/*.html htdocs/page/*.js htdocs/login/*.html htdocs/logout/*.html +nobase_dist_mod_DATA = htdocs/*.html htdocs/dash/*.html htdocs/app/*.html htdocs/graph/*.html htdocs/graph/*.js htdocs/page/*.html htdocs/page/*.js htdocs/login/*.html htdocs/logout/*.html +EXTRA_DIST = htdocs/*.html htdocs/dash/*.html htdocs/app/*.html htdocs/graph/*.html htdocs/graph/*.js htdocs/page/*.html htdocs/page/*.js htdocs/login/*.html htdocs/logout/*.html diff --git a/sca-cpp/trunk/modules/edit/apps/relay/app.composite b/sca-cpp/trunk/modules/edit/apps/relay/app.composite index 1e5015315c..2f630872de 100644 --- a/sca-cpp/trunk/modules/edit/apps/relay/app.composite +++ b/sca-cpp/trunk/modules/edit/apps/relay/app.composite @@ -28,7 +28,7 @@ <service name="HTML" promote="HTML"/> <service name="JSONFB" promote="JSONFB"/> - <component name="JSONTwit" t:color="red"> + <component name="JSONTwit" t:color="blue1"> <t:implementation.python script="relay.py"/> <service name="Relay"> <t:binding.http uri="jsontwit"/> @@ -38,7 +38,7 @@ </reference> </component> - <component name="XMLTwit" t:color="green"> + <component name="XMLTwit" t:color="green1"> <t:implementation.python script="relay.py"/> <service name="Relay"> <t:binding.http uri="xmltwit"/> @@ -48,7 +48,7 @@ </reference> </component> - <component name="RSSTwit" t:color="blue"> + <component name="RSSTwit" t:color="blue1"> <t:implementation.python script="relay.py"/> <service name="Relay"> <t:binding.http uri="rsstwit"/> @@ -58,7 +58,7 @@ </reference> </component> - <component name="HTML" t:color="yellow"> + <component name="HTML" t:color="yellow1"> <t:implementation.python script="relay.py"/> <service name="Relay"> <t:binding.http uri="html"/> @@ -68,7 +68,7 @@ </reference> </component> - <component name="JSONFB" t:color="orange"> + <component name="JSONFB" t:color="orange1"> <t:implementation.python script="relay.py"/> <service name="Relay"> <t:binding.http uri="jsonfb"/> diff --git a/sca-cpp/trunk/modules/edit/apps/store/app.composite b/sca-cpp/trunk/modules/edit/apps/store/app.composite index ec3fa32fa4..6f4bb9f43c 100644 --- a/sca-cpp/trunk/modules/edit/apps/store/app.composite +++ b/sca-cpp/trunk/modules/edit/apps/store/app.composite @@ -25,7 +25,7 @@ <service name="Store" promote="Store"/> <service name="ShoppingCart" promote="ShoppingCart"/> - <component name="Store" t:color="green"> + <component name="Store" t:color="green1"> <t:implementation.python script="store.py"/> <service name="Widget"> <t:binding.http uri="store"/> @@ -35,7 +35,7 @@ <reference name="shoppingTotal" target="ShoppingCart"/> </component> - <component name="Catalog" t:color="yellow"> + <component name="Catalog" t:color="yellow1"> <t:implementation.python script="fruits-catalog.py"/> <property name="currencyCode">USD</property> <service name="Catalog"> @@ -44,7 +44,7 @@ <reference name="currencyConverter" target="CurrencyConverter"/> </component> - <component name="ShoppingCart" t:color="magenta"> + <component name="ShoppingCart" t:color="magenta1"> <t:implementation.python script="shopping-cart.py"/> <service name="ShoppingCart"> <t:binding.http uri="shoppingCart"/> @@ -52,14 +52,14 @@ <reference name="cache" target="Cache"/> </component> - <component name="CurrencyConverter" t:color="blue"> + <component name="CurrencyConverter" t:color="blue1"> <t:implementation.python script="currency-converter.py"/> <service name="CurrencyConverter"> <t:binding.jsonrpc uri="currencyConverter"/> </service> </component> - <component name="Cache" t:color="orange"> + <component name="Cache" t:color="orange1"> <implementation.cpp path="../../components/cache" library="libmemcache"/> <service name="Cache"> <t:binding.atom uri="cache"/> diff --git a/sca-cpp/trunk/modules/edit/apps/store2/app.composite b/sca-cpp/trunk/modules/edit/apps/store2/app.composite index afec3cb1d3..4a549b37c1 100644 --- a/sca-cpp/trunk/modules/edit/apps/store2/app.composite +++ b/sca-cpp/trunk/modules/edit/apps/store2/app.composite @@ -25,7 +25,7 @@ <service name="Store" promote="Store"/> <service name="ShoppingCart" promote="ShoppingCart"/> - <component name="Store" t:color="green"> + <component name="Store" t:color="green1"> <t:implementation.python script="store.py"/> <service name="Widget"> <t:binding.http uri="store"/> @@ -35,7 +35,7 @@ <reference name="shoppingTotal" target="ShoppingCart"/> </component> - <component name="Catalog" t:color="yellow"> + <component name="Catalog" t:color="yellow1"> <t:implementation.python script="fruits-catalog.py"/> <property name="currencyCode">USD</property> <service name="Catalog" t:align="top"> @@ -44,7 +44,7 @@ <reference name="currencyConverter" t:align="bottom" target="CurrencyConverter"/> </component> - <component name="ShoppingCart" t:color="magenta"> + <component name="ShoppingCart" t:color="magenta1"> <t:implementation.python script="shopping-cart.py"/> <service name="ShoppingCart"> <t:binding.http uri="shoppingCart"/> @@ -52,14 +52,14 @@ <reference name="cache" target="Cache"/> </component> - <component name="CurrencyConverter" t:color="blue"> + <component name="CurrencyConverter" t:color="blue1"> <t:implementation.python script="currency-converter.py"/> <service name="CurrencyConverter" t:align="top"> <t:binding.jsonrpc uri="currencyConverter"/> </service> </component> - <component name="Cache" t:color="orange"> + <component name="Cache" t:color="orange1"> <implementation.cpp path="../../components/cache" library="libmemcache"/> <service name="Cache"> <t:binding.atom uri="cache"/> diff --git a/sca-cpp/trunk/modules/edit/apps/store3/app.composite b/sca-cpp/trunk/modules/edit/apps/store3/app.composite index 7cba2c19e1..9ec440435e 100644 --- a/sca-cpp/trunk/modules/edit/apps/store3/app.composite +++ b/sca-cpp/trunk/modules/edit/apps/store3/app.composite @@ -25,7 +25,7 @@ <service name="Store" promote="Store"/> <service name="ShoppingCart" promote="ShoppingCart"/> - <component name="Store" t:color="green"> + <component name="Store" t:color="green1"> <t:implementation.python script="store.py"/> <service name="Widget"> <t:binding.http uri="store"/> @@ -35,7 +35,7 @@ <reference name="shoppingTotal" target="ShoppingCart"/> </component> - <component name="Catalog" t:color="yellow"> + <component name="Catalog" t:color="yellow1"> <t:implementation.python script="fruits-catalog.py"/> <property name="currencyCode">USD</property> <service name="Catalog"> @@ -44,7 +44,7 @@ <reference name="currencyConverter" t:align="bottom" target="CurrencyConverter"/> </component> - <component name="ShoppingCart" t:color="magenta"> + <component name="ShoppingCart" t:color="magenta1"> <t:implementation.python script="shopping-cart.py"/> <service name="ShoppingCart"> <t:binding.http uri="shoppingCart"/> @@ -52,14 +52,14 @@ <reference name="cache" target="Cache"/> </component> - <component name="CurrencyConverter" t:color="blue"> + <component name="CurrencyConverter" t:color="blue1"> <t:implementation.python script="currency-converter.py"/> <service name="CurrencyConverter" t:align="top"> <t:binding.jsonrpc uri="currencyConverter"/> </service> </component> - <component name="Cache" t:color="orange"> + <component name="Cache" t:color="orange1"> <implementation.cpp path="../../components/cache" library="libmemcache"/> <service name="Cache"> <t:binding.atom uri="cache"/> diff --git a/sca-cpp/trunk/modules/edit/apps/travel/app.composite b/sca-cpp/trunk/modules/edit/apps/travel/app.composite index 833944a855..b4cef31135 100644 --- a/sca-cpp/trunk/modules/edit/apps/travel/app.composite +++ b/sca-cpp/trunk/modules/edit/apps/travel/app.composite @@ -24,7 +24,7 @@ <service name="SCAToursUserInterface" promote="SCAToursUserInterface"/>
- <component name="SCAToursUserInterface" t:color="green">
+ <component name="SCAToursUserInterface" t:color="green1">
<t:implementation.widget location="scatours.html"/>
<service name="Widget">
<t:binding.http uri="/scatours"/>
@@ -80,7 +80,7 @@ <service name="CurrencyConverter"/>
</component>
- <component name="HotelPartner" t:color="orange">
+ <component name="HotelPartner" t:color="orange1">
<implementation.java class="com.tuscanyscatours.hotel.impl.HotelImpl"/>
<service name="Search">
<binding.ws name="searchws" uri="http://localhost:8086/Hotel/Search"/>
@@ -92,7 +92,7 @@ <service name="Book"/>
</component>
- <component name="FlightPartner" t:color="orange">
+ <component name="FlightPartner" t:color="orange1">
<implementation.java class="com.tuscanyscatours.flight.impl.FlightImpl"/>
<service name="Search">
<interface.java interface="com.tuscanyscatours.common.Search"
@@ -106,7 +106,7 @@ <service name="Book"/>
</component>
- <component name="CarPartner" t:color="orange">
+ <component name="CarPartner" t:color="orange1">
<implementation.java class="com.tuscanyscatours.car.impl.CarImpl"/>
<service name="Search">
<binding.ws name="searchws" uri="http://localhost:8086/Car/Search"/>
@@ -170,7 +170,7 @@ <reference name="cartUpdates" target="ShoppingCart/CartUpdates"/>
</component>
- <component name="TripPartner" t:color="orange">
+ <component name="TripPartner" t:color="orange1">
<implementation.java class="com.tuscanyscatours.trip.impl.TripImpl"/>
<service name="Search">
<binding.ws name="searchws" uri="http://localhost:8085/Trip/Search"/>
@@ -191,7 +191,7 @@ </reference>
</component>
- <component name="CartStore" t:color="yellow">
+ <component name="CartStore" t:color="yellow1">
<!-- Add service element to specify alignment -->
<service name="CartStore" t:align="top"/>
<implementation.java class="com.tuscanyscatours.shoppingcart.impl.CartStoreImpl"/>
@@ -220,19 +220,19 @@ </component>
<!-- Add placeholder components representing external endpoints -->
- <component name="HotelSearch" t:color="red">
+ <component name="HotelSearch" t:color="red1">
<service name="HotelSearch"/>
<implementation.java class="com.tuscanyscatours.PlaceHolderImpl" />
</component>
- <component name="FlightSearch" t:color="red">
+ <component name="FlightSearch" t:color="red1">
<service name="FlightSearch"/>
<implementation.java class="com.tuscanyscatours.PlaceHolderImpl" />
</component>
- <component name="CarSearch" t:color="red">
+ <component name="CarSearch" t:color="red1">
<service name="CarSearch"/>
<implementation.java class="com.tuscanyscatours.PlaceHolderImpl" />
</component>
- <component name="TripSearch" t:color="red">
+ <component name="TripSearch" t:color="red1">
<service name="TripSearch"/>
<implementation.java class="com.tuscanyscatours.PlaceHolderImpl" />
</component>
diff --git a/sca-cpp/trunk/modules/edit/htdocs/app/app.html b/sca-cpp/trunk/modules/edit/htdocs/app/app.html new file mode 100644 index 0000000000..a2cf0e1f60 --- /dev/null +++ b/sca-cpp/trunk/modules/edit/htdocs/app/app.html @@ -0,0 +1,85 @@ +<!-- + * 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="/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> +</head> +<body> + +<table style="position: absolute; top: 0px; left: 0px;" width="100%"> +<tr><th><span>App Listing Information</span><span style="padding-top: 0px; padding-bottom:0px; position: absolute; top: 2px; right: 8px;"><input type="button" id="saveButton" style="font-weight: bold;" Value="Save"/></span></th></tr> +</table> +<br> +<br> + +<div> +<form id="appForm"> +<table width="100%"> +<tr><tr><td><b>App Title:</b></td></tr> +<tr><td><input type="text" id="appTitle" size="20"/></td></tr> +</table> +</form> +</div> + +<script type="text/javascript"> + +// Init service references +var editWidget = sca.component("EditWidget"); +var dashboard = sca.reference(editWidget, "dashboard"); + +/** + * The current app name. + */ +var appname = ui.queryParams()['app']; + +/** + * Get and display an app. + */ +function getapp(name) { + dashboard.get(name, function(doc) { + var entry = atom.readATOMEntryDocument(doc); + $('appTitle').value = car(entry); + }); +} + +/** + * Save an app. + */ +$('saveButton').onclick = function() { + var title = $('appTitle').value; + var app = mklist(title, appname, mklist()); + var entry = atom.writeATOMEntry(app); + + dashboard.put(appname, car(entry)); + return false; +}; + +// Get the current app +getapp(appname); + +</script> +</body> +</html> diff --git a/sca-cpp/trunk/modules/edit/htdocs/app/index.html b/sca-cpp/trunk/modules/edit/htdocs/app/index.html new file mode 100644 index 0000000000..ee07b5d4b7 --- /dev/null +++ b/sca-cpp/trunk/modules/edit/htdocs/app/index.html @@ -0,0 +1,66 @@ +<!-- + * 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> +<title>App Editor</title> +<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0"/> +<meta name="apple-mobile-web-app-capable" content="yes"/> +<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"/> +<link rel="stylesheet" type="text/css" href="/ui.css"/> +<script type="text/javascript" src="/util.js"></script> +<script type="text/javascript" src="/ui.js"></script> +</head> +<body> +<div id="menu"></div> + +<br/> +<h1><span id="title"></span></h1> +</br> + +<div id="app"></div> + +<script type="text/javascript"> +/** + * The current app name. + */ +var appname = ui.queryParams()['app']; + +// Load the menu bar +ui.loadwidget('menu', '/menu.html?app=' + appname); + +/** + * Display the page editor for an app. + */ +function editapp(name) { + if (isNil(name)) + return; + $('title').innerHTML = 'Editing: ' + name; + $('app').innerHTML = + '<iframe id="appFrame" style="height: 100%; width: 100%; border: 0px;" scrolling="no" frameborder="0" src="app.html?' + + 'app=' + name + + '"></iframe>'; +} + +// Display the editor for the current app +editapp(appname); + +</script> +</body> +</html> + diff --git a/sca-cpp/trunk/modules/edit/htdocs/dash/dashboard.html b/sca-cpp/trunk/modules/edit/htdocs/dash/dashboard.html index 71f9c61c41..29de0e396a 100644 --- a/sca-cpp/trunk/modules/edit/htdocs/dash/dashboard.html +++ b/sca-cpp/trunk/modules/edit/htdocs/dash/dashboard.html @@ -85,7 +85,8 @@ function getapps(sync) { title = car(entry); apps += '<tr>'; - apps += '<td><input name="apps" type="checkbox" value="' + name + '">' + '<a href=\"' + '/graph/?app=' + name + '\">' + name + '</a></td>'; + //apps += '<td><input name="apps" type="checkbox" value="' + name + '">' + '<a href=\"' + '/app/?app=' + name + '\">' + name + '</a></td>'; + apps += '<td><a href=\"' + '/app/?app=' + name + '\">' + name + '</a></td>'; apps += '<td class="tdw">' + title + '</td>'; apps += '</tr>'; } diff --git a/sca-cpp/trunk/modules/edit/htdocs/dash/index.html b/sca-cpp/trunk/modules/edit/htdocs/dash/index.html index 3b3dcc0cd5..60aafcd12e 100644 --- a/sca-cpp/trunk/modules/edit/htdocs/dash/index.html +++ b/sca-cpp/trunk/modules/edit/htdocs/dash/index.html @@ -34,9 +34,10 @@ <div id="dashboard"></div> <script type="text/javascript"> +// Load the menu bar ui.loadwidget('menu', '/menu.html'); -// Display the dashboard widget +// Load the dashboard ui.loadwidget('dashboard', 'dashboard.html'); </script> </body> diff --git a/sca-cpp/trunk/modules/edit/htdocs/graph/graph.html b/sca-cpp/trunk/modules/edit/htdocs/graph/graph.html index 5eb8c6cc1e..b078901a29 100644 --- a/sca-cpp/trunk/modules/edit/htdocs/graph/graph.html +++ b/sca-cpp/trunk/modules/edit/htdocs/graph/graph.html @@ -31,7 +31,7 @@ <body> <table style="position: absolute; top: 0px; left: 0px;" width="100%"> -<tr><th style="width: 338px;">Palette</th><th style="padding-top: 0px; padding-bottom: 0px;"><span>App</span><span style="position: absolute; top: 2px; right: 8px;"><input type="button" id="saveButton" style="font-weight: bold;" Value="Save"/></span></th></tr> +<tr><th style="width: 338px;">Palette</th><th style="padding-top: 0px; padding-bottom: 0px;"><span>Composition</span><span style="position: absolute; top: 2px; right: 8px;"><input type="button" id="saveButton" style="font-weight: bold;" Value="Save"/></span></th></tr> </table> <script type="text/javascript"> @@ -43,11 +43,14 @@ var apps = sca.reference(editWidget, "apps"); //rconsole = sca.defun(sca.reference(editWidget, "log"), "log"); /** - * Return the current app name. + * The current app name. */ -function appname() { - return ui.queryParams()['app']; -} +var appname = ui.queryParams()['app']; + +/** + * The current app composite. + */ +var composite; /** * Return the composite in an ATOM entry. @@ -65,7 +68,8 @@ function getapp(name, g) { if (isNil(name)) return; apps.get(name, function(doc) { - appendNodes(graph.composite(atomcomposite(doc), graph.mkpath().move(350,0)), g); + composite = atomcomposite(doc); + graph.edit(composite, graph.composite(composite, graph.mkpath().move(350,0)), g); }); } @@ -77,7 +81,7 @@ function getpalette(name, g, bg, palette, gpalettes) { return; palettes.get(name, function(doc) { gpalettes[name] = graph.composite(atomcomposite(doc), graph.mkpath().move(150,0)); - appendNodes(gpalettes[name], name == spalette? g : bg); + graph.display(gpalettes[name], name == spalette? g : bg); }); } @@ -87,16 +91,31 @@ function getpalette(name, g, bg, palette, gpalettes) { */ function installpalette(name, pos, g, bg, palette, gpalettes) { var b = graph.mkbutton(name, pos); - appendNodes(mklist(b), g); + graph.display(mklist(b), g); b.onclick = function() { + // Display the selected palette spalette = name; for (var pn in gpalettes) - appendNodes(gpalettes[pn], pn == spalette? g : bg); + graph.display(gpalettes[pn], pn == spalette? g : bg); } getpalette(name, g, bg, palette, gpalettes); } +/** + * Save the current edited page. + */ +$('saveButton').onclick = function(e) { + + // Update the page ATOM entry + var compxml = writeXML(composite, false); + var entry = '<entry xmlns="http://www.w3.org/2005/Atom">' + + '<title type="text">' + appname + '</title><id>' + appname + '</id><content type="application/xml"><item>' + + compxml + '</item></content></entry>'; + apps.put(appname, entry, function() { + }); +}; + // Create editor graph area var g = graph.mkgraph(graph.mkpath().move(0,50)); var bg = graph.mkgroup(graph.mkpath()); @@ -111,7 +130,7 @@ installpalette('social', graph.mkpath().move(0,220), g, bg, spalette, gpalettes) installpalette('sensors', graph.mkpath().move(0,290), g, bg, spalette, gpalettes); // Get and display the current app -getapp(appname(), g); +getapp(appname, g); </script> </body> diff --git a/sca-cpp/trunk/modules/edit/htdocs/graph/graph.js b/sca-cpp/trunk/modules/edit/htdocs/graph/graph.js index c391afaf23..dc5b48e76a 100644 --- a/sca-cpp/trunk/modules/edit/htdocs/graph/graph.js +++ b/sca-cpp/trunk/modules/edit/htdocs/graph/graph.js @@ -21,12 +21,12 @@ * SVG and VML composite rendering functions. */ -var graph = new Object(); +var graph = {}; /** * Basic colors */ -graph.colors = new Object(); +graph.colors = {}; graph.colors.black = '#000000'; graph.colors.blue = '#0000ff'; graph.colors.cyan = '#00ffff'; @@ -40,6 +40,13 @@ graph.colors.red = '#ff0000'; graph.colors.white = '#ffffff'; graph.colors.yellow = '#ffff00'; +graph.colors.orange1 = '#ffbb00'; +graph.colors.green1 = '#96d333'; +graph.colors.blue1 = '#00c3c9'; +graph.colors.red1 = '#d03f41'; +graph.colors.yellow1 = '#fcee21'; +graph.colors.magenta1 = '#c0688a'; + /** * Base path class. */ @@ -92,21 +99,31 @@ if (ui.isIE()) { document.write('<xml:namespace ns="urn:schemas-microsoft-com:vml" prefix="v" />'); /** - * Make a graph. + * Make a VML graph. */ - graph.mkgraph = function() { + graph.mkgraph = function(pos) { + + // Create div element to host the graph var div = document.createElement('div'); div.id = 'vmldiv'; + div.style.position = 'absolute'; + div.style.left = pos.xpos(); + div.style.top = pos.ypos(); document.body.appendChild(div); + // Create a VML group var vmlg = document.createElement('v:group'); vmlg.style.width = 5000; vmlg.style.height = 5000; vmlg.coordsize = '5000,5000'; div.appendChild(vmlg); + // Keep track of the current dragged element graph.dragging = null; + /** + * Find the first draggable element in a hierarchy of elements. + */ function draggable(n) { if (n == vmlg) return null; @@ -115,53 +132,99 @@ if (ui.isIE()) { return draggable(n.parentNode); } - function bringtotop(n) { - if (n == vmlg) - return null; - n.parentNode.appendChild(n); - return bringtotop(n.parentNode); - } - + /** + * Handle a mousedown event. + */ vmlg.onmousedown = function() { window.event.returnValue = false; + + // Find draggable element graph.dragging = draggable(window.event.srcElement); if (graph.dragging == null) return false; - bringtotop(graph.dragging); + + // Bring it to the top + graph.bringtotop(graph.dragging, vmlg); + + // Remember mouse position graph.dragX = window.event.clientX; graph.dragY = window.event.clientY; vmlg.setCapture(); return false; }; + /** + * Handle a mouseup event. + */ vmlg.onmouseup = function() { if (graph.dragging == null) return false; + + if (graph.dragging.parentNode == vmlg && graph.dragging.id.substring(0, 8) != 'palette:') { + if (ui.csspos(graph.dragging.style.left) >= 350) { + + // Add dragged component to the edited composite + if (!isNil(graph.dragging.comp) && isNil(graph.dragging.compos)) { + var compos = scdl.composite(vmlg.compos); + setlist(compos, graph.addcomp(graph.dragging.comp, compos)); + graph.dragging.compos = vmlg.compos; + } + } else { + + // Discard top level element dragged out of composite area + vmlg.removeChild(graph.dragging); + if (!isNil(graph.dragging.comp) && !isNil(graph.dragging.compos)) { + var compos = scdl.composite(vmlg.compos); + setlist(compos, graph.removecomp(graph.dragging.comp, compos)); + graph.dragging.compos = vmlg.compos; + } + } + } + + // Forget current dragged element graph.dragging = null; vmlg.releaseCapture(); return false; }; + /** + * Handle a mousemove event. + */ vmlg.onmousemove = function() { if (graph.dragging == null) return false; - var origX = graph.dragging.coordorigin.X; - var origY = graph.dragging.coordorigin.Y; - var newX = origX - (window.event.clientX - graph.dragX); - var newY = origY - (window.event.clientY - graph.dragY); - graph.dragX = window.event.clientX; - graph.dragY = window.event.clientY; - if (graph.dragging.id.substring(0, 8) == 'palette:') { - // Clone an element dragged from the palette - var clone = graph.compshape(graph.dragging.comp, mklist(), graph.mkpath().move(ui.posn(graph.dragging.style.left), ui.posn(graph.dragging.style.top))); - graph.dragging.parentNode.appendChild(clone); - graph.dragging = clone; - } - graph.dragging.setAttribute('coordorigin', newX + ' ' + newY); + // Calculate new position of dragged element + var origX = ui.csspos(graph.dragging.style.left); + var origY = ui.csspos(graph.dragging.style.top); + var newX = origX + (window.event.clientX - graph.dragX); + var newY = origY + (window.event.clientY - graph.dragY); + if (newX >= 0) + graph.dragX = window.event.clientX; + else + newX = 0; + if (newY >= 0) + graph.dragY = window.event.clientY; + else + newY = 0; + + // Clone an element dragged from the palette + if (graph.dragging.id.substring(0, 8) == 'palette:') + graph.dragging = graph.clonepalette(graph.dragging); + + // Move the dragged element + graph.dragging.style.left = newX; + graph.dragging.style.top = newY; + + // Update dragged component position + if (!isNil(graph.dragging.comp)) + setlist(graph.dragging.comp, graph.movecomp(graph.dragging.comp, graph.mkpath().move(newX, newY))); + return false; }; + // Create hidden spans to help compute the width of + // component and reference titles graph.comptitlewidthdiv = document.createElement('span'); graph.comptitlewidthdiv.style.visibility = 'hidden' graph.comptitlewidthdiv.style.fontWeight = 'bold' @@ -268,10 +331,14 @@ if (ui.isIE()) { * Return a shape representing a component. */ graph.compshape = function(comp, cassoc, pos) { + + // Make the component title element var title = graph.comptitle(comp); + // Compute the component shape path var d = graph.comppath(comp, cassoc).str(); + // Create the main component shape var shape = document.createElement('v:shape'); shape.style.width = 5000; shape.style.height = 5000; @@ -280,6 +347,7 @@ if (ui.isIE()) { shape.fillcolor = graph.color(comp); shape.stroked = 'false'; + // Create an overlay contour shape var contour = document.createElement('v:shape'); contour.style.width = 5000; contour.style.height = 5000; @@ -294,6 +362,7 @@ if (ui.isIE()) { stroke.opacity = '20%'; contour.appendChild(stroke); + // Create a group and add the component and contour shapes to it var g = document.createElement('v:group'); g.id = scdl.name(comp); g.style.width = 5000; @@ -325,17 +394,23 @@ if (ui.isIE()) { * Return a shape representing a button. */ graph.mkbutton = function(t, pos) { + + // Make the title element var title = graph.mktitle(t, true, pos); + + // Compute the path of the button shape var d = graph.buttonpath().str(); + // Create the main button shape var shape = document.createElement('v:shape'); shape.style.width = 5000; shape.style.height = 5000; shape.coordsize = '5000,5000'; shape.path = d; - shape.fillcolor = graph.colors.blue; + shape.fillcolor = graph.colors.blue1; shape.stroked = 'false'; + // Create an overlay contour shape var contour = document.createElement('v:shape'); contour.style.width = 5000; contour.style.height = 5000; @@ -350,6 +425,7 @@ if (ui.isIE()) { stroke.opacity = '20%'; contour.appendChild(stroke); + // Create a group and add the button and contour shapes to it var g = document.createElement('v:group'); g.style.width = 5000; g.style.height = 5000; @@ -370,9 +446,11 @@ if (ui.isIE()) { graph.svgns='http://www.w3.org/2000/svg'; /** - * Make a graph. + * Make an SVG graph. */ graph.mkgraph = function(pos) { + + // Create a div element to host the graph var div = document.createElement('div'); div.id = 'svgdiv'; div.style.position = 'absolute'; @@ -381,13 +459,18 @@ if (ui.isIE()) { // -webkit-user-select: none; document.body.appendChild(div); + // Create SVG element var svg = document.createElementNS(graph.svgns, 'svg'); svg.style.height = 5000; svg.style.width = 5000; div.appendChild(svg); + // Keep track of current dragged element graph.dragging = null; + /** + * Find the first draggable element in a hierarchy of elements. + */ function draggable(n) { if (n == svg) return null; @@ -396,37 +479,70 @@ if (ui.isIE()) { return draggable(n.parentNode); } - function bringtotop(n) { - if (n == svg) - return null; - n.parentNode.appendChild(n); - return bringtotop(n.parentNode); - } - + /** + * Handle a mouse down event. + */ svg.onmousedown = function(e) { if (e.preventDefault) e.preventDefault(); else e.returnValue = false; + + // Find draggable element graph.dragging = draggable(e.target); if (graph.dragging == null) return false; - bringtotop(graph.dragging); + + // Bring it to the top + graph.bringtotop(graph.dragging, svg); + + // Remember the mouse position var pos = typeof e.touches != "undefined" ? e.touches[0] : e; graph.dragX = pos.screenX; graph.dragY = pos.screenY; return false; }; + // Support touch devices svg.ontouchstart = svg.onmousedown; + /** + * Handle a mouse up event. + */ window.onmouseup = function(e) { if (graph.dragging == null) return false; + + if (graph.dragging.parentNode == svg && graph.dragging.id.substring(0, 8) != 'palette:') { + var pmatrix = graph.dragging.parentNode.getCTM(); + var matrix = graph.dragging.getCTM(); + var curX = pmatrix != null? (Number(matrix.e) - Number(pmatrix.e)): Number(matrix.e); + if (curX >= 350) { + + // Add dragged component to the edited composite + if (!isNil(graph.dragging.comp) && isNil(graph.dragging.compos)) { + var compos = scdl.composite(svg.compos); + setlist(compos, graph.addcomp(graph.dragging.comp, compos)); + graph.dragging.compos = svg.compos; + } + } else { + + // Discard top level element dragged out of composite area + svg.removeChild(graph.dragging); + if (!isNil(graph.dragging.comp) && !isNil(graph.dragging.compos)) { + var compos = scdl.composite(svg.compos); + setlist(compos, graph.removecomp(graph.dragging.comp, compos)); + graph.dragging.compos = svg.compos; + } + } + } + + // Forget current dragged element graph.dragging = null; return false; }; + // Support touch devices window.top.onmouseup = window.onmouseup; window.ontouchend = window.onmouseup; window.gestureend = window.onmouseup; @@ -435,6 +551,9 @@ if (ui.isIE()) { window.ontouchcancel = window.onmouseup; window.top.ontouchcancel = window.onmouseup; + /** + * Handle a mouse move event. + */ window.onmousemove = function(e) { if (graph.dragging == null) return false; @@ -442,6 +561,8 @@ if (ui.isIE()) { e.preventDefault(); else e.returnValue = false; + + // Calculate new position of dragged element var pmatrix = graph.dragging.parentNode.getCTM(); var matrix = graph.dragging.getCTM(); var curX = pmatrix != null? (Number(matrix.e) - Number(pmatrix.e)): Number(matrix.e); @@ -458,20 +579,27 @@ if (ui.isIE()) { else newY = 0; - if (graph.dragging.id.substring(0, 8) == 'palette:') { - // Clone an element dragged from the palette - var clone = graph.compshape(graph.dragging.comp, mklist(), graph.mkpath()); - graph.dragging.parentNode.appendChild(clone); - graph.dragging = clone; - } + // Clone an element dragged from the palette + if (graph.dragging.id.substring(0, 8) == 'palette:') + graph.dragging = graph.clonepalette(graph.dragging); + + // Move the dragged element graph.dragging.setAttribute('transform', 'translate(' + newX + ',' + newY + ')'); + + // Update dragged component position + if (!isNil(graph.dragging.comp)) + setlist(graph.dragging.comp, graph.movecomp(graph.dragging.comp, graph.mkpath().move(newX, newY))); + return false; }; + // Support touch devices window.top.onmousemove = window.onmousemove; window.ontouchmove = window.onmousemove; window.top.ontouchmove = window.onmousemove; + // Create a hidden SVG element to help compute the width + // of component and reference titles graph.titlewidthsvg = document.createElementNS(graph.svgns, 'svg'); graph.titlewidthsvg.style.visibility = 'hidden'; graph.titlewidthsvg.style.height = 0; @@ -571,14 +699,19 @@ if (ui.isIE()) { * Return a shape representing a component. */ graph.compshape = function(comp, cassoc, pos) { + + // Make the component title var title = graph.comptitle(comp); + // Compute the path of the component shape var d = graph.comppath(comp, cassoc).str(); + // Create the main component shape var shape = document.createElementNS(graph.svgns, 'path'); shape.setAttribute('d', d); shape.setAttribute('fill', graph.color(comp)); + // Create an overlay contour shape var contour = document.createElementNS(graph.svgns, 'path'); contour.setAttribute('d', d); contour.setAttribute('fill', 'none'); @@ -587,6 +720,7 @@ if (ui.isIE()) { contour.setAttribute('stroke-opacity', '0.20'); contour.setAttribute('transform', 'translate(1,1)'); + // Create a group and add the component and contour shapes to it. var g = document.createElementNS(graph.svgns, 'g'); g.id = scdl.name(comp); g.setAttribute('transform', 'translate(' + pos.xpos() + ',' + pos.ypos() + ')'); @@ -613,13 +747,19 @@ if (ui.isIE()) { * Return a shape representing a button. */ graph.mkbutton = function(t, pos) { + + // Make the button title var title = graph.mktitle(t, true); + + // Compute the path of the button shape var d = graph.buttonpath().str(); + // Create the main button shape var shape = document.createElementNS(graph.svgns, 'path'); shape.setAttribute('d', d); - shape.setAttribute('fill', graph.colors.blue); + shape.setAttribute('fill', graph.colors.blue1); + // Create an overlay contour shape var contour = document.createElementNS(graph.svgns, 'path'); contour.setAttribute('d', d); contour.setAttribute('fill', 'none'); @@ -628,6 +768,7 @@ if (ui.isIE()) { contour.setAttribute('stroke-opacity', '0.20'); contour.setAttribute('transform', 'translate(1,1)'); + // Create a group and add the button and contour shapes to it var g = document.createElementNS(graph.svgns, 'g'); g.setAttribute('transform', 'translate(' + pos.xpos() + ',' + pos.ypos() + ')'); g.appendChild(shape); @@ -638,6 +779,16 @@ if (ui.isIE()) { } /** + * Bring an element and its parents to the top. + */ +graph.bringtotop = function(n, g) { + if (n == g) + return null; + n.parentNode.appendChild(n); + return graph.bringtotop(n.parentNode, g); +} + +/** * Return the title of a SCDL element. */ graph.title = function(e) { @@ -646,7 +797,17 @@ graph.title = function(e) { }; /** - * Return the services and references of a component. + * Return the color of a component. + */ +graph.color = function(comp) { + return memo(comp, 'color', function() { + var c = scdl.color(comp); + return c == null? graph.colors.blue1 : graph.colors[c]; + }); +}; + +/** + * Return the services on the top side of a component. */ graph.tsvcs = function(comp) { return memo(comp, 'tsvcs', function() { @@ -658,6 +819,9 @@ graph.tsvcs = function(comp) { }); }; +/** + * Return the services on the left side of a component. + */ graph.lsvcs = function(comp) { return memo(comp, 'lsvcs', function() { var svcs = scdl.services(comp); @@ -676,12 +840,18 @@ graph.lsvcs = function(comp) { }); }; +/** + * Return the references on the bottom side of a component. + */ graph.brefs = function(comp) { return memo(comp, 'brefs', function() { return filter(function(r) { return scdl.align(r) == 'bottom'; }, scdl.references(comp)); }); }; +/** + * Return the references on the right side of a component. + */ graph.rrefs = function(comp) { return memo(comp, 'rrefs', function() { return filter(function(r) { var a = scdl.align(r); return a == null || a == 'right'; }, scdl.references(comp)); @@ -689,16 +859,6 @@ graph.rrefs = function(comp) { }; /** - * Return the color of a component. - */ -graph.color = function(comp) { - return memo(comp, 'color', function() { - var c = scdl.color(comp); - return c == null? graph.colors.blue : graph.colors[c]; - }); -}; - -/** * Return the height of a reference on the right side of a component. */ graph.rrefheight = function(ref, cassoc) { @@ -861,33 +1021,43 @@ graph.tsvcpath = function(svc, cassoc, path) { * Return a path representing a component. */ graph.comppath = function(comp, cassoc) { - var height = graph.compheight(comp, cassoc); + + // Calculate the width and height of the component shape var width = graph.compwidth(comp, cassoc); + var height = graph.compheight(comp, cassoc); + /** + * Apply a path rendering function to a list of services or references. + */ function renderpath(x, f, cassoc, path) { if (isNil(x)) return path; return renderpath(cdr(x), f, cassoc, f(car(x), cassoc, path)); } + // Render the services on the top side of the component var tsvcs = graph.tsvcs(comp); var path = graph.mkpath().move(10,0); path = renderpath(tsvcs, graph.tsvcpath, cassoc, path); + // Render the references on the right side of the component var rrefs = graph.rrefs(comp); path = path.line(width - 10,path.ypos()).rcurve(10,0,0,10); path = renderpath(rrefs, graph.rrefpath, cassoc, path); + // Render the references on the bottom side of the component var brefs = reverse(graph.brefs(comp)); var boffset = 10 + graph.brefswidth(brefs, cassoc); path = path.line(path.xpos(),height - 10).rcurve(0,10,-10,0).line(boffset, path.ypos()); path = renderpath(brefs, graph.brefpath, cassoc, path); + // Render the services on the top side of the component var lsvcs = graph.lsvcs(comp); var loffset = 10 + (length(lsvcs) * 60); path = path.line(10,path.ypos()).rcurve(-10,0,0,-10).line(path.xpos(), loffset); path = renderpath(lsvcs, graph.lsvcpath, cassoc, path); + // Close the component shape path path = path.line(0,10).rcurve(0,-10,10,0); return path.end(); }; @@ -915,15 +1085,31 @@ graph.composite = function(compos, pos) { var cassoc = scdl.nameToElementAssoc(comps); var proms = scdl.promotions(compos); + /** + * Render a component. + */ function rendercomp(comp, cassoc, pos) { + + /** + * Render the references on the right side of a component. + */ function renderrrefs(refs, cassoc, pos) { + + /** + * Render a reference on the right side of a component. + */ function renderrref(ref, cassoc, pos) { var target = assoc(scdl.target(ref), cassoc); if (isNil(target)) return mklist(); + + // Render the component target of the reference return rendercomp(cadr(target), cassoc, pos); } + /** + * Move the rendering cursor down below a reference. + */ function rendermove(ref, cassoc, pos) { return pos.clone().rmove(0, graph.rrefheight(ref, cassoc)); } @@ -933,14 +1119,26 @@ graph.composite = function(compos, pos) { return append(renderrref(car(refs), cassoc, pos), renderrrefs(cdr(refs), cassoc, rendermove(car(refs), cassoc, pos))); } + /** + * Render the references on the bottom side of a component. + */ function renderbrefs(refs, cassoc, pos) { + + /** + * Render a reference on the bottom side of a component. + */ function renderbref(ref, cassoc, pos) { var target = assoc(scdl.target(ref), cassoc); if (isNil(target)) return mklist(); + + // Render the component target of the reference return rendercomp(cadr(target), cassoc, pos); } + /** + * Move the rendering cursor to the right of a reference. + */ function rendermove(ref, cassoc, pos) { return pos.clone().rmove(graph.brefwidth(ref, cassoc), 0); } @@ -950,8 +1148,11 @@ graph.composite = function(compos, pos) { return append(renderbref(car(refs), cassoc, pos), renderbrefs(cdr(refs), cassoc, rendermove(car(refs), cassoc, pos))); } + // Compute the component shape var gcomp = graph.compshape(comp, cassoc, pos); + // Add the shapes of the components wired to its references + // as children elements var rrefs = graph.rrefs(comp); var rpos = graph.mkpath().rmove(graph.compwidth(comp, cassoc), 0); appendNodes(renderrrefs(rrefs, cassoc, rpos), gcomp); @@ -963,7 +1164,14 @@ graph.composite = function(compos, pos) { return mklist(gcomp); } + /** + * Render a list of promoted service components. + */ function renderproms(svcs, cassoc, pos) { + + /** + * Return the component promoted by a service. + */ function promcomp(svc, cassoc) { var c = assoc(scdl.promote(svc), cassoc); if (isNil(c)) @@ -971,12 +1179,18 @@ graph.composite = function(compos, pos) { return cadr(c); } + /** + * Return the position of a component. + */ function comppos(comp, pos) { var x = scdl.x(comp); var y = scdl.y(comp); - return graph.mkpath().move(x != null? x : pos.xpos(), y != null? y : pos.ypos()); + return graph.mkpath().move(x != null? Number(x) + 350 : pos.xpos(), y != null? Number(y) : pos.ypos()); } + /** + * Move the rendering cursor down below a component. + */ function rendermove(comp, cassoc, pos) { return pos.clone().rmove(0, graph.compclosureheight(comp, cassoc) + 40); } @@ -984,6 +1198,8 @@ graph.composite = function(compos, pos) { if (isNil(svcs)) return mklist(); + // Render the first promoted component in the list + // then recurse to render the rest of the list var comp = promcomp(car(svcs), cassoc); if (isNil(comp)) return renderproms(cdr(svcs), cassoc, rendermove(car(svcs), cassoc, pos)); @@ -992,13 +1208,85 @@ graph.composite = function(compos, pos) { return append(rendercomp(comp, cassoc, cpos), renderproms(cdr(svcs), cassoc, rendermove(comp, cassoc, cpos))); } + // Render the promoted service components var rproms = renderproms(proms, cassoc, pos.clone().rmove(20,20)); - if (name == 'palette') + if (name == 'palette') { + + // Prefix ids of palette component elements with 'palette:' return map(function(r) { r.id = 'palette:' + r.id; return r; }, rproms); + } else { + + // Link app component elements to the containing composite + return map(function(r) { + r.compos = compos; + return r; + }, rproms); + } return rproms; }; +/** + * Clone a palette element and the component associated with it. + */ +graph.clones = 0; +graph.clonepalette = function(e) { + + // Clone the component and give it a unique name + var comp = append(mklist(element, "'component", mklist(attribute, "'name", scdl.name(e.comp) + (++graph.clones))), + filter(function(c) { return !(isAttribute(c) && attributeName(c) == "'name")}, elementChildren(e.comp))); + + // Make the component shape element + var clone = graph.compshape(comp, mklist(), graph.mkpath()); + e.parentNode.appendChild(clone); + return clone; +}; + +/** + * Move a component to the given position. + */ +graph.movecomp = function(comp, pos) { + + // Add or set the x and y attributes of the component + return append(mklist(element, "'component", mklist(attribute, "'t:x", '' + (pos.xpos() - 350)), mklist(attribute, "'t:y", '' + pos.ypos())), + filter(function(e) { return !(isAttribute(e) && (attributeName(e) == "'t:x" || attributeName(e) == "'t:y")); }, elementChildren(comp))); +}; + +/** + * Add a component to a composite. + */ +graph.addcomp = function(comp, compos) { + var name = scdl.name(comp); + var prom = mklist(element, "'service", mklist(attribute, "'name", name), mklist(attribute, "'promote", name)); + return append(mklist(element, "'composite"), append(elementChildren(compos), mklist(prom, graph.dragging.comp))); +} + +/** + * Remove a component from a composite. + */ +graph.removecomp = function(comp, compos) { + var name = scdl.name(comp); + return append(mklist(element, "'composite"), + filter(function(c) { return !(isElement(c) && scdl.name(c) == name); }, elementChildren(compos))); +} + +/** + * Display a list of graphical nodes. + */ +graph.display = function(nodes, g) { + appendNodes(nodes, g); + return nodes; +}; + +/** + * Display and enable editing of a composite and the graphical + * nodes that represent it. + */ +graph.edit = function(compos, nodes, g) { + g.compos = compos; + return graph.display(nodes, g); +}; + diff --git a/sca-cpp/trunk/modules/edit/htdocs/graph/index.html b/sca-cpp/trunk/modules/edit/htdocs/graph/index.html index aebc0ece68..e1f0bacdeb 100644 --- a/sca-cpp/trunk/modules/edit/htdocs/graph/index.html +++ b/sca-cpp/trunk/modules/edit/htdocs/graph/index.html @@ -18,7 +18,7 @@ --> <html> <head> -<title>App Editor</title> +<title>App Composition Editor</title> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0"/> <meta name="apple-mobile-web-app-capable" content="yes"/> <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"/> @@ -37,14 +37,12 @@ <script type="text/javascript"> /** - * Return the current app name. + * The current app name. */ -function appname() { - return ui.queryParams()['app']; -} +var appname = ui.queryParams()['app']; // Load the menu bar -ui.loadwidget('menu', '/menu.html?app=' + appname()); +ui.loadwidget('menu', '/menu.html?app=' + appname); /** * Display the editor for an app. @@ -60,7 +58,7 @@ function editapp(name) { } // Display the editor for the current app -editapp(appname()); +editapp(appname); </script> </body> diff --git a/sca-cpp/trunk/modules/edit/htdocs/index.html b/sca-cpp/trunk/modules/edit/htdocs/index.html index 4dde5b543d..d0736ba295 100644 --- a/sca-cpp/trunk/modules/edit/htdocs/index.html +++ b/sca-cpp/trunk/modules/edit/htdocs/index.html @@ -37,10 +37,13 @@ <p>Try the <a href="dash">App Dashboard</a> to manage your collection of apps.</p> <h2>App Editor</h2> -<p>Try the <a href="graph/?app=store">App Editor</a> to edit an app.</p> +<p>Try the <a href="app/?app=store">App Editor</a> to edit an app.</p> + +<h2>Composition Editor</h2> +<p>Try the <a href="graph/?app=store">Composition Editor</a> to compose an app.</p> <h2>Page Editor</h2> -<p>Try the <a href="page/?app=store">Page Editor</a> to edit an app page.</p> +<p>Try the <a href="page/?app=store">Page Editor</a> to draw an app page.</p> <script type="text/javascript"> ui.loadwidget('menu', '/menu.html'); diff --git a/sca-cpp/trunk/modules/edit/htdocs/menu.html b/sca-cpp/trunk/modules/edit/htdocs/menu.html index 7155e2fc55..21677c5602 100644 --- a/sca-cpp/trunk/modules/edit/htdocs/menu.html +++ b/sca-cpp/trunk/modules/edit/htdocs/menu.html @@ -40,7 +40,7 @@ var mdiv = $('menu'); var name = appname(); mdiv.innerHTML = ui.menubar( append(mklist(ui.menu('Home', '/'), ui.menu('Dashboard', '/dash')), - (isNil(name) || name == 'undefined')? mklist() : mklist(ui.menu('App', '/graph/?app=' + name), ui.menu('Page', '/page/?app=' + name))), + (isNil(name) || name == 'undefined')? mklist() : mklist(ui.menu('App', '/app/?app=' + name), ui.menu('Composition', '/graph/?app=' + name), ui.menu('Page', '/page/?app=' + name))), mklist(ui.menu('Sign out', '/logout'))); </script> diff --git a/sca-cpp/trunk/modules/edit/htdocs/page/index.html b/sca-cpp/trunk/modules/edit/htdocs/page/index.html index 92f286fdc6..5f9d93efed 100644 --- a/sca-cpp/trunk/modules/edit/htdocs/page/index.html +++ b/sca-cpp/trunk/modules/edit/htdocs/page/index.html @@ -37,14 +37,12 @@ <script type="text/javascript"> /** - * Return the current app name. + * The current app name. */ -function appname() { - return ui.queryParams()['app']; -} +var appname = ui.queryParams()['app']; // Load the menu bar -ui.loadwidget('menu', '/menu.html?app=' + appname()); +ui.loadwidget('menu', '/menu.html?app=' + appname); /** * Display the page editor for an app. @@ -60,7 +58,7 @@ function editapp(name) { } // Display the editor for the current app -editapp(appname()); +editapp(appname); </script> </body> diff --git a/sca-cpp/trunk/modules/edit/htdocs/page/page.html b/sca-cpp/trunk/modules/edit/htdocs/page/page.html index e2cd50088e..202fb7aacc 100644 --- a/sca-cpp/trunk/modules/edit/htdocs/page/page.html +++ b/sca-cpp/trunk/modules/edit/htdocs/page/page.html @@ -57,11 +57,9 @@ var editWidget = sca.component("EditWidget"); var pages = sca.reference(editWidget, "pages"); /** - * Return the current app name. + * The current app name. */ -function appname() { - return ui.queryParams()['app']; -} +var appname = ui.queryParams()['app']; /** * Return the page in an ATOM entry. @@ -79,6 +77,7 @@ function getpage(name, edit) { if (isNil(name)) return; pages.get(name, function(doc) { + // Convert the page to XHTML var xhtml = writeStrings(writeXML(atompage(doc), false)); @@ -88,7 +87,7 @@ function getpage(name, edit) { // Append page nodes to editor map(function(e) { - e.style.left = ui.posn(e.style.left) + 350; + e.style.left = ui.csspos(e.style.left) + 350; edit.appendChild(e); return page.cover(e); }, nodeList(buffer.childNodes[0].childNodes)); @@ -99,6 +98,7 @@ function getpage(name, edit) { * Save the current edited page. */ $('saveButton').onclick = function(e) { + // Copy page DOM to hidden buffer var edit = $('page'); var buffer = $('buffer'); @@ -114,8 +114,8 @@ $('saveButton').onclick = function(e) { div.removeChild(e); return e; } - var x = ui.posn(e.style.left) - 350; - if (x < 0 || ui.posn(e.style.top) < 0) { + var x = ui.csspos(e.style.left) - 350; + if (x < 0 || ui.csspos(e.style.top) < 0) { div.removeChild(e); return e; } @@ -128,11 +128,11 @@ $('saveButton').onclick = function(e) { var xhtml = writeStrings(writeXML(lxhtml, false)); // Update the page ATOM entry - var name = appname(); - var entry = '<entry xmlns="http://www.w3.org/2005/Atom"><title type="text">' + name + '</title><id>' + name + '</id><content type="application/xml"><item>' + + var entry = '<entry xmlns="http://www.w3.org/2005/Atom">' + + '<title type="text">' + appname + '</title><id>' + appname + '</id><content type="application/xml"><item>' + xhtml + '</item></content></entry>'; - pages.put(name, entry, function(e) {}); + pages.put(appname, entry, function(e) {}); }; // Initialize the page editor @@ -140,7 +140,7 @@ var edit = $('page'); page.initpage(edit); // Get and display the current app page -getpage(appname(), edit); +getpage(appname, edit); </script> </body> diff --git a/sca-cpp/trunk/modules/edit/htdocs/page/page.js b/sca-cpp/trunk/modules/edit/htdocs/page/page.js index 25f6399075..4628ec1235 100644 --- a/sca-cpp/trunk/modules/edit/htdocs/page/page.js +++ b/sca-cpp/trunk/modules/edit/htdocs/page/page.js @@ -20,56 +20,66 @@ /** * Page editing functions. */ -var page = new Object(); +var page = {}; if (ui.isIE()) { /** - * Init a page editor. + * Init a page editor. IE-specific implementation. */ page.initpage = function(elem) { - page.dragging = null; - function draggable(n) { - if (n == elem) - return null; - if (n.id != '') - return n; - if (n.covered) - return n.covered; - return draggable(n.parentNode); - } - - function bringtotop(n) { - n.parentNode.appendChild(n); - n.cover.parentNode.appendChild(n.cover); - } + // Keep track of the current dragged element + page.dragging = null; + /** + * Handle a mouse down event. + */ elem.onmousedown = function() { window.event.returnValue = false; - page.dragging = draggable(window.event.srcElement); + + // Find a draggable element + page.dragging = page.draggable(window.event.srcElement, elem); if (page.dragging == null) return false; - bringtotop(page.dragging); + + // Bring it to the top + page.bringtotop(page.dragging); + + // Save the mouse position page.dragX = window.event.clientX; page.dragY = window.event.clientY; elem.setCapture(); return false; }; + /** + * Handle a mouse up event. + */ elem.onmouseup = function() { if (page.dragging == null) return false; + + // Discard element dragged out of page area + if (ui.csspos(page.dragging.style.left) < 350 && page.dragging.id.substring(0, 8) != 'palette:') + page.dragging.parentNode.removeChild(page.dragging); + + // Forget current dragged element page.dragging = null; elem.releaseCapture(); return false; }; + /** + * Handle a mouse move event. + */ elem.onmousemove = function() { if (page.dragging == null) return false; - var curX = ui.posn(page.dragging.style.left); - var curY = ui.posn(page.dragging.style.top); + + // Compute dragged element position + var curX = ui.csspos(page.dragging.style.left); + var curY = ui.csspos(page.dragging.style.top); var newX = curX + (window.event.clientX - page.dragX); var newY = curY + (window.event.clientY - page.dragY); if (newX >= 0) @@ -81,10 +91,11 @@ if (ui.isIE()) { else newY = 0; - if (page.dragging.id.substring(0, 8) == 'palette:') { - // Clone the dragged element + // Clone element dragged from palette + if (page.dragging.id.substring(0, 8) == 'palette:') page.dragging = page.clone(page.dragging); - } + + // Move dragged element page.dragging.style.left = newX; page.dragging.style.top = newY; page.dragging.cover.style.left = newX; @@ -92,7 +103,8 @@ if (ui.isIE()) { }; - // Cover child elements with span elements + // Cover child elements with span elements to prevent + // any input events to reach them map(page.cover, nodeList(elem.childNodes)); return elem; @@ -101,59 +113,69 @@ if (ui.isIE()) { } else { /** - * Init a page editor. + * Init a page editor. Generic implementation for all other browsers. */ page.initpage = function(elem) { page.dragging = null; - function draggable(n) { - if (n == elem) - return null; - if (n.id != '') - return n; - if (n.covered) - return n.covered; - return draggable(n.parentNode); - } - - function bringtotop(n) { - n.parentNode.appendChild(n); - n.cover.parentNode.appendChild(n.cover); - } - + /** + * Handle a mouse down event. + */ elem.onmousedown = function(e) { if (e.preventDefault) e.preventDefault(); else e.returnValue = false; - page.dragging = draggable(e.target); + + // Find a draggable element + page.dragging = page.draggable(e.target, elem); if (page.dragging == null) return false; - bringtotop(page.dragging); + + // Bring it to the top + page.bringtotop(page.dragging); + + // Remember mouse position var pos = typeof e.touches != "undefined" ? e.touches[0] : e; page.dragX = pos.screenX; page.dragY = pos.screenY; return false; }; + // Support touch devices elem.ontouchstart = elem.onmousedown; + /** + * Handle a mouse up event. + */ window.onmouseup = function(e) { if (page.dragging == null) return false; + + // Discard element if dragged out of page area + if (ui.csspos(page.dragging.style.left) < 350 && page.dragging.id.substring(0, 8) != 'palette:') + page.dragging.parentNode.removeChild(page.dragging); + + // Forget dragged element page.dragging = null; return false; }; + // Support touch devices window.top.onmouseup = window.onmouseup; window.ontouchend = window.onmouseup; window.top.ontouchend = window.onmouseup; + /** + * Handle a mouse move event. + */ window.onmousemove = function(e) { if (page.dragging == null) return false; - var curX = ui.posn(page.dragging.style.left); - var curY = ui.posn(page.dragging.style.top); + + // Compute position of dragged element + var curX = ui.csspos(page.dragging.style.left); + var curY = ui.csspos(page.dragging.style.top); var pos = typeof e.touches != "undefined" ? e.touches[0] : e; var newX = curX + (pos.screenX - page.dragX); var newY = curY + (pos.screenY - page.dragY); @@ -166,10 +188,12 @@ if (ui.isIE()) { else newY = 0; + // Clone element dragged from palette if (page.dragging.id.substring(0, 8) == 'palette:') { - // Clone the dragged element page.dragging = page.clone(page.dragging); } + + // Move the dragged element page.dragging.style.left = newX; page.dragging.style.top = newY; page.dragging.cover.style.left = newX; @@ -177,11 +201,13 @@ if (ui.isIE()) { return false; }; + // Support touch devices window.top.onmousemove = window.onmousemove; window.ontouchmove = window.onmousemove; window.top.ontouchmove = window.onmousemove; - // Cover child elements with span elements + // Cover child elements with span elements to prevent + // any input events to reach them map(page.cover, nodeList(elem.childNodes)); return elem; @@ -189,15 +215,37 @@ if (ui.isIE()) { } /** - * Cover a page element with a <span> element to prevent mouse events to reach it. + * Find a draggable element in a hierarchy of elements. + */ +page.draggable = function(n, e) { + if (n == e) + return null; + if (n.id != '') + return n; + if (n.covered) + return n.covered; + return page.draggable(n.parentNode, e); +} + +/** + * Bring an element and its parent to the top. + */ +page.bringtotop = function(n) { + n.parentNode.appendChild(n); + n.cover.parentNode.appendChild(n.cover); +} + +/** + * Cover a page element with a <span> element to prevent + * any input events to reach it. */ page.cover = function(e) { if (e.id == '' || isNil(e.style)) return e; var cover = document.createElement('span'); cover.style.position = 'absolute'; - cover.style.left = ui.posn(e.style.left) - 5; - cover.style.top = ui.posn(e.style.top) - 5; + cover.style.left = ui.csspos(e.style.left) - 5; + cover.style.top = ui.csspos(e.style.top) - 5; cover.style.width = e.clientWidth + 10; cover.style.height = e.clientHeight + 10; cover.style.visibility = 'visible'; @@ -208,20 +256,31 @@ page.cover = function(e) { } /** - * Clone a page element. + * Clone a palette element. */ page.clone = function(e) { + + /** + * Clone an element's HTML. + */ function mkclone(e) { var ne = document.createElement('span'); + + // Skip the palette: prefix ne.id = e.id.substr(8); + + // Copy the HTML content ne.innerHTML = e.innerHTML; return ne; } + /** + * Clone an element's position. + */ function posclone(ne, e) { ne.style.position = 'absolute'; - ne.style.left = ui.posn(e.style.left); - ne.style.top = ui.posn(e.style.top); + ne.style.left = ui.csspos(e.style.left); + ne.style.top = ui.csspos(e.style.top); e.parentNode.appendChild(ne); page.cover(ne); return ne; diff --git a/sca-cpp/trunk/modules/edit/palettes/control/palette.composite b/sca-cpp/trunk/modules/edit/palettes/control/palette.composite index 56c50a4e48..acb1c15755 100644 --- a/sca-cpp/trunk/modules/edit/palettes/control/palette.composite +++ b/sca-cpp/trunk/modules/edit/palettes/control/palette.composite @@ -28,7 +28,7 @@ <service name="ifelse" promote="ifelse"/> <service name="foreach" promote="foreach"/> - <component name="page" t:color="yellow"> + <component name="page" t:color="yellow1"> <documentation>when page requested</documentation> <t:implementation.python script="page.py"/> <service name="page" t:visible="false"/> @@ -36,7 +36,7 @@ <reference name="do" t:align="bottom"/> </component> - <component name="every" t:color="yellow"> + <component name="every" t:color="yellow1"> <documentation>every n seconds</documentation> <t:implementation.python script="every.py"/> <service name="every" t:visible="false"/> @@ -44,14 +44,14 @@ <reference name="do" t:align="bottom"/> </component> - <component name="if" t:color="yellow"> + <component name="if" t:color="yellow1"> <t:implementation.python script="if_.py"/> <service name="if" t:align="top"/> <reference name="condition"/> <reference name="do" t:align="bottom"/> </component> - <component name="ifelse" t:color="yellow"> + <component name="ifelse" t:color="yellow1"> <documentation>if else</documentation> <t:implementation.python script="ifelse.py"/> <service name="ifelse" t:align="top"/> @@ -60,7 +60,7 @@ <reference name="else" t:align="bottom"/> </component> - <component name="foreach" t:color="yellow"> + <component name="foreach" t:color="yellow1"> <documentation>for each</documentation> <t:implementation.python script="ifelse.py"/> <service name="foreach" t:align="top"/> diff --git a/sca-cpp/trunk/modules/edit/palettes/operators/palette.composite b/sca-cpp/trunk/modules/edit/palettes/operators/palette.composite index 35f8dfdf9c..54fd47768a 100644 --- a/sca-cpp/trunk/modules/edit/palettes/operators/palette.composite +++ b/sca-cpp/trunk/modules/edit/palettes/operators/palette.composite @@ -35,37 +35,37 @@ <service name="add" promote="add"/> <service name="subtract" promote="subtract"/> - <component name="true" t:color="green"> + <component name="true" t:color="green1"> <t:implementation.python script="true_.py"/> <service name="true"/> </component> - <component name="false" t:color="green"> + <component name="false" t:color="green1"> <t:implementation.python script="false_.py"/> <service name="false"/> </component> - <component name="and" t:color="green"> + <component name="and" t:color="green1"> <t:implementation.python script="and_.py"/> <service name="and"/> <reference name="value1"/> <reference name="value2"/> </component> - <component name="or" t:color="green"> + <component name="or" t:color="green1"> <t:implementation.python script="or_.py"/> <service name="or"/> <reference name="value1"/> <reference name="value2"/> </component> - <component name="not" t:color="green"> + <component name="not" t:color="green1"> <t:implementation.python script="not_.py"/> <service name="not"/> <reference name="value"/> </component> - <component name="equals" t:color="green"> + <component name="equals" t:color="green1"> <documentation>=</documentation> <t:implementation.python script="equals.py"/> <service name="equals"> @@ -75,7 +75,7 @@ <reference name="value2"/> </component> - <component name="greater" t:color="green"> + <component name="greater" t:color="green1"> <documentation>gt</documentation> <t:implementation.python script="greater.py"/> <service name="greater"> @@ -85,7 +85,7 @@ <reference name="value2"/> </component> - <component name="lesser" t:color="green"> + <component name="lesser" t:color="green1"> <documentation>lt</documentation> <t:implementation.python script="lesser.py"/> <service name="lesser"> @@ -95,7 +95,7 @@ <reference name="value2"/> </component> - <component name="multiply" t:color="green"> + <component name="multiply" t:color="green1"> <documentation>*</documentation> <t:implementation.python script="multiply.py"/> <service name="multiply"> @@ -105,7 +105,7 @@ <reference name="value2"/> </component> - <component name="divide" t:color="green"> + <component name="divide" t:color="green1"> <documentation>/</documentation> <t:implementation.python script="divide.py"/> <service name="divide"> @@ -115,7 +115,7 @@ <reference name="value2"/> </component> - <component name="add" t:color="green"> + <component name="add" t:color="green1"> <documentation>+</documentation> <t:implementation.python script="add.py"/> <service name="add"> @@ -125,7 +125,7 @@ <reference name="value2"/> </component> - <component name="subtract" t:color="green"> + <component name="subtract" t:color="green1"> <documentation>-</documentation> <t:implementation.python script="subtract.py"/> <service name="subtract"> diff --git a/sca-cpp/trunk/modules/edit/palettes/sensors/palette.composite b/sca-cpp/trunk/modules/edit/palettes/sensors/palette.composite index 20ef8225ce..87381f24f4 100644 --- a/sca-cpp/trunk/modules/edit/palettes/sensors/palette.composite +++ b/sca-cpp/trunk/modules/edit/palettes/sensors/palette.composite @@ -24,7 +24,7 @@ <service name="location" promote="location"/> - <component name="location" t:color="magenta"> + <component name="location" t:color="magenta1"> <t:implementation.python script="location.py"/> <service name="location"/> </component> diff --git a/sca-cpp/trunk/modules/edit/palettes/social/palette.composite b/sca-cpp/trunk/modules/edit/palettes/social/palette.composite index 264e2ed137..739b878025 100644 --- a/sca-cpp/trunk/modules/edit/palettes/social/palette.composite +++ b/sca-cpp/trunk/modules/edit/palettes/social/palette.composite @@ -28,7 +28,7 @@ <service name="HTML" promote="HTML"/> <service name="JSONFB" promote="JSONFB"/> - <component name="JSONTwit" t:color="red"> + <component name="JSONTwit" t:color="blue1"> <t:implementation.python script="relay.py"/> <service name="Relay"> <t:binding.http uri="jsontwit"/> @@ -38,7 +38,7 @@ </reference> </component> - <component name="XMLTwit" t:color="green"> + <component name="XMLTwit" t:color="blue1"> <t:implementation.python script="relay.py"/> <service name="Relay"> <t:binding.http uri="xmltwit"/> @@ -48,7 +48,7 @@ </reference> </component> - <component name="RSSTwit" t:color="blue"> + <component name="RSSTwit" t:color="blue1"> <t:implementation.python script="relay.py"/> <service name="Relay"> <t:binding.http uri="rsstwit"/> @@ -58,7 +58,7 @@ </reference> </component> - <component name="HTML" t:color="yellow"> + <component name="HTML" t:color="blue1"> <t:implementation.python script="relay.py"/> <service name="Relay"> <t:binding.http uri="html"/> @@ -68,7 +68,7 @@ </reference> </component> - <component name="JSONFB" t:color="orange"> + <component name="JSONFB" t:color="blue1"> <t:implementation.python script="relay.py"/> <service name="Relay"> <t:binding.http uri="jsonfb"/> diff --git a/sca-cpp/trunk/modules/edit/palettes/variables/palette.composite b/sca-cpp/trunk/modules/edit/palettes/variables/palette.composite index 42fc43525b..1d10027f95 100644 --- a/sca-cpp/trunk/modules/edit/palettes/variables/palette.composite +++ b/sca-cpp/trunk/modules/edit/palettes/variables/palette.composite @@ -29,17 +29,17 @@ <service name="first" promote="first"/> <service name="rest" promote="rest"/> - <component name="number" t:color="orange"> + <component name="number" t:color="orange1"> <t:implementation.python script="number.py"/> <service name="number"/> </component> - <component name="text" t:color="orange"> + <component name="text" t:color="orange1"> <t:implementation.python script="text.py"/> <service name="text"/> </component> - <component name="set" t:color="orange"> + <component name="set" t:color="orange1"> <documentation>set variable</documentation> <t:implementation.python script="set.py"/> <service name="set"/> @@ -47,7 +47,7 @@ <reference name="variable"/> </component> - <component name="list" t:color="orange"> + <component name="list" t:color="orange1"> <documentation>make a list</documentation> <t:implementation.python script="list_.py"/> <service name="list"/> @@ -55,14 +55,14 @@ <reference name="rest"/> </component> - <component name="first" t:color="orange"> + <component name="first" t:color="orange1"> <documentation>first of a list</documentation> <t:implementation.python script="first.py"/> <service name="first"/> <reference name="value"/> </component> - <component name="rest" t:color="orange"> + <component name="rest" t:color="orange1"> <documentation>rest of a list</documentation> <t:implementation.python script="rest.py"/> <service name="rest"/> diff --git a/sca-cpp/trunk/modules/js/htdocs/atomutil.js b/sca-cpp/trunk/modules/js/htdocs/atomutil.js index 24a47980f7..21aa16e0fc 100644 --- a/sca-cpp/trunk/modules/js/htdocs/atomutil.js +++ b/sca-cpp/trunk/modules/js/htdocs/atomutil.js @@ -20,7 +20,7 @@ /** * ATOM data conversion functions. */ -var atom = new Object(); +var atom = {}; /** * Convert a list of elements to a list of values representing an ATOM entry. diff --git a/sca-cpp/trunk/modules/js/htdocs/component.js b/sca-cpp/trunk/modules/js/htdocs/component.js index 9907e955c9..835cc148c2 100644 --- a/sca-cpp/trunk/modules/js/htdocs/component.js +++ b/sca-cpp/trunk/modules/js/htdocs/component.js @@ -34,7 +34,7 @@ /** * Escape a character. */ -var JSONClient = new Object(); +var JSONClient = {}; JSONClient.escapeJSONChar = function(c) { if(c == "\"" || c == "\\") return "\\" + c; @@ -450,7 +450,7 @@ if (typeof DOMParser == "undefined") { * Public API. */ -var sca = new Object(); +var sca = {}; /** * Return a component. diff --git a/sca-cpp/trunk/modules/js/htdocs/elemutil.js b/sca-cpp/trunk/modules/js/htdocs/elemutil.js index be976c3982..f6f8dcd186 100644 --- a/sca-cpp/trunk/modules/js/htdocs/elemutil.js +++ b/sca-cpp/trunk/modules/js/htdocs/elemutil.js @@ -203,18 +203,28 @@ function selector(s) { } /** - * Return the value of the attribute with the given name. + * Return the attribute with the given name. */ -function namedAttributeValue(name, l) { +function namedAttribute(name, l) { return memo(l, name, function() { var f = filter(function(v) { return isAttribute(v) && attributeName(v) == name; }, l); if (isNil(f)) return null; - return caddr(car(f)); + return car(f); }); } /** + * Return the value of the attribute with the given name. + */ +function namedAttributeValue(name, l) { + var a = namedAttribute(name, l); + if (a == null) + return null + return attributeValue(a); +} + +/** * Return child elements with the given name. */ function namedElementChildren(name, l) { @@ -233,3 +243,41 @@ function namedElementChild(name, l) { return car(f); } +/** + * Side effect functions. Use with moderation. + */ + +/** + * Set the value of the attribute with the given name. + */ +function setNamedAttributeValue(name, v, l) { + var f = filter(function(v) { return isAttribute(v) && attributeName(v) == name; }, l); + if (!isNil(f)) { + + // Un-memoize attribute and change its value + unmemo(l, name); + car(f)[2] = '' + v; + return v; + } + + // Insert new attribute + insertn$(mklist(attribute, name, '' + v), l, 2); + return v; +} + +/** + * Set the value of an element. + */ +function setElementValue(v, l) { + if (elementHasValue(l)) { + + // Change existing element value + l[length(l) - 1] = v; + return v; + } + + // Append element value + $append(l, mklist(v)); + return v; +} + diff --git a/sca-cpp/trunk/modules/js/htdocs/scdl.js b/sca-cpp/trunk/modules/js/htdocs/scdl.js index df661a29ba..73d07b4a1c 100644 --- a/sca-cpp/trunk/modules/js/htdocs/scdl.js +++ b/sca-cpp/trunk/modules/js/htdocs/scdl.js @@ -20,7 +20,7 @@ /** * SCDL parsing functions. */ -var scdl = new Object(); +var scdl = {}; /** * Returns a composite element. diff --git a/sca-cpp/trunk/modules/js/htdocs/ui.css b/sca-cpp/trunk/modules/js/htdocs/ui.css index f3f4507e27..5b441b735d 100644 --- a/sca-cpp/trunk/modules/js/htdocs/ui.css +++ b/sca-cpp/trunk/modules/js/htdocs/ui.css @@ -28,10 +28,10 @@ font-family: arial,sans-serif; font-style: normal; font-variant: normal; font-si } th { -font-weight: bold; background-color: #e5ecf9; color: #598edd; +font-weight: bold; background-color: #96d333; color: #000000; text-align: left; padding-left: 2px; padding-right: 8px; padding-top: 2px; padding-bottom: 4px; vertical-align: text-top; border-top: 1px; border-bottom: 1px; border-left: 0px; border-right: 0px; -border-style: solid; border-top-color: #a2bae7; border-bottom-color: #d1d3d4; +border-style: solid; border-top-color: #96d333; border-bottom-color: #96d333; } td { @@ -52,11 +52,11 @@ vertical-align: middle; } a:link { -color: blue; +color: #96d333; } a:visited { -color: blue; +color: #96d333; } h1 { diff --git a/sca-cpp/trunk/modules/js/htdocs/ui.js b/sca-cpp/trunk/modules/js/htdocs/ui.js index 483aef6f9f..31cdaed7c6 100644 --- a/sca-cpp/trunk/modules/js/htdocs/ui.js +++ b/sca-cpp/trunk/modules/js/htdocs/ui.js @@ -21,7 +21,7 @@ * UI utility functions. */ -var ui = new Object(); +var ui = {}; /** * Return true if the current browser is Internet Explorer. @@ -266,7 +266,7 @@ ui.installwidget = function() { /** * Convert a CSS position to a numeric position. */ -ui.posn = function(p) { +ui.csspos = function(p) { if (p == '') return 0; return Number(p.substr(0, p.length - 2)); diff --git a/sca-cpp/trunk/modules/js/htdocs/util.js b/sca-cpp/trunk/modules/js/htdocs/util.js index 155836b4e9..873874c7be 100644 --- a/sca-cpp/trunk/modules/js/htdocs/util.js +++ b/sca-cpp/trunk/modules/js/htdocs/util.js @@ -218,3 +218,121 @@ function memo(obj, key, f) { return obj[key] = f(); } +/** + * Un-memoize a value. + */ +function unmemo(obj, key) { + obj[key] = null; + return true; +} + +/** + * Functions with side effects. Use with moderation. + */ + +/** + * Set the car of a list. + */ +function setcar(l, v) { + l[0] = v; + return l; +} + +/** + * Set the cadr of a list. + */ +function setcadr(l, v) { + l[1] = v; + return l; +} + +/** + * Set the caddr of a list. + */ +function setcaddr(l, v) { + l[2] = v; + return l; +} + +/** + * Append the elements of a list to a list. + */ +function setappend(a, b) { + if (isNil(b)) + return a; + a.push(car(b)); + return setappend(a, cdr(b)); +} + +/** + * Set the cdr of a list. + */ +function setcdr(a, b) { + a.length = 1; + return setappend(a, b); +} + +/** + * Set the contents of a list. + */ +function setlist(a, b) { + a.length = 0; + return setappend(a, b); +} + +/** + * Insert a value at a given position in a list. + */ +function insertn$(v, n, l) { + function upshift(i) { + if (i == n) + return true; + l[i] = l[i - 1]; + return upshift(i - 1); + } + + upshift(length(l)); + l[n] = v; + return l; +} + +/** + * Insert a value at the beginning of a list. + */ +function insert$(v, l) { + return insertn$(v, 0, l); +} + +/** + * Append a list at the end of a list. + */ +function append$(a, b) { + if (isNil(b)) + return a; + a.push(car(b)); + return append$(a, cdr(b)); +} + +/** + * Delete a value from a list. + */ +function delete$(v, l) { + function dnshift(i, max) { + if (i >= max) + return true; + l[i] = l[i + 1]; + return dnshift(i + 1, max); + } + + dnshift(n, length(l) - 1); + l.pop(); + return l; +} + +/** + * Delete a value at the beginning of a list. + */ +function delete$(l) { + return deleten$(l, 0); +} + |