git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@1154447 13f79535-47bb-0310-9956-ffa450edef68
691 lines
20 KiB
HTML
691 lines
20 KiB
HTML
<!DOCTYPE html>
|
|
<!--
|
|
* 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 manifest="/cache-manifest.cmf">
|
|
<head>
|
|
<title></title>
|
|
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0"/>
|
|
<meta name="apple-mobile-web-app-capable" content="yes"/>
|
|
<meta name="apple-mobile-web-app-status-bar-style" content="black"/>
|
|
<script type="text/javascript">
|
|
document.title = window.location.hostname.split('.')[0];
|
|
</script>
|
|
<link rel="apple-touch-icon" href="/public/touchicon.png"/>
|
|
<link rel="stylesheet" type="text/css" href="/ui-min.css"/>
|
|
<script type="text/javascript" src="/all-min.js"></script>
|
|
</head>
|
|
<body class="delayed" onload="ui.onload();" onbeforeunload="ui.onbeforeunload();">
|
|
<div id="bodydiv" class="bodydiv">
|
|
|
|
<div id="headdiv" class="hsection">
|
|
<script type="text/javascript" src="/headconfig.js"></script>
|
|
</div>
|
|
|
|
<div id="app">
|
|
<iframe id="appframe" style="position: relative; height: 5000px; width: 100%;" scrolling="no" frameborder="0" src="/frame.html"></iframe>
|
|
</div>
|
|
|
|
<div id="appbuffer" style="visibility: hidden">
|
|
</div>
|
|
|
|
<script type="text/javascript">
|
|
ui.initbody();
|
|
|
|
/**
|
|
* The main app div.
|
|
*/
|
|
var appdiv = $('app');
|
|
var appframe = $('appframe');
|
|
var appbody;
|
|
|
|
/**
|
|
* Start, stop, timer, animation and location components.
|
|
*/
|
|
var startcomp = sca.httpclient('start', '/start');
|
|
var stopcomp = sca.httpclient('stop', '/stop');
|
|
var timercomp = sca.httpclient('timer', '/timer');
|
|
var animationcomp = sca.httpclient('animation', '/animation');
|
|
var locationcomp = sca.httpclient('location', '/location');
|
|
|
|
/**
|
|
* Find a named value in a tree of elements. The value name is given
|
|
* as a list of ids.
|
|
*/
|
|
function namedvalue(l, id) {
|
|
if (isNil(l))
|
|
return null;
|
|
var e = car(l);
|
|
|
|
// Element matches id segment
|
|
if (car(id) == elementName(e)) {
|
|
|
|
// Found element matching the whole id path
|
|
if (isNil(cdr(id)))
|
|
return e;
|
|
|
|
// Search for next id segments in child elements
|
|
if (!elementHasValue(e)) {
|
|
var v = namedvalue(elementChildren(e), cdr(id));
|
|
if (v != null)
|
|
return v;
|
|
}
|
|
}
|
|
|
|
// Search for id through the whole element tree
|
|
if (!elementHasValue(e)) {
|
|
var v = namedvalue(elementChildren(e), id);
|
|
if (v != null)
|
|
return v;
|
|
}
|
|
return namedvalue(cdr(l), id);
|
|
}
|
|
|
|
/**
|
|
* Return the value of an input element.
|
|
*/
|
|
function inputvalue(e) {
|
|
if (e.className == 'entry' || e.className == 'password') {
|
|
return car(childElements(e)).value;
|
|
}
|
|
if (e.className == 'button') {
|
|
return car(childElements(e)).value;
|
|
}
|
|
if (e.className == 'checkbox') {
|
|
if (!car(childElements(e)).checked)
|
|
return null;
|
|
return car(childElements(e)).value;
|
|
}
|
|
if (e.className == 'select') {
|
|
return car(childElements(car(childElements(e)))).value;
|
|
}
|
|
return null;
|
|
};
|
|
|
|
/**
|
|
* Set a value into a widget.
|
|
*/
|
|
function setwidgetvalue(e, dv) {
|
|
var htattrs = namedElementChild("'htattrs", dv);
|
|
|
|
function attr(ce) {
|
|
return mklist(elementName(ce) == "'htstyle"? 'style' : elementName(ce).substring(1), elementHasValue(ce)? elementValue(ce) : elementChildren(ce));
|
|
}
|
|
|
|
function vattr(dv) {
|
|
return (elementHasValue(dv) && !isNil(elementValue(dv)))? mklist(mklist('value', isNil(elementValue(dv))? '' : elementValue(dv))) : mklist();
|
|
}
|
|
|
|
function sattr(dv) {
|
|
var s = namedElementChild("'htstyle", dv);
|
|
return isNil(s)? mklist() : mklist(mklist('style', elementHasValue(s)? elementValue(s) : elementChildren(s)))
|
|
}
|
|
|
|
var attrs = append(append(isNil(htattrs)? mklist() : map(attr, elementChildren(htattrs)), vattr(dv)), sattr(dv));
|
|
|
|
// Set the attributes of the widget
|
|
function setattrs(vsetter, attrs, ce) {
|
|
return map(function(a) {
|
|
if (car(a) == 'value')
|
|
return vsetter(a, ce);
|
|
|
|
if (car(a) == 'style') {
|
|
// Split a style property between a style attribute
|
|
// and a stylesheet definition in the document's head
|
|
|
|
function prop(s) {
|
|
if (s == ';')
|
|
return '';
|
|
var i = s.indexOf('<style>');
|
|
if (i == -1)
|
|
return s;
|
|
var j = s.indexOf('</style>');
|
|
return s.substring(0, i) + prop(s.substring(j + 8));
|
|
}
|
|
|
|
function sheet(s) {
|
|
var i = s.indexOf('<style>');
|
|
if (i == -1)
|
|
return '';
|
|
var j = s.indexOf('</style>');
|
|
return s.substring(i + 7, j) + sheet(s.substring(j + 8));
|
|
}
|
|
|
|
var st = cadr(a).replace(new RegExp('{id}', 'g'), e.id);
|
|
var p = prop(st);
|
|
var s = sheet(st);
|
|
|
|
// Define the stylesheet
|
|
if (s != '') {
|
|
var esheet = appframe.contentDocument.getElementById('style_' + e.id);
|
|
if (isNil(esheet)) {
|
|
var nesheet = document.createElement('style');
|
|
nesheet.id = 'style_' + e.id;
|
|
nesheet.type = 'text/css';
|
|
appframe.contentDocument.getElementsByTagName('head')[0].appendChild(nesheet);
|
|
nesheet.innerHTML = s;
|
|
} else {
|
|
esheet.innerHTML = s;
|
|
}
|
|
}
|
|
|
|
var aname = ce.style.webkitAnimationName;
|
|
|
|
// Set the style attribute
|
|
ce.setAttribute('style', p);
|
|
|
|
// Restart current animation if necessary
|
|
if (!isNil(aname) && ce.style.webkitAnimationName == aname) {
|
|
ce.style.webkitAnimationName = '';
|
|
setTimeout(function() {
|
|
ce.style.webkitAnimationName = aname;
|
|
}, 0);
|
|
}
|
|
return a;
|
|
}
|
|
|
|
ce.setAttribute(car(a), cadr(a));
|
|
return a;
|
|
}, attrs);
|
|
}
|
|
|
|
if (e.className == 'h1' || e.className == 'h2' || e.className == 'text' || e.className == 'section') {
|
|
var ce = car(childElements(e));
|
|
return setattrs(function(a, ce) { ce.innerHTML = cadr(a); }, attrs, ce);
|
|
}
|
|
if (e.className == 'entry' || e.className == 'password') {
|
|
var ce = car(childElements(e));
|
|
return setattrs(function(a, ce) { ce.defaultValue = cadr(a); }, attrs, ce);
|
|
}
|
|
if (e.className == 'button') {
|
|
var ce = car(childElements(e));
|
|
return setattrs(function(a, ce) { ce.value = cadr(a); }, attrs, ce);
|
|
}
|
|
if (e.className == 'checkbox') {
|
|
var ce = car(childElements(e));
|
|
|
|
function setcheckvalue(a, ce) {
|
|
var v = cadr(a);
|
|
ce.value = v;
|
|
map(function(n) { if (n.nodeName == "SPAN") n.innerHTML = v; return n; }, nodeList(e.childNodes));
|
|
return true;
|
|
}
|
|
|
|
return setattrs(setcheckvalue, attrs, ce);
|
|
}
|
|
if (e.className == 'select') {
|
|
var ce = car(childElements(car(childElements(e))));
|
|
|
|
function setselectvalue(a, ce) {
|
|
var v = cadr(a);
|
|
ce.value = v;
|
|
ce.innerHTML = v;
|
|
return true;
|
|
}
|
|
|
|
return setattrs(setselectvalue, attrs, ce);
|
|
}
|
|
if (e.className == 'list') {
|
|
var dl = ui.datalist(isNil(dv)? mklist() : mklist(dv));
|
|
e.innerHTML = dl;
|
|
return dl;
|
|
}
|
|
if (e.className == 'table') {
|
|
var dl = ui.datatable(isNil(dv)? mklist() : mklist(dv));
|
|
e.innerHTML = dl;
|
|
return dl;
|
|
}
|
|
if (e.className == 'link') {
|
|
var ce = car(childElements(e));
|
|
|
|
function setlinkvalue(a, ce) {
|
|
var v = cadr(a);
|
|
if (isList(v)) {
|
|
ce.href = car(v);
|
|
ce.innerHTML = cadr(v);
|
|
return true;
|
|
}
|
|
ce.href = v;
|
|
ce.innerHTML = v;
|
|
return true;
|
|
}
|
|
|
|
return setattrs(setlinkvalue, attrs, ce);
|
|
}
|
|
if (e.className == 'img') {
|
|
var ce = car(childElements(e));
|
|
return setattrs(function(a, ce) { ce.setAttribute('src', cadr(a)); }, attrs, ce);
|
|
}
|
|
if (e.className == 'iframe') {
|
|
var ce = car(childElements(e));
|
|
return setattrs(function(a, ce) { ce.setAttribute('src', cadr(a)); }, attrs, ce);
|
|
}
|
|
return '';
|
|
};
|
|
|
|
/**
|
|
* Update the app page with the given app data.
|
|
*/
|
|
function updatepage(l) {
|
|
if (isNil(l))
|
|
return true;
|
|
|
|
// Update the widgets values
|
|
function updatewidget(e) {
|
|
var dv = namedvalue(l, map(function(t) { return "'" + t; }, e.id.split('.')));
|
|
if (dv == null || isNil(dv))
|
|
return e;
|
|
setwidgetvalue(e, dv);
|
|
return e;
|
|
}
|
|
|
|
map(updatewidget, filter(function(e) { return !isNil(e.id) && e.id.substring(0, 5) != 'page:'; }, nodeList(ui.elementByID(appbody, 'page').childNodes)));
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Convert a document to application data.
|
|
*/
|
|
function docdata(doc) {
|
|
if (isNil(doc))
|
|
return null;
|
|
|
|
if (json.isJSON(mklist(doc)))
|
|
return json.readJSON(mklist(doc));
|
|
|
|
if (atom.isATOMEntry(mklist(doc)))
|
|
return atom.readATOMEntry(mklist(doc));
|
|
|
|
if (atom.isATOMFeed(mklist(doc)))
|
|
return atom.readATOMFeed(mklist(doc));
|
|
|
|
return doc;
|
|
}
|
|
|
|
/**
|
|
* Bind a handler to a widget.
|
|
*/
|
|
function bindwidgethandler(e) {
|
|
if (e.className == 'button') {
|
|
var b = car(childElements(e));
|
|
b.name = e.id;
|
|
b.onclick = function() { return buttonClickHandler(b.value); };
|
|
return e;
|
|
}
|
|
if (e.className == 'link') {
|
|
var l = car(childElements(e));
|
|
var hr = l.href;
|
|
if (hr.substring(0, 5) == 'link:' && hr.indexOf('://') == -1) {
|
|
var f = function(e) {
|
|
e.preventDefault();
|
|
return buttonClickHandler(hr.substring(5));
|
|
};
|
|
l.ontouchstart = l.onclick = f;
|
|
l.href = 'javascript:void()';
|
|
}
|
|
return e;
|
|
}
|
|
if (e.className == 'entry' || e.className == 'password' || e.className == 'checkbox') {
|
|
car(childElements(e)).name = e.id;
|
|
return e;
|
|
}
|
|
if (e.className == 'select') {
|
|
var ce = car(childElements(car(childElements(e))));
|
|
ce.name = e.id;
|
|
return e;
|
|
}
|
|
return e;
|
|
}
|
|
|
|
/**
|
|
* Initial fixup of a widget.
|
|
*/
|
|
function fixupwidget(e) {
|
|
if (e.className == 'h1' || e.className == 'h2' || e.className == 'text' || e.className == 'section') {
|
|
if (e.className == 'section')
|
|
e.style.width = '100%';
|
|
var ce = car(childElements(e));
|
|
if (ce.innerHTML == '=' + e.id)
|
|
ce.innerHTML = '';
|
|
return e;
|
|
}
|
|
if (e.className == 'entry' || e.className == 'password') {
|
|
var ce = car(childElements(e));
|
|
if (ce.defaultValue == '=' + e.id)
|
|
ce.defaultValue = '';
|
|
return e;
|
|
}
|
|
if (e.className == 'button') {
|
|
var ce = car(childElements(e));
|
|
if (ce.value == '=' + e.id)
|
|
ce.value = '';
|
|
return e;
|
|
}
|
|
if (e.className == 'checkbox') {
|
|
var ce = car(childElements(e));
|
|
if (ce.value == '=' + e.id) {
|
|
ce.value = '';
|
|
map(function(n) { if (n.nodeName == "SPAN") n.innerHTML = ''; return n; }, nodeList(e.childNodes));
|
|
}
|
|
return e;
|
|
}
|
|
if (e.className == 'select') {
|
|
var ce = car(childElements(car(childElements(e))));
|
|
if (ce.value == '=' + e.id) {
|
|
ce.value = '';
|
|
ce.innerHTML = '';
|
|
}
|
|
return e;
|
|
}
|
|
if (e.className == 'list') {
|
|
car(childElements(e)).innerHTML = '';
|
|
e.style.width = '100%';
|
|
car(childElements(e)).style.width = '100%';
|
|
return e;
|
|
}
|
|
if (e.className == 'table') {
|
|
car(childElements(e)).innerHTML = '';
|
|
e.style.width = '100%';
|
|
car(childElements(e)).style.width = '100%';
|
|
return e;
|
|
}
|
|
if (e.className == 'link') {
|
|
var ce = car(childElements(e));
|
|
if (ce.innerHTML == '=' + e.id)
|
|
ce.innerHTML = '';
|
|
return e;
|
|
}
|
|
if (e.className == 'img') {
|
|
var ce = car(childElements(e));
|
|
return e;
|
|
}
|
|
if (e.className == 'iframe') {
|
|
var ce = car(childElements(e));
|
|
e.innerHTML = '<iframe src="' + ce.href + '" frameborder="no" scrolling="no"></iframe>';
|
|
return 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 document from a component.
|
|
*/
|
|
function getdoc(comp, name, uri) {
|
|
try {
|
|
return comp.getnocache(uri);
|
|
} catch(e) {
|
|
log('exception on get(' + name + ', ' + uri + ')', e);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get app data from the main app page component.
|
|
*/
|
|
function getpagedata() {
|
|
try {
|
|
|
|
// Display component data on the page
|
|
function displaypage(doc) {
|
|
updatepage(docdata(doc));
|
|
return true;
|
|
}
|
|
|
|
// Eval a component init script
|
|
function evalcompinit(doc) {
|
|
if (isNil(doc))
|
|
return true;
|
|
var js = car(json.readJSON(mklist(doc)));
|
|
if (!elementHasValue(js))
|
|
return true;
|
|
eval(elementValue(js));
|
|
return true;
|
|
}
|
|
|
|
// Initial setup of a widget
|
|
function setupwidget(e) {
|
|
initwidget(e);
|
|
fixupwidget(e);
|
|
bindwidgethandler(e);
|
|
}
|
|
|
|
// Get the component app data
|
|
var doc = getdoc(startcomp, 'start', window.location.search);
|
|
|
|
// Prepare app HTML page
|
|
appbody = appframe.contentDocument.body;
|
|
var appbufferbody = $('appbufferframe').contentDocument.body;
|
|
appbody.innerHTML = appbufferbody.innerHTML;
|
|
appbufferbody.innerHTML = '';
|
|
|
|
// Setup the widgets
|
|
map(setupwidget, filter(function(e) { return !isNil(e.id); }, nodeList(ui.elementByID(appbody, 'page').childNodes)));
|
|
|
|
// Display data on the page
|
|
displaypage(doc);
|
|
|
|
// Get and eval the optional timer, animation and location watch setup scripts
|
|
evalcompinit(getdoc(timercomp, 'timer', 'setup'));
|
|
evalcompinit(getdoc(animationcomp, 'animation', 'setup'));
|
|
evalcompinit(getdoc(locationcomp, 'location', 'setup'));
|
|
|
|
return true;
|
|
|
|
} catch(e) {
|
|
log('exception in getpagedata()', e);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Build a query string from the values of the page's input fields.
|
|
*/
|
|
function compquery() {
|
|
function queryarg(e) {
|
|
return e.id + '=' + inputvalue(e);
|
|
}
|
|
|
|
function childrenList(n) {
|
|
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(appbody, 'page'))));
|
|
|
|
// Append current location properties if known
|
|
if (!isNil(geoposition)) {
|
|
var g = geoposition;
|
|
args = append(args, mklist('latitude=' + g.coords.latitude, 'longitude=' + g.coords.longitude, 'altitude=' + g.coords.altitude,
|
|
'accuracy=' + g.coords.accuracy, 'altitudeAccuracy=' + g.coords.altitudeAccuracy, 'heading=' + g.coords.heading,
|
|
'speed=' + g.coords.speed));
|
|
}
|
|
|
|
return '?' + args.join('&');
|
|
}
|
|
|
|
/**
|
|
* Handle a button click event.
|
|
*/
|
|
function buttonClickHandler(id) {
|
|
try {
|
|
return updatepage(docdata(getdoc(sca.component(id), 'button', compquery())));
|
|
} catch(e) {
|
|
log('exception in buttonClickHandler()', e);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Handle a timer interval event.
|
|
*/
|
|
function intervalHandler() {
|
|
try {
|
|
return updatepage(docdata(getdoc(timercomp, 'timer', compquery())));
|
|
} catch(e) {
|
|
log('exception in intervalHandler()', e);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Setup an interval timer.
|
|
*/
|
|
function setupIntervalHandler(msec) {
|
|
intervalHandler();
|
|
try {
|
|
return setInterval(intervalHandler, msec);
|
|
} catch(e) {
|
|
log('exception in setupIntervalHandler()', e);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Handle an animation event.
|
|
*/
|
|
var animationData = null;
|
|
var currentAnimationData = null;
|
|
var animationLoop = 0;
|
|
var currentAnimationLoop = 0;
|
|
|
|
function animationHandler() {
|
|
try {
|
|
// Get animation data if necessary
|
|
if (isNil(animationData)) {
|
|
animationData = docdata(getdoc(animationcomp, 'animation', compquery()));
|
|
if (isNil(animationData)) {
|
|
// Retry later
|
|
return true;
|
|
}
|
|
currentAnimationData = animationData;
|
|
currentAnimationLoop = animationLoop;
|
|
}
|
|
|
|
// Update page with animation data
|
|
updatepage(car(currentAnimationData));
|
|
|
|
// End of animation?
|
|
if (isNil(cdr(currentAnimationData))) {
|
|
if (currentAnimationLoop == -1) {
|
|
// Repeat current animation forever
|
|
currentAnimationData = animationData;
|
|
return true;
|
|
}
|
|
|
|
currentAnimationLoop = currentAnimationLoop - 1;
|
|
if (currentAnimationLoop <= 0) {
|
|
// Get next animation data
|
|
currentAnimationData = null;
|
|
animationData = null;
|
|
return true;
|
|
}
|
|
|
|
// Repeat animation
|
|
currentAnimationData = animationData;
|
|
return true;
|
|
}
|
|
|
|
// Move to the next animation frame
|
|
currentAnimationData = cdr(currentAnimationData);
|
|
return true;
|
|
|
|
} catch(e) {
|
|
log('exception in animationHandler()', e);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Setup an animation.
|
|
*/
|
|
function setupAnimationHandler(msec, loop) {
|
|
animationLoop = loop;
|
|
animationHandler();
|
|
try {
|
|
return setInterval(animationHandler, msec);
|
|
} catch(e) {
|
|
log('exception in setupAnimationHandler()', e);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Handle a location watch event.
|
|
*/
|
|
var locationWatch = null;
|
|
var geoposition = null;
|
|
|
|
function locationHandler(pos) {
|
|
try {
|
|
geoposition = pos;
|
|
return updatepage(docdata(getdoc(locationcomp, 'location', compquery())));
|
|
} catch(e) {
|
|
locationErrorHandler(e);
|
|
}
|
|
}
|
|
|
|
function locationErrorHandler(e) {
|
|
log('location error', e);
|
|
if (!isNil(locationWatch)) {
|
|
try {
|
|
navigator.geolocation.clearWatch(locationWatch);
|
|
} catch(e) {}
|
|
locationWatch = null;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Setup a location watch handler.
|
|
*/
|
|
function setupLocationHandler() {
|
|
function installLocationHandler() {
|
|
if (!isNil(locationWatch))
|
|
return true;
|
|
try {
|
|
locationWatch = navigator.geolocation.watchPosition(locationHandler, locationErrorHandler);
|
|
} catch(e) {
|
|
log('exception in installLocationHandler()', e);
|
|
}
|
|
}
|
|
|
|
installLocationHandler();
|
|
setInterval(installLocationHandler, 10000);
|
|
return true;
|
|
}
|
|
|
|
// Load the app frame
|
|
$('appbuffer').innerHTML = '<iframe id="appbufferframe" style="position: relative; height: 5000px; width: 100%;" scrolling="no" frameborder="0" src="app.html" onload="getpagedata()"></iframe>';
|
|
</script>
|
|
|
|
<div id="footdiv" class="fsection">
|
|
<script type="text/javascript" src="/footconfig.js"></script>
|
|
</div>
|
|
|
|
</div>
|
|
</body>
|
|
</html>
|
|
|