Simplify page navigations and optimize layout and event handling on touch devices. Optimize caching and minimize Ajax calls.

git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@1126297 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
jsdelfino 2011-05-23 02:28:47 +00:00
parent 09fdc02e7a
commit 49f4223605
17 changed files with 801 additions and 458 deletions

View file

@ -57,6 +57,7 @@ config.sub
config.status
config.js
all.js
intro*.png
depcomp
install-sh
ltmain.sh

View file

@ -1,25 +0,0 @@
CACHE MANIFEST
# Common resources
all-min.js
config.js
ui-min.css
# App resources
app.html
data/index.html
favicon.ico
index.html
public/app.png
public/iframe.html
public/img.png
public/notauth.html
public/notfound.html
public/notyet.html
public/oops.html
public/touchicon.png
robots.txt
NETWORK:
*

View file

@ -0,0 +1,25 @@
CACHE MANIFEST
# Common resources
/all-min.js
/config.js
/ui-min.css
# App resources
/
/app.html
/data/index.html
/favicon.ico
/public/app.png
/public/iframe.html
/public/img.png
/public/notauth.html
/public/notfound.html
/public/notyet.html
/public/oops.html
/public/touchicon.png
/robots.txt
NETWORK:
*

View file

@ -17,7 +17,7 @@
* specific language governing permissions and limitations
* under the License.
-->
<html manifest="/cache-manifest.cmf">
<html>
<head>
<title>App</title>
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0"/>
@ -37,20 +37,25 @@ document.title = window.location.hostname.split('.')[0];
<div id="app"></div>
<span id="appFrame"></span>
<span id="appbuffer"></span>
<span id="appebuffer"></span>
</div>
<script type="text/javascript">
if (ui.isIE()) $('bodydiv').style.right = -20;
/**
* Start, stop, timer and geolocation components.
* The main app div.
*/
var appdiv = $('app');
/**
* Start, stop, timer and location components.
*/
var startcomp = sca.httpclient('start', '/start');
var stopcomp = sca.httpclient('stop', '/stop');
var timercomp = sca.httpclient('timer', '/timer');
var geolocationcomp = sca.httpclient('geolocation', '/geolocation');
var locationcomp = sca.httpclient('location', '/location');
/**
* Find a named value in a tree of elements.
@ -146,13 +151,13 @@ function setwidgetvalue(e, dv) {
return t;
}
if (e.className == 'list') {
var t = ui.datalist(mklist(dv));
car(childElements(e)).innerHTML = t;
var t = ui.datalist(isNil(dv)? mklist() : mklist(dv));
e.innerHTML = t;
return t;
}
if (e.className == 'table') {
var t = ui.datatable(mklist(dv));
car(childElements(e)).innerHTML = t;
var t = ui.datatable(isNil(dv)? mklist() : mklist(dv));
e.innerHTML = t;
return t;
}
if (e.className == 'link') {
@ -190,7 +195,7 @@ function displaydata(l) {
return e;
}
map(updatewidget, filter(function(e) { return !isNil(e.id); }, nodeList(ui.elementByID($('app'), 'page').childNodes)));
map(updatewidget, filter(function(e) { return !isNil(e.id) && e.id.substring(0, 5) != 'page:'; }, nodeList(ui.elementByID(appdiv, 'page').childNodes)));
return true;
}
@ -219,10 +224,11 @@ function displaydoc(doc) {
function bindwidgethandler(e) {
if (e.className == 'button') {
var b = car(childElements(e));
b.onclick = function() { return buttonClickHandler(e.id); };
b.name = e.id;
b.onclick = function() { return buttonClickHandler(b.value); };
return e;
}
if (e.className == 'button' || e.className == 'entry' || e.className == 'password' || e.className == 'checkbox') {
if (e.className == 'entry' || e.className == 'password' || e.className == 'checkbox') {
car(childElements(e)).name = e.id;
return e;
}
@ -262,6 +268,15 @@ function fixupwidget(e) {
return e;
}
/**
* Set initial value of a widget.
*/
function initwidget(e) {
if (!isNil(e.id) && e.id.substring(0, 5) != 'page:')
setwidgetvalue(e, mklist());
return e;
}
/**
* Get app data from the main app page component.
*/
@ -291,6 +306,7 @@ function getpagedata() {
// Initial setup of a widget
function setupwidget(e) {
initwidget(e);
fixupwidget(e);
bindwidgethandler(e);
}
@ -298,17 +314,24 @@ function getpagedata() {
// Get the component app data
var doc = startcomp.get(window.location.search);
try {
$('app').innerHTML = $('appFrame').contentDocument.body.innerHTML;
var appFrame = $('appFrame');
if (!isNil(appFrame.contentDocument.body)) {
appdiv.innerHTML = appFrame.contentDocument.body.innerHTML;
} else {
$('appebuffer').appendChild(appFrame.contentDocument.documentElement);
appdiv.innerHTML = appebuffer.innerHTML;
appebuffer.innerHTML = '';
}
// Initial setup of the widgets
map(setupwidget, filter(function(e) { return !isNil(e.id); }, nodeList(ui.elementByID($('app'), 'page').childNodes)));
map(setupwidget, filter(function(e) { return !isNil(e.id); }, nodeList(ui.elementByID(appdiv, 'page').childNodes)));
// Display data on the page
displaypage(doc);
// Get and eval the optional timer and location watch setup scripts
evalcompinit(timercomp.get('setup'));
evalcompinit(geolocationcomp.get('setup'));
evalcompinit(locationcomp.get('setup'));
return true;
} catch(e) {
@ -339,7 +362,7 @@ function compquery() {
return append(nodeList(n.childNodes), reduce(append, mklist(), map(childrenList, nodeList(n.childNodes))));
}
var args = map(queryarg, filter(function(e) { return !isNil(e.id) && !isNil(inputvalue(e)); }, childrenList(ui.elementByID($('app'), 'page'))));
var args = map(queryarg, filter(function(e) { return !isNil(e.id) && !isNil(inputvalue(e)); }, childrenList(ui.elementByID(appdiv, 'page'))));
// Append current location properties if known
if (!isNil(geoposition)) {
@ -378,6 +401,7 @@ function intervalHandler() {
* Setup an interval timer.
*/
function setupIntervalHandler(msec) {
intervalHandler();
try {
return setInterval(intervalHandler, msec);
} catch(e) {
@ -394,7 +418,7 @@ var geoposition = null;
function locationHandler(pos) {
try {
geoposition = pos;
return getcompdata(geolocationcomp, compquery());
return getcompdata(locationcomp, compquery());
} catch(e) {
locationErrorHandler(e);
}
@ -431,7 +455,7 @@ function setupLocationHandler() {
}
// Load the app frame
$('app').innerHTML = '<iframe id="appFrame" class="widgetFrame" src="app.html" onload="getpagedata()"></iframe>';
$('appbuffer').innerHTML = '<iframe id="appFrame" class="widgetframe" src="app.html" onload="getpagedata()"></iframe>';
</script>
</body>

View file

@ -1,36 +1,37 @@
CACHE MANIFEST
# Common resources
all-min.js
config.js
ui-min.css
/all-min.js
/config.js
/ui-min.css
# App resources
app/index.html
clone/index.html
data/index.html
create/index.html
data/index.html
favicon.ico
graph/graph.js
graph/index.html
home.png
index.html
menu.js
page/index.html
page/page.js
public/app.png
public/grid72.png
public/iframe.html
public/img.png
public/notauth.html
public/notfound.html
public/notyet.html
public/oops.html
public/touchicon.png
robots.txt
stats/index.html
store/index.html
/
/account/
/app/
/clone/
/data/
/create/
/data/
/favicon.ico
/graph/graph.js
/graph/
/home.png
/menu.js
/page/
/page/page.js
/public/app.png
/public/grid72.png
/public/iframe.html
/public/img.png
/public/notauth.html
/public/notfound.html
/public/notyet.html
/public/oops.html
/public/touchicon.png
/robots.txt
/stats/
/store/
NETWORK:
*

View file

@ -36,7 +36,7 @@
<table style="width: 100%;">
<tr>
<td><h1><span id="h1"></span><span id="appNameHeader"></span></h1></td>
<td><h2><span id="h1"></span><span id="appNameHeader"></span></h2></td>
</tr>
</table>
@ -49,7 +49,7 @@
<form id="cloneAppForm" style="position: absolute; top: 90px; left: 0px;">
<table style="width: 100%;">
<tr><td><b>New App Name:</b></td></tr>
<tr><td><input type="text" id="appName" size="15" placeholder="Your app name"/>&nbsp;<span id="appDomain"></span></td></tr>
<tr><td><input type="text" id="appName" size="15" autocapitalize="off" placeholder="Your app name"/>&nbsp;<span id="appDomain"></span></td></tr>
<tr><tr><td style="padding-top: 6px;"><b>App Icon:</b></td></tr>
<tr><td><img src="/public/app.png" style="width: 50px; height: 50px; vertical-align: top;"></td></tr>
<tr><tr><td style="padding-top: 6px;"><b>Sharing:</b></td></tr>
@ -89,11 +89,11 @@ function applink(appname) {
// Set page titles
var tclone = isNil(config.clone)? 'Clone' : config.clone;
document.title = windowtitle(window.location.hostname) + ' - ' + tclone + ' - ' + appname;
$('h1').innerHTML = hometitle(window.location.hostname);
$('appNameHeader').innerHTML = ' - <a href=\"' + applink(appname) + '\" target=\"' + '_blank' + '\">' + appname + '</a>';
//$('h1').innerHTML = hometitle(window.location.hostname);
$('appNameHeader').innerHTML = '<a href=\"' + applink(appname) + '\" target=\"' + '_blank' + '\">' + appname + '.' + window.location.hostname + '</a>';
$('th').innerHTML = tclone + ' this App';
$('cloneAppOKButton').value = tclone;
$('cloneAppOKButton').title = tclone + ' the app';
$('cloneAppOKButton').title = tclone + ' this app';
// Load the menu bar
displaymenu();
@ -106,7 +106,7 @@ ui.showbody();
// Init service references
var editWidget = sca.component("EditWidget");
var dashboard = sca.reference(editWidget, "dashboard");
var dashboards = sca.reference(editWidget, "dashboards");
var apps = sca.reference(editWidget, "apps");
/**
@ -138,11 +138,15 @@ $('cloneAppForm').onsubmit = function() {
var name = $('appName').value;
if (name == '')
return false;
// Clone the app
var title = $('appTitle').value;
var app = mklist(mklist("'entry", mklist("'title", title != ''? title : name), mklist("'id", appname)));
var entry = atom.writeATOMEntry(valuesToElements(app));
dashboard.put(name, car(entry));
window.open('/store/', '_self');
dashboards.put(name, car(entry));
// Open it in the page editor
window.open('/page/?app=' + name, '_self');
return false;
};
@ -150,7 +154,7 @@ $('cloneAppForm').onsubmit = function() {
* Cancel cloning an app.
*/
$('cloneAppCancelButton').onclick = function() {
return window.open('/store/', '_self');
window.open('/stats/?app=' + appname, '_self');
};
// Get the current app

View file

@ -47,7 +47,7 @@
<form id="createAppForm" style="position: absolute; top: 90px; left: 0px;">
<table style="width: 100%;">
<tr><td><b>App Name:</b></td></tr>
<tr><td><input type="text" id="appName" size="15" placeholder="Your app name"/>&nbsp;<span id="appDomain"></span></td></tr>
<tr><td><input type="text" id="appName" size="15" autocapitalize="off" placeholder="Your app name"/>&nbsp;<span id="appDomain"></span></td></tr>
<tr><tr><td style="padding-top: 6px;"><b>App Icon:</b></td></tr>
<tr><td><img src="/public/app.png" style="width: 50px; height: 50px; vertical-align: top;"></td></tr>
<tr><tr><td style="padding-top: 6px;"><b>Sharing:</b></td></tr>
@ -81,7 +81,8 @@ ui.showbody();
// Init service references
var editWidget = sca.component("EditWidget");
var dashboard = sca.reference(editWidget, "dashboard");
var dashboards = sca.reference(editWidget, "dashboards");
var apps = sca.reference(editWidget, "apps");
/**
* Create an app.
@ -90,11 +91,15 @@ $('createAppForm').onsubmit = function() {
var name = $('appName').value;
if (name == '')
return false;
// Clone the '.new' app template
var title = $('appTitle').value;
var app = mklist(mklist("'entry", mklist("'title", title != ''? title : name), mklist("'id", name)));
var app = mklist(mklist("'entry", mklist("'title", title != ''? title : name), mklist("'id", 'new')));
var entry = atom.writeATOMEntry(valuesToElements(app));
dashboard.put(name, car(entry));
window.open('/store/', '_self');
dashboards.put(name, car(entry));
// Open it in the page editor
window.open('/page/?app=' + name, '_self');
return false;
};

View file

@ -35,23 +35,25 @@ document.title = 'View - ' + window.location.hostname.split('.')[0] + '/' + cn;
<body class="delayed" onorientationchange="ui.reload();">
<div id="bodydiv" style="position: absolute; top: 0px; left: 0px; right: 0px;">
<div id="compLinkHeader" style="margin-top: 4px; margin-bottom: 4px;"></div>
<div id="datadiv" style="position: relative; left: 0px; right: 0px;">
</div>
<script type="text/javascript">
if (ui.isIE()) $('bodydiv').style.right = -20;
// Get the component name
var cname = ui.queryParams()['component'];
/**
* The current component.
*/
var cname = ui.queryParams()['component'];
var comp = sca.component(cname);
/**
* Display an HTML element.
*/
function display(e) {
$('bodydiv').innerHTML = e;
$('datadiv').innerHTML = e;
ui.showbody();
return true;

View file

@ -41,6 +41,8 @@ graph.colors.red = '#ff0000';
graph.colors.white = '#ffffff';
graph.colors.yellow = '#ffff00';
graph.colors.link = '#598edd';
graph.colors.orange1 = '#ffbb00';
graph.colors.green1 = '#96d333';
graph.colors.blue1 = '#00c3c9';
@ -54,7 +56,6 @@ graph.colors.lightgray1 = '#dcdcdc'
* Default positions and sizes.
*/
var palcx = 2500;
var trashcx = 2480;
var proxcx = 20;
var proxcy = 20;
var buttoncx = 65;
@ -150,53 +151,22 @@ graph.mkgraph = function(pos, cvalue, cadd, cdelete) {
*/
div.onmousedown = function(e) {
// On mouse controlled devices, engage the click component selection
// logic right away
if (typeof e.touches == 'undefined')
div.onclick(e);
// Find draggable component
graph.dragging = draggable(e.target);
graph.selected = graph.dragging;
if (graph.dragging == null) {
// Reset current selection
cvalue.value = '';
cvalue.disabled = true;
cdelete.disabled = true;
// Trigger component select event
svg.oncompselect('');
var dragging = draggable(e.target);
if (dragging == null || dragging != graph.selected)
return true;
}
// 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;
// Move into the editing area and hide the palette
var gpos = graph.relpos(graph.dragging);
graph.move(graph.dragging, graph.mkpath().move(gpos.xpos() + palcx, gpos.ypos()));
div.style.left = ui.pixpos(palcx * -1);
}
// Cut wire to component
if (graph.dragging.parentNode != svg)
setElement(compos, graph.sortcompos(graph.cutwire(graph.dragging, compos, svg)));
// Bring component to the top
graph.bringtotop(graph.dragging, svg);
graph.dragging = dragging;
// 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
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
@ -216,45 +186,28 @@ graph.mkgraph = function(pos, cvalue, cadd, cdelete) {
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.sortcompos(graph.addcomp(graph.dragging.comp, compos)));
graph.dragging.compos = svg.compos;
}
// 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;
}
// Update component position
setElement(graph.dragging.comp, graph.movecomp(graph.dragging.comp, graph.abspos(graph.dragging, svg)));
// Update component position
// 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))));
}
// Snap top level component position to grid
if (graph.dragging.parentNode == svg) {
var gpos = graph.relpos(graph.dragging);
graph.move(graph.dragging, graph.mkpath().move(graph.gridsnap(gpos.xpos()), graph.gridsnap(gpos.ypos())));
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.sortcompos(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.sortcompos(graph.clonerefs(graph.gcollect(graph.removecomp(graph.dragging.comp, compos)))));
}
// Reset current selection
graph.selected = null;
cvalue.value = '';
cvalue.disabled = true;
cdelete.disabled = true;
// Trigger component select event
svg.oncompselect('');
}
}
@ -262,7 +215,14 @@ graph.mkgraph = function(pos, cvalue, cadd, cdelete) {
graph.dragging = null;
// Refresh the composite
graph.refresh(svg);
var nodes = graph.refresh(svg);
// Reselected the previously selected component
graph.selected = graph.findcompnode(scdl.name(graph.selected.comp), nodes);
graph.compselect(graph.selected, true, cvalue, cdelete);
// Trigger component select event
svg.oncompselect(graph.selected);
// Trigger composite change event
svg.oncomposchange(false);
@ -273,13 +233,79 @@ graph.mkgraph = function(pos, cvalue, cadd, cdelete) {
div.ontouchend = div.onmouseup;
// Handle a mouse click event.
div.onclick = function(e) {
if (graph.dragging == null && (e.target == div || e.target == svg)) {
div.onclick = svg.onclick = function(e) {
// Find selected component
var selected = draggable(e.target);
if (selected == null) {
if (graph.selected != null) {
// Reset current selection
graph.compselect(graph.selected, false, cvalue, cdelete);
graph.selected = null;
// Trigger component select event
svg.oncompselect(null);
}
// Dismiss the palette
if (ui.numpos(div.style.left) != (palcx * -1))
if (e.target == div || e.target == svg && ui.numpos(div.style.left) != (palcx * -1))
div.style.left = ui.pixpos(palcx * -1);
return true;
}
// Ignore multiple click events
if (selected == graph.selected)
return true;
if (selected.id.substring(0, 8) == 'palette:' && ui.numpos(div.style.left) != 0)
return true;
// Deselect previously selected component
graph.compselect(graph.selected, false, cvalue, cdelete);
// Clone component from the palette
if (selected.id.substring(0, 8) == 'palette:') {
var compos = scdl.composite(svg.compos);
graph.selected = graph.clonepalette(selected, compos, svg);
setElement(compos, graph.sortcompos(graph.addcomp(graph.selected.comp, compos)));
graph.selected.compos = svg.compos;
// Move into the editing area and hide the palette
var gpos = graph.relpos(graph.selected);
graph.move(graph.selected, graph.mkpath().move(gpos.xpos() + palcx, gpos.ypos()));
div.style.left = ui.pixpos(palcx * -1);
// Update component position
setElement(graph.selected.comp, graph.movecomp(graph.selected.comp, graph.abspos(graph.selected, svg)));
// Refresh the composite
var nodes = graph.refresh(svg);
// Reselect the previously selected component
graph.selected = graph.findcompnode(scdl.name(graph.selected.comp), nodes);
graph.compselect(graph.selected, true, cvalue, cdelete);
// Trigger component select event
svg.oncompselect(graph.selected);
// Trigger composite change event
svg.oncomposchange(true);
} else {
graph.selected = selected;
// Select the component
graph.compselect(graph.selected, true, cvalue, cdelete);
// Trigger component select event
svg.oncompselect(graph.selected);
}
if (e.preventDefault)
e.preventDefault();
else
e.returnValue = false;
return true;
}
@ -290,15 +316,28 @@ graph.mkgraph = function(pos, cvalue, cadd, cdelete) {
if (graph.dragging == null)
return true;
// Get the mouse position
var pos = typeof e.touches != "undefined" ? e.touches[0] : e;
if (pos.screenX == graph.dragX && pos.screenY == graph.dragY)
return true;
// Cut wire to component
if (graph.dragging.parentNode != svg) {
var compos = scdl.composite(svg.compos);
setElement(compos, graph.sortcompos(graph.cutwire(graph.dragging, compos, svg)));
// Bring component to the top
graph.bringtotop(graph.dragging, svg);
}
// 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)
if (newX >= palcx)
graph.dragX = pos.screenX;
else
newX = 0;
newX = palcx;
if (newY >= 0)
graph.dragY = pos.screenY;
else
@ -319,19 +358,25 @@ graph.mkgraph = function(pos, cvalue, cadd, cdelete) {
cvalue.onchange = function() {
if (graph.selected == null)
return false;
if (g.parentNode.style.visibility == 'hidden')
return false;
// Change component name and refactor references to it
function changename() {
var compos = scdl.composite(svg.compos);
cvalue.value = graph.ucid(cvalue.value, compos);
cvalue.value = graph.ucid(cvalue.value, compos, false);
graph.selected.id = cvalue.value;
setElement(compos, graph.sortcompos(graph.renamecomp(graph.selected.comp, compos, cvalue.value)));
// Trigger component select event
svg.oncompselect(graph.selected.id);
// Refresh the composite
graph.refresh(svg);
var nodes = graph.refresh(svg);
// Reselected the previously selected component
graph.selected = graph.findcompnode(scdl.name(graph.selected.comp), nodes);
graph.compselect(graph.selected, true, cvalue, cdelete);
// Trigger component select event
svg.oncompselect(graph.selected);
// Trigger composite change event
svg.oncomposchange(true);
@ -345,7 +390,14 @@ graph.mkgraph = function(pos, cvalue, cadd, cdelete) {
cvalue.disabled = !graph.hasproperty(graph.selected.comp);
// Refresh the composite
graph.refresh(svg);
var nodes = graph.refresh(svg);
// Reselected the previously selected component
graph.selected = graph.findcompnode(scdl.name(graph.selected.comp), nodes);
graph.compselect(graph.selected, true, cvalue, cdelete);
// Trigger component select event
svg.oncompselect(graph.selected);
// Trigger composite change event
svg.oncomposchange(true);
@ -359,23 +411,23 @@ graph.mkgraph = function(pos, cvalue, cadd, cdelete) {
cdelete.onclick = function() {
if (graph.selected == null)
return false;
if (graph.selected.id.substring(0, 8) != 'palette:' && !isNil(graph.selected.compos)) {
if (graph.selected.id.substring(0, 8) != 'palette:') {
// Remove selected component
var compos = scdl.composite(svg.compos);
if (isNil(graph.selected.compos))
setElement(compos, graph.sortcompos(graph.cutwire(graph.selected, compos, svg)));
setElement(compos, graph.sortcompos(graph.clonerefs(graph.gcollect(graph.removecomp(graph.selected.comp, compos)))));
// Reset current selection
graph.compselect(graph.selected, false, cvalue, cdelete);
graph.selected = null;
cvalue.value = '';
cvalue.disabled = true;
cdelete.disabled = true;
// Refresh the composite
graph.refresh(svg);
// Trigger component select event
svg.oncompselect('');
svg.oncompselect(null);
// Trigger composite change event
svg.oncomposchange(true);
@ -511,10 +563,41 @@ graph.proptitlewidth = function(comp) {
return width;
};
/**
* Draw a component shape selection.
*/
graph.compselect = function(g, s, cvalue, cdelete) {
if (isNil(g) || !s) {
if (!isNil(cvalue)) {
cvalue.value = '';
cvalue.disabled = true;
}
if (!isNil(cdelete))
cdelete.disabled = true;
if (isNil(g))
return true;
g.contour.setAttribute('stroke', graph.colors.gray);
g.contour.setAttribute('stroke-opacity', '0.20');
return true;
}
if (!isNil(cvalue)) {
cvalue.value = graph.hasproperty(g.comp)? graph.property(g.comp) : g.id;
cvalue.disabled = false;
}
if (!isNil(cdelete))
cdelete.disabled = false;
g.contour.setAttribute('stroke', graph.colors.link);
g.contour.setAttribute('stroke-opacity', '0.80');
g.parentNode.appendChild(g);
return true;
};
/**
* Return a node representing a component.
*/
graph.compnode = function(comp, cassoc, pos) {
graph.compnode = function(comp, cassoc, pos, parentg) {
// Make the component and property title elements
var title = graph.comptitle(comp);
@ -554,9 +637,31 @@ graph.compnode = function(comp, cassoc, pos) {
g.refpos = reverse(path.refpos);
g.svcpos = reverse(path.svcpos);
// Store the contour in the component shape
g.contour = contour;
// Handle onclick events
g.onclick = parentg.onclick;
return g;
};
/**
* Find the node representing a component.
*/
graph.findcompnode = function(name, nodes) {
if (isNil(nodes))
return null;
if (isNil(car(nodes).comp))
return graph.findcompnode(name, cdr(nodes));
if (name == scdl.name(car(nodes).comp))
return car(nodes);
var node = graph.findcompnode(name, nodeList(car(nodes).childNodes));
if (!isNil(node))
return node;
return graph.findcompnode(name, cdr(nodes));
}
/**
* Return a graphical group.
*/
@ -598,6 +703,10 @@ graph.mkbutton = function(t, pos) {
g.appendChild(shape);
g.appendChild(contour);
g.appendChild(title);
// Store the contour in the button shape
g.contour = contour;
return g;
};
@ -605,7 +714,7 @@ graph.mkbutton = function(t, pos) {
* Return the relative position of a node.
*/
graph.relpos = function(e) {
var pmatrix = e.parentNode.getCTM();
var pmatrix = e.parentNode != null? e.parentNode.getCTM() : null;
var matrix = e.getCTM();
var curX = pmatrix != null? (Number(matrix.e) - Number(pmatrix.e)): Number(matrix.e);
var curY = pmatrix != null? (Number(matrix.f) - Number(pmatrix.f)): Number(matrix.f);
@ -1048,12 +1157,20 @@ graph.buttonpath = function(t) {
/**
* Render a SCDL composite into a list of component nodes.
*/
graph.composite = function(compos, pos) {
graph.composite = function(compos, pos, aspalette, g) {
var name = scdl.name(scdl.composite(compos));
var comps = scdl.components(compos);
var cassoc = scdl.nameToElementAssoc(comps);
var proms = scdl.promotions(compos);
// Unmemoize any memoized info about components and their references.
map(function(c) {
unmemo(c);
map(function(r) {
unmemo(r);
}, scdl.references(c));
}, comps);
/**
* Render a component.
*/
@ -1124,7 +1241,7 @@ graph.composite = function(compos, pos) {
}
// Compute the component shape
var gcomp = graph.compnode(comp, cassoc, pos);
var gcomp = graph.compnode(comp, cassoc, pos, g);
// Render the components wired to the component references
var rrefs = graph.rrefs(comp);
@ -1201,10 +1318,17 @@ graph.composite = function(compos, pos) {
// Render the promoted service components
var rproms = renderproms(proms, cassoc, pos.clone().rmove(tabsz * 4, tabsz * 4));
if (name == 'palette') {
if (aspalette) {
// Prefix ids of palette component elements with 'palette:' and
// move them to the palette area
return map(function(r) {
r.id = 'palette:' + r.id;
var gpos = graph.relpos(r);
graph.move(r, graph.mkpath().move(gpos.xpos() - palcx, gpos.ypos()));
return r;
}, rproms);
// 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
@ -1215,11 +1339,14 @@ graph.composite = function(compos, pos) {
/**
* Return a component unique id.
*/
graph.ucid = function(prefix, compos) {
graph.ucid = function(prefix, compos, clone) {
// Build an assoc list keyed by component name
var comps = map(function(c) { return mklist(scdl.name(c), c); }, namedElementChildren("'component", compos));
if (!clone && isNil(assoc(prefix, comps)))
return prefix;
/**
* Find a free component id.
*/
@ -1229,26 +1356,23 @@ graph.ucid = function(prefix, compos) {
return ucid(p, id + 1);
}
if (isNil(assoc(prefix, comps)))
return prefix;
return ucid(prefix == ''? 'comp' : prefix, 2);
return ucid(prefix == ''? 'comp' : prefix, 1);
};
/**
* Clone a palette component node.
*/
graph.clonepalette = function(e, compos) {
graph.clonepalette = function(e, compos, g) {
// Clone the SCDL component and give it a unique name
var comp = append(mklist(element, "'component", mklist(attribute, "'name", graph.ucid(scdl.name(e.comp), compos))),
// Clone the SCDL component and give it a unique name
var wcomp = append(mklist(element, "'component", mklist(attribute, "'name", graph.ucid(scdl.name(e.comp), compos, true))),
filter(function(c) { return !(isAttribute(c) && attributeName(c) == "'name")}, elementChildren(e.comp)));
var x = '<composite xmlns:t="http://tuscany.apache.org/xmlns/sca/1.1">' + writeXML(mklist(comp), false) + '</composite>';
var compos = readXML(mklist(x));
comp = car(scdl.components(compos));
var x = '<composite>' + writeXML(mklist(wcomp), false) + '</composite>';
var rcompos = readXML(mklist(x));
var comp = car(scdl.components(rcompos));
// Make a component node
var gcomp = graph.compnode(comp, mklist(), graph.mkpath());
var gcomp = graph.compnode(comp, mklist(), graph.mkpath(), g);
graph.move(gcomp, graph.relpos(e));
e.parentNode.appendChild(gcomp);
@ -1261,11 +1385,18 @@ graph.clonepalette = function(e, compos) {
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)));
filter(function(e) { return !(isAttribute(e) && (attributeName(e) == "'x" || attributeName(e) == "'y")); }, elementChildren(comp)));
return append(mklist(element, "'component", mklist(attribute, "'x", '' + (pos.xpos() - palcx)), mklist(attribute, "'y", '' + pos.ypos())),
filter(function(e) { return !(isAttribute(e) && (attributeName(e) == "'x" || attributeName(e) == "'y")); }, elementChildren(comp)));
};
/**
* Align a pos along a 10pixel grid.
*/
graph.gridsnap = function(x) {
return Math.round(x / 10) * 10;
}
/**
* Sort elements of a composite.
*/
@ -1356,7 +1487,7 @@ graph.clonerefs = function(compos) {
// reference at the end of the list
var cc = append(
filter(function(e) { return !(elementName(e) == "'reference" && scdl.target(e) == null); }, elementChildren(c)),
mklist(mklist(element, "'reference", mklist(attribute, "'name", scdl.name(car(refs))), mklist(attribute, "'t:clonable", "true"))));
mklist(mklist(element, "'reference", mklist(attribute, "'name", scdl.name(car(refs))), mklist(attribute, "'clonable", "true"))));
return append(mklist(element, "'component"), cc);
}, elementChildren(compos)));
@ -1535,10 +1666,11 @@ graph.hide = function(g) {
*/
graph.refresh = function(g) {
// Remove nodes and redisplay the composite associated with the graph
// Remove existing nodes from the graph
map(function(n) { if (!isNil(n.comp) && n.id.substr(0, 8) != 'palette:') { g.removeChild(n); } return n; }, nodeList(g.childNodes));
graph.display(graph.composite(g.compos, graph.mkpath().move(palcx,0)), g);
return g;
// Redisplay the composite associated with the graph
return graph.display(graph.composite(g.compos, graph.mkpath().move(palcx,0), false, g), g);
};
/**

View file

@ -37,32 +37,45 @@
<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>
<td><h2><span id="h1"></span><span id="appNameHeader"></span></h2></td>
<td style="vertical-align: middle; text-align: right; padding-right: 2px;"><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;">&gt;</span>
<th class="thr thl" style="padding-left: 2px; padding-right: 2px; width: 100%">
<input id="compValue" type="text" value="" title="Component value" autocapitalize="off" placeholder="Value" style="position: relative; width: 100%;"/>
</th>
<th class="thl thr" style="text-align: right; padding-right: 2px;">
<span id="deleteCompButton" 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="addCompButton" 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="playCompButton" 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;">&gt;</span>
</th>
</tr>
</table>
<div id="dataDiv" style="position:absolute; top: 95px; left: 0px; right: 0px; height: 5000px; visibility: hidden">
<div id="playdiv" style="position:absolute; top: 95px; left: 0px; right: 0px; height: 5000px; visibility: hidden">
</div>
</div>
<script type="text/javascript">
// Get the app name
var appname = ui.queryParams()['app'];
if (isNil(appname))
window.open('/', '_self');
var ispalette = false;
if (isNil(appname)) {
appname = ui.queryParams()['palette'];
if (isNil(appname))
window.open('/', '_self');
// Edit a palette instead of a regular app
ispalette = true;
}
/**
* Return the link to an app.
@ -79,41 +92,65 @@ function applink(appname) {
// 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>';
//$('h1').innerHTML = hometitle(window.location.hostname);
$('appNameHeader').innerHTML = '<a href=\"' + applink(appname) + '\" target=\"' + '_blank' + '\">' + appname + '.' + window.location.hostname + '</a>';
// Load the menu bar
displaymenu();
/**
* Component value field, add, delete and play buttons.
*/
var cvalue = $('compValue');
var cadd = $('addCompButton');
var cdelete = $('deleteCompButton');
var cplay = $('playCompButton');
/**
* Adjust field size.
*/
function resizeFields() {
cvalue.style.width = '0px';
cvalue.style.width = ui.pixpos(cvalue.parentNode.clientWidth - 18);
return true;
}
resizeFields();
window.onresize = resizeFields;
// 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");
var composites = sca.reference(editWidget, ispalette? "palettes" : "composites");
// Setup remote log
//rconsole = sca.defun(sca.reference(editWidget, "log"), "log");
/**
* The current app composite, corresponding saved XML content and component name.
* Track the current app composite and corresponding saved XML content.
*/
var savedcomposxml = '';
var composite;
var compname = '';
/**
* Track the composition graph and whether it's visible or not.
* Track the composition graph, whether it's visible or not and the selected component.
*/
var g;
var gdiv;
var bg;
var gvisible = true;
var gcomp = null;
var pdiv = $('playdiv');
// Track the palettes
/**
* Track the palettes.
*/
var gpalettes = new Array();
var spalette = 'control';
var bpalette = null;
/**
* Return the composite in an ATOM entry.
@ -139,11 +176,13 @@ function getapp(name, g) {
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"' +
var x = '<composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912" ' +
'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);
// Display the composite
graph.edit(name, composite, graph.composite(composite, graph.mkpath().move(palcx,0), false, g), oncomposchange, oncompselect, g);
// Track the saved composite XML
savedcomposxml = car(writeXML(composite, false));
@ -161,7 +200,7 @@ function displaypalette(name, g, palette, gpalettes) {
// Get the palette from the server
var doc = palettes.get(name);
gpalettes[name] = graph.composite(atomcomposite(doc), graph.mkpath().move(80,0));
gpalettes[name] = graph.composite(atomcomposite(doc), graph.mkpath().move(2580,0), true, g);
}
graph.display(gpalettes[name], g);
return true;
@ -177,7 +216,10 @@ function installpalette(name, pos, g, bg, palette, gpalettes) {
b.onclick = function(e) {
// Swap the selected palette
graph.compselect(bpalette, false);
displaypalette(spalette, bg, palette, gpalettes);
bpalette = b;
graph.compselect(b, true, null, null);
spalette = name;
return displaypalette(spalette, g, palette, gpalettes);
};
@ -190,7 +232,10 @@ function installpalette(name, pos, g, bg, palette, gpalettes) {
}
// Display the selected palette
return displaypalette(name, g, palette, gpalettes);
graph.compselect(b, true, null, null);
displaypalette(name, g, palette, gpalettes);
return b;
}
/**
@ -202,8 +247,9 @@ function save(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';
composites.put(appname, entry, function(r) {
$('saveStatus').innerHTML = 'Saved';
});
return true;
}
@ -220,15 +266,14 @@ function oncomposchange(prop) {
if (prop)
return save(newxml);
// Autosave other changes after 3 seconds
// Autosave other changes after 1 second
$('saveStatus').innerHTML = 'Modified';
setTimeout(function() {
var savexml = car(writeXML(composite, false));
if (savedcomposxml == savexml) {
if (savedcomposxml == newxml) {
$('saveStatus').innerHTML = 'Saved';
return false;
}
return save(savexml);
return save(newxml);
}, 1000);
return true;
}
@ -236,7 +281,7 @@ function oncomposchange(prop) {
/**
* Return the link to a component value.
*/
function compvaluelink(appname, cname) {
function compdatalink(appname, cname) {
if (cname == '' || isNil(cname))
return '';
var protocol = window.location.protocol;
@ -249,9 +294,9 @@ function compvaluelink(appname, cname) {
}
/**
* Return the link to a component raw data.
* Return the link to a component.
*/
function compdebuglink(appname, cname) {
function complink(appname, cname) {
if (cname == '' || isNil(cname))
return '';
var protocol = window.location.protocol;
@ -259,78 +304,81 @@ function compdebuglink(appname, cname) {
var port = ':' + window.location.port;
if (port == ':80' || port == ':443' || port == ':')
port = '';
var link = protocol + '//' + appname + '.' + host + port + '/components/' + cname;
var link = protocol + '//' + appname + '.' + host + port + '/c/' + cname;
return link;
}
/**
* Handle a component select event.
*/
function oncompselect(cname) {
if (cname == compname)
function oncompselect(gsel) {
if (gsel == gcomp)
return true;
compname = cname;
var link = compvaluelink(appname, cname);
gcomp = gsel;
var cname = isNil(gsel)? '' : gsel.id;
var link = compdatalink(appname, cname);
function updateButton(b, v) {
b.style.color = v? '#000000' : '#808080';
}
updateButton($('deleteComponentButton'), link != '');
updateButton($('playComponentButton'), link != '');
updateButton(cdelete, link != '');
updateButton(cplay, link != '');
return true;
}
/**
* Show the result data of a component.
*/
function showdata(cname) {
function showdata(gcomp) {
if (!gvisible)
return true;
gvisible = false;
$('playComponentButton').innerHTML = '&lt;';
if (isNil(gcomp))
return true;
cvalue.value = complink(appname, gcomp.id);
cplay.innerHTML = '&lt;';
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>';
gvisible = false;
pdiv.style.visibility = 'visible';
pdiv.innerHTML = '<iframe id="dataFrame" style="position: relative; height: 5000px; width: 100%; border: 0px;" scrolling="no" frameborder="0" src="' +
compdatalink(appname, gcomp.id) + '"></iframe>';
return true;
}
/**
* Show the composition graph.
*/
function showgraph() {
function showgraph(gcomp) {
if (gvisible)
return true;
gvisible = true;
$('playComponentButton').innerHTML = '&gt;';
var rdiv = $('dataDiv');
rdiv.style.visibility = 'hidden';
rdiv.innerHTML = '';
cplay.innerHTML = '&gt;';
pdiv.style.visibility = 'hidden';
pdiv.innerHTML = '';
gdiv.style.visibility = 'visible'
gvisible = true;
graph.compselect(gcomp, true, cvalue, cdelete);
return true;
}
/**
* Play the current component.
* Handle play component button event.
*/
$('playComponentButton').onclick = function() {
if (compname == '')
cplay.onclick = function() {
if (gcomp == null)
return false;
if (!gvisible)
return showgraph();
return showdata(compname);
return showgraph(gcomp);
return showdata(gcomp);
}
// Create editor graph area
g = graph.mkgraph(graph.mkpath().move(-2500,95), $('compValue'), $('addComponentButton'), $('deleteComponentButton'));
g = graph.mkgraph(graph.mkpath().move(-2500,95), cvalue, cadd, cdelete);
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);
var pos = graph.mkpath().move(0, 0);
bpalette = 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);

View file

@ -37,20 +37,18 @@
<table style="width: 100%;">
<tr><td><h1><span id="h1"></span></h1></td></tr>
</table>
<br/>
<div style="margin-left: auto; margin-right: auto; text-align: center;">
<h1><span id="maintitle"><span></h1>
<br/><br/><br/><br/>
<div id="maintitle" style="font-size: 150%;"></div>
<div id="maindiagram"></div>
<br/><br/><br/><br/>
<div id="maindiagram"><div id="diagram" style="width: 320px; height: 280px; background: url(home.png); padding: 0px; margin: 0px auto;"></div></div>
<br/>
<input type="button" class="greenbutton" style="font-size: 150%; font-weight: bold; font-style: italic; padding: 10px;" id="getstarted" title="Get Started" value="Get Started"/>
<br/><br/><br/>
<div>Safari, Chrome, Firefox only for now.</div>
<br/><br/>
<div>Requires Safari 5+, Chrome 11+, Firefox 4+, IE 9+</div>
</div>
@ -65,13 +63,23 @@ $('h1').innerHTML = hometitle(window.location.hostname);
displaymenu();
$('maintitle').innerHTML = isNil(config.maintitle)? 'Simple App Builder' : config.maintitle;
$('maindiagram').innerHTML = isNil(config.maindiagram)? '&lt;&lt insert diagram here &gt;&gt;' : config.maindiagram;
$('getstarted').onclick = function() {
return window.open('/store/', '_self');
};
// Display the main diagram
var diagram = $('diagram');
var bgpos = 0;
setInterval(function() {
bgpos = bgpos -280;
if (bgpos == -2800)
bgpos = 0;
diagram.style.backgroundPosition = '0px ' + ui.pixpos(bgpos);
}, 2000);
// Show the page
ui.showbody();
</script>
</body>

View file

@ -27,13 +27,15 @@
<link rel="stylesheet" type="text/css" href="/ui-min.css"/>
<script type="text/javascript" src="/all-min.js"></script>
</head>
<body onorientationchange="ui.reload();">
<body class="delayed" onorientationchange="ui.reload();">
<div id="bodydiv" class="devicewidth">
<h1>Sign in</h1>
<form name="formSignin" onsubmit="submitSignin();" method="POST" action="/login/dologin/">
<table border="0">
<tr><td><b>Username:</b></td></tr>
<tr><td><input type="text" id="httpd_username" name="httpd_username" value="" size="15" placeholder="Enter your user name" style="width: 300px;"/></td></tr>
<tr><td><input type="text" id="httpd_username" name="httpd_username" value="" size="15" autocapitalize="off" placeholder="Enter your user name" style="width: 300px;"/></td></tr>
<tr><td><b>Password:</b></td></tr>
<tr><td><input type="password" name="httpd_password" value="" size="15" placeholder="Enter your password" style="width: 300px;"/></td></tr>
<tr><td><input type="submit" value="Sign in" class="greenbutton" style="font-weight: bold;"/></td><td></td></tr>
@ -41,7 +43,13 @@
<input type="hidden" name="httpd_location" value="/"/>
</form>
</div>
<script type="text/javascript">
// Show the page
ui.showbody();
function queryParams() {
qp = new Array();
qs = window.location.search.substring(1).split('&');

View file

@ -27,14 +27,22 @@
<link rel="stylesheet" type="text/css" href="/ui-min.css"/>
<script type="text/javascript" src="/all-min.js"></script>
</head>
<body onorientationchange="ui.reload();">
<body class="delayed" onorientationchange="ui.reload();">
<div id="bodydiv" class="devicewidth">
<h1>Sign out</h1>
<form name="signout" onsubmit="submitSignout();" action="/" method="GET">
<input type="submit" id="signOut" value="Sign out" class="greenbutton" style="font-weight: bold"/>
</form>
</div>
<script type="text/javascript">
// Show the page
ui.showbody();
function submitSignout() {
var reset = 'TuscanyOpenAuth=;expires=' + new Date(1970,01,01).toGMTString() + ';domain=.' + domainname(window.location.hostname) + ';path=/;secure=TRUE';
document.cookie = reset;

View file

@ -37,26 +37,28 @@
<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>
<td><h2><span id="h1"></span><span id="appNameHeader"></span></h2></td>
<td style="vertical-align: middle; text-align: right; padding-right: 2px;"><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="widgetName" type="text" value="" title="Widget name" placeholder="Name" style="position: relative; width: 65px;"/>
<input id="widgetText" type="text" value="" title="Widget text" placeholder="Text" style="position: relative; width: 120px;"/>
<th class="thr thl" style="padding-left: 2px; padding-right: 2px; width: 100%;">
<input id="widgetValue" type="text" value="" title="Widget value" autocapitalize="off" placeholder="Value" style="position: relative; width: 100%;"/>
</th>
<th class="thl thr" style="text-align: right; padding-right: 2px;">
<span id="deleteWidgetButton" title="Delete a Widget" 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="addWidgetButton" title="Add a Widget" 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="playWidgetButton" title="View" 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;">&gt;</span>
-->
<span id="playPageButton" title="View page" class="bluebutton" 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;">&gt;</span>
</th>
</tr>
</table>
<div id="page" style="position: absolute; top: 95px; left: -2500px; right: 0px; height: 5000px;">
<div id="editdiv" style="position: absolute; top: 95px; left: -2500px; right: 0px; height: 5000px;">
<div style="position: absolute; left: 2500px; top: 0px; right: 0px; height: 5000px; border:1px; border-style: solid; border-color: #a2bae7; background: url(/public/grid72.png);"></div>
<div class="guide" style="position: absolute; left: 2500px; top: 0px; width: 320px; height: 460px;"></div>
@ -85,6 +87,8 @@
</div>
<div id="playdiv" style="visibility: hidden; position: absolute; top: 95px; left: 0px; right: 0px; height: 5000px;"></div>
<div id="buffer" style="visibility: hidden; position: absolute; top: 0px; left: 0px; width: 0px; height: 0px"></div>
</div>
@ -111,12 +115,35 @@ function applink(appname) {
// Set page titles
document.title = windowtitle(window.location.hostname) + ' - Page - ' + appname;
$('h1').innerHTML = hometitle(window.location.hostname);
$('appNameHeader').innerHTML = ' - <a href=\"' + applink(appname) + '\" target=\"' + '_blank' + '\">' + appname + '</a>';
//$('h1').innerHTML = hometitle(window.location.hostname);
$('appNameHeader').innerHTML = '<a href=\"' + applink(appname) + '\" target=\"' + '_blank' + '\">' + appname + '.' + window.location.hostname + '</a>';
// Load the menu bar
displaymenu();
/**
* Page editor area, widget value field, add, delete and play page buttons.
*/
var ediv = $('editdiv');
var evisible = true;
var pdiv = $('playdiv');
var wvalue = $('widgetValue');
var wadd = $('addWidgetButton');
var wdelete = $('deleteWidgetButton');
var pplay = $('playPageButton');
/**
* Adjust fields sizes.
*/
function resizeFields() {
wvalue.style.width = '0px';
wvalue.style.width = ui.pixpos(wvalue.parentNode.clientWidth - 18);
return true;
}
resizeFields();
window.onresize = resizeFields;
// Show the page
ui.showbody();
@ -138,15 +165,19 @@ function atompage(doc) {
}
/**
* Track the current widget and page saved XHTML content.
* Track the current page saved XHTML content.
*/
var widgetname = '';
var savedpagexhtml = '';
/**
* Track the current widget.
*/
var widget = null;
/**
* Get and display an app page.
*/
function getpage(name, edit) {
function getpage(name, ediv) {
if (isNil(name))
return false;
return pages.get(name, function(doc) {
@ -157,19 +188,19 @@ function getpage(name, edit) {
// Create a default empty page if necessary
if (isNil(el))
buffer.innerHTML = '<DIV id="page">\n</DIV>\n';
buffer.innerHTML = '<div id="page"></div>';
else
buffer.innerHTML = writeStrings(writeXML(atompage(doc), false));
// Append page nodes to editor
map(function(e) {
edit.appendChild(e);
ediv.appendChild(e);
if (!isNil(e.style))
e.style.left = ui.pixpos(ui.numpos(e.style.left) + 2500);
return page.cover(e);
}, nodeList(buffer.childNodes[0].childNodes));
savedpagexhtml = pagexhtml();
savedpagexhtml = pagexhtml(ediv);
return true;
});
}
@ -177,22 +208,28 @@ function getpage(name, edit) {
/**
* Handle add widget button click event.
*/
$('addWidgetButton').onclick = function(e) {
wadd.onclick = function(e) {
// Show the widget palette
$('page').style.left = ui.pixpos(0);
ediv.style.left = ui.pixpos(0);
};
/**
* Return the current page XHTML content.
*/
function pagexhtml() {
function pagexhtml(ediv) {
// Copy page DOM to hidden buffer
var edit = $('page');
var buffer = $('buffer');
buffer.innerHTML = '<DIV id="page">\n</DIV>\n'
buffer.innerHTML = '<div id="page"></div>'
var div = buffer.childNodes[0];
div.innerHTML = edit.innerHTML;
// Capture the nodes inside the page div
div.innerHTML = ediv.innerHTML;
var nodes = nodeList(div.childNodes);
map(function(e) {
div.removeChild(e);
return e;
}, nodes);
// Filter out palette and editor artifacts, which are not
// part of the page, as well as nodes positioned out the
@ -204,7 +241,7 @@ function pagexhtml() {
if (x < 0 || ui.numpos(e.style.top) < 0)
return false;
return true;
}, nodeList(div.childNodes));
}, nodes);
// Reposition nodes
map(function(e) {
@ -226,8 +263,7 @@ function pagexhtml() {
return 0;
});
// Append them back to the div in order
div.innerHTML = '';
// Append the sorted nodes back to the div in order
map(function(e) {
div.appendChild(e);
return e;
@ -242,20 +278,20 @@ function pagexhtml() {
/**
* Save the current page.
*/
function save() {
function save(newxml) {
$('saveStatus').innerHTML = 'Saving';
// Get the current page XHTML content
savedpagexhtml = pagexhtml();
savedpagexhtml = newxml;
// Update the page ATOM entry
var entry = '<entry xmlns="http://www.w3.org/2005/Atom">' +
'<title type="text">' + appname + '</title><id>' + appname + '</id><content type="application/xml">' +
savedpagexhtml + '</content></entry>';
newxml + '</content></entry>';
pages.put(appname, entry);
if (savedpagexhtml == pagexhtml())
pages.put(appname, entry, function(r) {
$('saveStatus').innerHTML = 'Saved';
});
return true;
};
@ -263,19 +299,22 @@ function save() {
* Handle a page change event
*/
function onpagechange(prop) {
if (savedpagexhtml == pagexhtml())
var newxml = pagexhtml(ediv);
if (savedpagexhtml == newxml)
return false;
$('saveStatus').innerHTML = 'Modified';
// Save property changes right away
if (prop)
return save();
return save(newxml);
// Autosave other changes after 3 seconds
// Autosave other changes after 1 second
setTimeout(function() {
if (savedpagexhtml == pagexhtml())
if (savedpagexhtml == newxml) {
$('saveStatus').innerHTML = 'Saved';
return false;
return save();
}
return save(newxml);
}, 1000);
return true;
}
@ -298,40 +337,68 @@ function compvaluelink(appname, cname) {
/**
* Handle a widget select event.
*/
function onwidgetselect(wname) {
if (wname == widgetname)
function onwidgetselect(w) {
if (w == widget)
return true;
widgetname = wname;
var link = compvaluelink(appname, wname);
widget = w;
var link = compvaluelink(appname, isNil(w)? '' : w.id);
function updateButton(b, v) {
b.style.color = v? '#000000' : '#808080';
}
updateButton($('deleteWidgetButton'), link != '');
//updateButton($('playWidgetButton'), link != '');
updateButton(wdelete, link != '');
return true;
}
/**
* Play the component associated with the current widget.
* Play page in a frame.
*/
/*
$('playWidgetButton').onclick = function() {
var link = compvaluelink(appname, widgetname);
if (link == '')
return;
return window.open(link, '_' + appname + '_' + widgetname);
function playpage() {
if (!evisible)
return true;
page.widgetselect(widget, false, wvalue, wdelete);
page.selected = null;
wvalue.value = applink(appname);
pplay.innerHTML = '&lt;';
ediv.style.visibility = 'hidden'
evisible = false;
pdiv.style.visibility = 'visible';
pdiv.innerHTML = '<iframe id="appFrame" style="position: relative; height: 5000px; width: 100%; border: 0px;" scrolling="no" frameborder="0" src="' +
applink(appname) + '"></iframe>';
return true;
}
/**
* Show the page editor.
*/
function showedit() {
if (evisible)
return true;
pplay.innerHTML = '&gt;';
pdiv.style.visibility = 'hidden';
pdiv.innerHTML = '';
ediv.style.visibility = 'visible'
evisible = true;
page.widgetselect(widget, true, wvalue, wdelete);
page.selected = widget;
return true;
}
/**
* Handle play page button event.
*/
pplay.onclick = function() {
if (!evisible)
return showedit();
return playpage();
}
*/
// Initialize the page editor
var edit = $('page');
page.edit(edit, $('widgetName'), $('widgetText'), $('addWidgetButton'), $('deleteWidgetButton'), onpagechange, onwidgetselect);
page.edit(ediv, wvalue, wadd, wdelete, onpagechange, onwidgetselect);
// Get and display the current app page
getpage(appname, edit);
getpage(appname, ediv);
</script>
</body>

View file

@ -26,18 +26,16 @@ var page = {};
* Default positions and sizes.
*/
var palcx = 2500;
var trashcx = 2480;
/**
* Init a page editor. Works with all browsers except IE.
*/
page.edit = function(elem, wname, wtext, wadd, wdelete, onchange, onselect) {
page.edit = function(elem, wvalue, wadd, wdelete, onchange, onselect) {
// Track element dragging and selection
page.dragging = null;
page.selected = null;
wname.disabled = true;
wtext.disabled = true;
wvalue.disabled = true;
wdelete.disabled = true;
// Trigger widget select and page change events
@ -49,59 +47,22 @@ page.edit = function(elem, wname, wtext, wadd, wdelete, onchange, onselect) {
*/
elem.onmousedown = function(e) {
// On mouse controlled devices, engage the click component selection
// logic right away
if (typeof e.touches == 'undefined')
elem.onclick(e);
// Find a draggable element
page.dragging = page.draggable(e.target, elem);
page.selected = page.dragging;
if (page.dragging == null) {
// Reset current selection
wname.value = '';
wname.disabled = true;
wtext.value = '';
wtext.disabled = true;
wdelete.disabled = true;
// Trigger widget select event
page.onwidgetselect('');
var dragging = page.draggable(e.target, elem);
if (dragging == null || dragging != page.selected)
return true;
}
// Clone element dragged from palette
if (page.dragging.id.substring(0, 8) == 'palette:') {
page.dragging = page.clone(page.dragging);
page.selected = page.dragging;
// Move into the editing area and hide the palette
page.selected.style.left = ui.pixpos(ui.numpos(page.selected.style.left) + palcx);
elem.style.left = ui.pixpos(palcx * -1);
// Bring it to the top
page.bringtotop(page.dragging);
// Trigger page change event
page.onpagechange(true);
} else {
// Bring it to the top
page.bringtotop(page.dragging);
}
page.dragging = dragging;
// Remember mouse position
var pos = typeof e.touches != "undefined" ? e.touches[0] : e;
page.dragX = pos.screenX;
page.dragY = pos.screenY;
// Update the widget name and text fields
wname.value = page.selected.id;
wname.disabled = false;
wtext.value = page.text(page.selected);
wtext.disabled = !page.hastext(page.selected);
wdelete.disabled = false;
// Trigger widget select event
page.onwidgetselect(page.selected.id);
if (e.preventDefault)
e.preventDefault();
else
@ -130,29 +91,6 @@ page.edit = function(elem, wname, wtext, wadd, wdelete, onchange, onselect) {
// Fixup widget style
page.fixupwidget(page.dragging);
// Discard element dragged out of page area
if (ui.numpos(page.dragging.style.left) < palcx && page.dragging.id.substring(0, 8) != 'palette:') {
if (ui.numpos(page.dragging.style.left) >= trashcx) {
// Unless it's close enough to page area, then move it there
page.dragging.style.left = ui.pixpos(palcx);
page.dragging.cover.style.left = ui.pixpos(palcx);
} else {
page.dragging.parentNode.removeChild(page.dragging);
// Reset current selection
page.selected = null;
wname.value = '';
wname.disabled = true;
wtext.value = '';
wtext.disabled = true;
wdelete.disabled = true;
// Trigger widget select event
page.onwidgetselect('');
}
}
// Forget dragged element
page.dragging = null;
@ -171,16 +109,20 @@ page.edit = function(elem, wname, wtext, wadd, wdelete, onchange, onselect) {
if (page.dragging == null)
return true;
// Get the mouse position
var pos = typeof e.touches != "undefined" ? e.touches[0] : e;
if (pos.screenX == page.dragX && pos.screenY == page.dragY)
return true;
// Compute position of dragged element
var curX = ui.numpos(page.dragging.style.left);
var curY = ui.numpos(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);
if (newX >= 0)
if (newX >= palcx)
page.dragX = pos.screenX;
else
newX = 0;
newX = palcx;
if (newY >= 0)
page.dragY = pos.screenY;
else
@ -201,32 +143,70 @@ page.edit = function(elem, wname, wtext, wadd, wdelete, onchange, onselect) {
* Handle a mouse click event.
*/
elem.onclick = function(e) {
if (page.dragging == null) {
// Find selected element
var selected = page.draggable(e.target, elem);
if (selected == null) {
if (page.selected != null) {
// Reset current selection
page.widgetselect(page.selected, false, wvalue, wdelete);
page.selected = null;
// Trigger widget select event
page.onwidgetselect(null);
}
// Dismiss the palette
if (ui.numpos(elem.style.left) != (palcx * -1))
elem.style.left = ui.pixpos(palcx * -1);
return true;
}
// Deselect the previously selected element
page.widgetselect(page.selected, false, wvalue, wdelete);
// Clone element dragged from palette
if (selected.id.substring(0, 8) == 'palette:') {
page.selected = page.clone(selected);
// Move into the editing area and hide the palette
page.selected.style.left = ui.pixpos(ui.numpos(page.selected.style.left) + palcx);
page.selected.cover.style.left = ui.pixpos(ui.numpos(page.selected.cover.style.left) + palcx);
elem.style.left = ui.pixpos(palcx * -1);
// Bring it to the top
page.bringtotop(page.selected);
// Trigger page change event
page.onpagechange(true);
} else {
// Bring selected element to the top
page.selected = selected;
page.bringtotop(page.selected);
}
// Select the element
page.widgetselect(page.selected, true, wvalue, wdelete);
// Trigger widget select event
page.onwidgetselect(page.selected);
return true;
};
/**
* Handle field on change events.
*/
wname.onchange = wname.onblur = function() {
wvalue.onchange = wvalue.onblur = function() {
if (page.selected == null)
return false;
page.selected.id = wname.value;
// Trigger page change event
page.onpagechange(true);
return false;
};
wtext.onchange = wtext.onblur = function() {
if (page.selected == null)
return false;
page.settext(page.selected, wtext.value);
page.settext(page.selected, wvalue.value);
page.selected.cover.style.width = ui.pixpos(page.selected.clientWidth + 4);
page.selected.cover.style.height = ui.pixpos(page.selected.clientHeight + 4);
// Trigger page change event
page.onpagechange(true);
@ -246,19 +226,16 @@ page.edit = function(elem, wname, wtext, wadd, wdelete, onchange, onselect) {
if (page.selected == null)
return false;
// Reset current selection
page.widgetselect(page.selected, false, wvalue, wdelete);
// Remove selected widget
page.selected.parentNode.removeChild(page.selected);
// Reset current selection
page.selected.cover.parentNode.removeChild(page.selected.cover);
page.selected = null;
wname.value = '';
wname.disabled = true;
wtext.value = '';
wtext.disabled = true;
wdelete.disabled = true;
// Trigger widget select event
page.onwidgetselect('');
page.onwidgetselect(null);
// Trigger page change event
page.onpagechange(true);
@ -276,6 +253,11 @@ page.edit = function(elem, wname, wtext, wadd, wdelete, onchange, onselect) {
* Return the text of a widget.
*/
page.text = function(e) {
var formula = e.id;
if (formula.substring(0, 5) != 'page:') {
return '=' + formula;
}
if (e.className == 'h1' || e.className == 'h2' || e.className == 'text' || e.className == 'section')
return car(childElements(e)).innerHTML;
if (e.className == 'button' || e.className == 'checkbox')
@ -331,6 +313,9 @@ page.hastext = function(e) {
* Set the text of a widget.
*/
page.settext = function(e, t) {
var formula = t.length > 1 && t.substring(0, 1) == '=';
e.id = formula? t.substring(1) : 'page:' + e.className;
if (e.className == 'h1' || e.className == 'h2' || e.className == 'text' || e.className == 'section') {
car(childElements(e)).innerHTML = t;
return t;
@ -351,10 +336,12 @@ page.settext = function(e, t) {
return t;
}
if (e.className == 'list') {
e.innerHTML = '<table class="datatable" style="width: 100%;;"><tr><td class="datatd">' + t + '</td></tr><tr><td class="datatd">...</td></tr></table>';
return '';
}
if (e.className == 'table') {
return '';
e.innerHTML = '<table class="datatable" style="width: 100%;"><tr><td class="datatdl">' + t + '</td><td class="datatdr">...</td></tr><tr><td class="datatdl">...</td><td class="datatdr">...</td></tr></table>';
return t;
}
if (e.className == 'link') {
var l = t.split(',');
@ -364,11 +351,11 @@ page.settext = function(e, t) {
return t;
}
if (e.className == 'img') {
car(childElements(e)).src = t;
car(childElements(e)).src = formula? '/public/img.png' : t;
return t;
}
if (e.className == 'iframe') {
car(childElements(e)).href = t;
car(childElements(e)).href = formula? '/public/iframe.html' : t;
return t;
}
return '';
@ -388,10 +375,12 @@ page.fixupwidget = function(e) {
return e;
}
if (e.className == 'list') {
e.style.width = '100%';
car(childElements(e)).style.width = '100%';
return e;
}
if (e.className == 'table') {
e.style.width = '100%';
car(childElements(e)).style.width = '100%';
return e;
}
@ -426,6 +415,33 @@ page.bringtotop = function(n) {
n.cover.parentNode.appendChild(n.cover);
}
/**
* Draw widget selection.
*/
page.widgetselect = function(n, s, wvalue, wdelete) {
if (isNil(n) || !s) {
// Clear the widget value field
wvalue.value = '';
wvalue.disabled = true;
wdelete.disabled = true;
// Clear the widget outline
if (!isNil(n))
n.cover.style.borderWidth = '0px';
}
if (isNil(n))
return true;
// Update the widget value field
wvalue.value = page.text(n);
wvalue.disabled = false;
wdelete.disabled = false;
// Outline the widget
n.cover.style.borderWidth = s? '2px' : '0px';
return true;
};
/**
* Cover a page element with a <span> element to prevent
* any input events to reach it.
@ -433,13 +449,18 @@ page.bringtotop = function(n) {
page.cover = function(e) {
if (e.id == '' || isNil(e.style))
return e;
var cover = document.createElement('span');
var cover = document.createElement('div');
cover.style.position = 'absolute';
cover.style.left = ui.pixpos(ui.numpos(e.style.left) - 5);
cover.style.top = ui.pixpos(ui.numpos(e.style.top) - 5);
cover.style.width = e.clientWidth + 10;
cover.style.height = e.clientHeight + 10;
cover.style.visibility = 'visible';
cover.style.left = ui.pixpos(ui.numpos(e.style.left) - 2);
cover.style.top = ui.pixpos(ui.numpos(e.style.top) - 2);
cover.style.width = ui.pixpos(e.clientWidth + 4);
cover.style.height = ui.pixpos(e.clientHeight + 4);
cover.style.visibility = 'inherit';
cover.style.borderStyle = 'solid';
cover.style.borderWidth = '0px';
cover.style.borderColor = '#598edd';
cover.style.padding = '0px';
cover.style.margin = '0px';
cover.covered = e;
e.cover = cover;
e.parentNode.appendChild(cover);
@ -458,11 +479,15 @@ page.clone = function(e) {
var ne = document.createElement('span');
// Skip the palette: prefix
ne.id = e.id.substr(8);
ne.id = 'page:' + e.id.substr(8);
// Copy the class and HTML content
ne.className = e.className;
ne.innerHTML = e.innerHTML;
// Fixup the widget style
page.fixupwidget(ne);
return ne;
}

View file

@ -36,14 +36,18 @@
<table style="width: 100%;">
<tr>
<td><h1><span id="h1"></span><span id="appNameHeader"></span></h1></td>
<td><h2><span id="h1"></span><span id="appNameHeader"></span></h2></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="thl thr" style="padding-top: 4px; padding-bottom: 4px;">Stats</th>
<th class="thl thr" style="padding-top: 4px; padding-bottom: 4px; padding-left: 2px; padding-right: 2px; ">Stats</th>
<th class="thl thr" style="width: 100%; text-align: right; padding-right: 2px; padding-top: 0px; padding-bottom: 0px;">
<input type="button" class="greenbutton" style="font-weight: bold; margin-top: 0px; margin-bottom: 0px; height: 24px;" id="cloneApp" value="Clone" title="Clone this app"/>
</th>
</tr>
</table>
@ -85,8 +89,11 @@ function applink(appname) {
// Set page titles
document.title = windowtitle(window.location.hostname) + ' - Stats - ' + appname;
$('h1').innerHTML = hometitle(window.location.hostname);
$('appNameHeader').innerHTML = ' - <a href=\"' + applink(appname) + '\" target=\"' + '_blank' + '\">' + appname + '</a>';
//$('h1').innerHTML = hometitle(window.location.hostname);
$('appNameHeader').innerHTML = '<a href=\"' + applink(appname) + '\" target=\"' + '_blank' + '\">' + appname + '.' + window.location.hostname + '</a>';
var tclone = isNil(config.clone)? 'Clone' : config.clone;
$('cloneApp').value = tclone;
$('cloneApp').title = tclone + ' this app';
// Load the menu bar
displaymenu();
@ -96,7 +103,7 @@ ui.showbody();
// Init service references
var editWidget = sca.component("EditWidget");
var dashboard = sca.reference(editWidget, "dashboard");
var dashboards = sca.reference(editWidget, "dashboards");
/**
* The current app entry and corresponding saved XML content.
@ -110,7 +117,7 @@ var savedappentryxml = '';
function getapp(name) {
if (isNil(name))
return false;
return dashboard.get(name, function(doc) {
return dashboards.get(name, function(doc) {
appentry = doc != null? car(elementsToValues(atom.readATOMEntry(mklist(doc)))) : mklist("'entry", mklist("'title", ''), mklist("'id", name));
var title = cadr(assoc("'title", cdr(appentry)));
$('appTitle').value = title;
@ -127,7 +134,7 @@ function getapp(name) {
function save(entryxml) {
$('saveStatus').innerHTML = 'Saving';
savedappentryxml = entryxml;
dashboard.put(appname, savedappentryxml);
dashboards.put(appname, savedappentryxml);
$('saveStatus').innerHTML = 'Saved';
return true;
}
@ -156,6 +163,13 @@ $('appForm').onsubmit = function() {
return false;
};
/**
* Handle Clone button event.
*/
$('cloneApp').onclick = function() {
return window.open('/clone/?app=' + appname, '_self');
}
// Get the current app
getapp(appname);

View file

@ -94,7 +94,7 @@ ui.showbody();
*/
var editWidget = sca.component("EditWidget");
var store = sca.reference(editWidget, "store");
var dashboard = sca.reference(editWidget, "dashboard");
var dashboards = sca.reference(editWidget, "dashboards");
/**
* Return the link to an app.
@ -116,6 +116,13 @@ function editApp(appname) {
return window.open('/page/?app=' + appname, '_self');
}
/**
* View an app.
*/
function viewApp(appname) {
return window.open('/stats/?app=' + appname, '_self');
}
/**
* Create an app.
*/
@ -125,13 +132,6 @@ if (category == 'myapps') {
}
}
/**
* Clone an app.
*/
function cloneApp(appname) {
return window.open('/clone/?app=' + appname, '_self');
}
/**
* Get and display list of apps.
*/
@ -150,10 +150,7 @@ function getapps(category) {
apps += '<div class="box" style="width: 285px; display: inline-block; border: 1px; border-style: solid; border-color: #dcdcdc; border-collapse: collapse; margin: 5px; padding: 10px; vertical-align: top;">'
apps += '<table><tr>';
apps += '<td>';
apps += '<div>' + ui.ahref(applink(name), '_blank', '<img src="/public/app.png" width="50" height="50" style="height: 50px; width: 50px; vertical-align: top; margin-right: 10px; margin-bottom: 5px;"></img>') + '</div>';
apps += '<div><input type="button" class="greenbutton" id="cloneApp" value="' + clone + '" title="' + clone + ' this app" onclick="cloneApp(\'' + name + '\');"></div>';
if (category == 'myapps')
apps += '<div><input type="button" id="editApp" class="bluebutton" value="Edit" title="Edit this app" onclick="editApp(\'' + name + '\');"></div>';
apps += '<div>' + ui.ahref('/stats/?app=' + name, '_self', '<img src="/public/app.png" width="50" height="50" style="height: 50px; width: 50px; vertical-align: top; margin-right: 10px; margin-bottom: 5px;"></img>') + '</div>';
apps += '</td>';
apps += '<td class="tdw">';
apps += '<div style="font-weight: bold">' + ui.ahref(applink(name), '_blank', name) + '</div>';
@ -164,7 +161,6 @@ function getapps(category) {
apps += '<div>Feb 4, 2011</div>';
apps += '<br/>';
apps += '<div>' + title + '</div>';
apps += '<br/>';
apps += '</td>';
apps += '</tr></table>';
apps += '</div>';
@ -174,7 +170,7 @@ function getapps(category) {
}
if (category == 'myapps')
return dashboard.get('', display);
return dashboards.get('', display);
return store.get(category, display);
}