diff options
author | jsdelfino <jsdelfino@13f79535-47bb-0310-9956-ffa450edef68> | 2012-01-30 15:56:11 +0000 |
---|---|---|
committer | jsdelfino <jsdelfino@13f79535-47bb-0310-9956-ffa450edef68> | 2012-01-30 15:56:11 +0000 |
commit | f4c4803ce0c14585e3c2af3641d94b651877e04c (patch) | |
tree | 9f10df32f2d34a3c697aaee897bad0b180922095 /sca-cpp/trunk/hosting/server/htdocs/app | |
parent | 1b10f18fce6baeb721a725661ded630614831304 (diff) |
Refactor server hosting module, rename it and move it under a hosting dir, and refactor its datastore components into a single component.
git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@1237740 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'sca-cpp/trunk/hosting/server/htdocs/app')
-rw-r--r-- | sca-cpp/trunk/hosting/server/htdocs/app/cache-manifest.cmf | 17 | ||||
-rw-r--r-- | sca-cpp/trunk/hosting/server/htdocs/app/index.html | 906 |
2 files changed, 923 insertions, 0 deletions
diff --git a/sca-cpp/trunk/hosting/server/htdocs/app/cache-manifest.cmf b/sca-cpp/trunk/hosting/server/htdocs/app/cache-manifest.cmf new file mode 100644 index 0000000000..6ea53970aa --- /dev/null +++ b/sca-cpp/trunk/hosting/server/htdocs/app/cache-manifest.cmf @@ -0,0 +1,17 @@ +CACHE MANIFEST + +# Version 5 + +# App resources +/favicon.ico +/public/iframe-min.html +/public/img.png +/public/notauth/ +/public/notfound/ +/public/notyet/ +/public/oops/ +/public/touchicon.png + +NETWORK: +* + diff --git a/sca-cpp/trunk/hosting/server/htdocs/app/index.html b/sca-cpp/trunk/hosting/server/htdocs/app/index.html new file mode 100644 index 0000000000..0b01c1d3bd --- /dev/null +++ b/sca-cpp/trunk/hosting/server/htdocs/app/index.html @@ -0,0 +1,906 @@ +<!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, minimum-scale=1.0, maximum-scale=1.0"/> +<meta name="apple-mobile-web-app-capable" content="yes"/> +<meta name="apple-mobile-web-app-status-bar-style" content="black"/> +<link rel="apple-touch-icon" href="/public/touchicon.png"/> +<base href="/"/> +<script type="text/javascript"> + +window.appcache = {}; + +/** + * Get and cache a resource. + */ +appcache.get = function(uri) { + var h = uri.indexOf('#'); + var u = h == -1? uri : uri.substring(0, h); + + // Get resource from local storage first + var item = localStorage.getItem(u); + if (item != null && item != '') + return item; + + // Get resource from network + var http = new XMLHttpRequest(); + http.open("GET", u, false); + http.send(null); + if (http.status == 200) { + if (http.getResponseHeader("X-Login") != null) { + if (log) log('http error', u, 'X-Login'); + // Redirect to login page if not signed in + document.location = '/login/'; + return null; + } else if (http.responseText == '' || http.getResponseHeader("Content-Type") == null) { + if (log) log('http error', u, 'No-Content'); + return null; + } + localStorage.setItem(u, http.responseText); + return http.responseText; + } + if (log) log('http error', u, http.status, http.statusText); + // Redirect to login page if not signed in + if (http.status == 403) + document.location = '/login/'; + return null; +}; + +// Load Javascript and CSS +(function() { + var bootjs = document.createElement('script'); + bootjs.type = 'text/javascript'; + bootjs.text = appcache.get('/all-min.js'); + document.head.appendChild(bootjs); + document.head.appendChild(ui.declareCSS(appcache.get('/ui-min.css'))); +})(); + +// Redirect to login page if not signed in +if (document.location.protocol == 'https:' && !ui.signedin()) + document.location = '/login/'; + +</script> +</head> +<body class="delayed" onload="onload();"> +<div id="mainbodydiv" class="mainbodydiv"> + +<div id="headdiv" class="hsection"> +<script type="text/javascript"> +(function() { +$('headdiv').appendChild(ui.declareScript(appcache.get('/config-min.js'))); +})(); +</script> +</div> + +<div id="content"> +</div> + +<script type="text/javascript"> + +/** + * Get the app name + */ +var appname = location.pathname.split('/')[1]; + +// Set page title +document.title = appname; + +/** + * The main page div. + */ +var contentdiv = $('content'); + +/** + * Initialize the app HTTP clients. + */ +var appWidget = sca.component('AppWidget'); +var pagecomp = sca.reference(appWidget, 'pages'); +var startcomp = sca.httpclient('start', '/' + appname + '/start'); +var stopcomp = sca.httpclient('stop', '/' + appname + '/stop'); +var timercomp = sca.httpclient('timer', '/' + appname + '/timer'); +var animationcomp = sca.httpclient('animation', '/' + appname + '/animation'); +var locationcomp = sca.httpclient('location', '/' + appname + '/location'); + +/** + * Pre-fetch app resources. + */ +var appresources = [ + ['/all-min.js'], + ['/ui-min.css'], + ['/config-min.js'], + ['/public/config-min.js'] +]; + +/** + * Handle application cache events. + */ +applicationCache.addEventListener('checking', function(e) { + //log('appcache checking', e); +}, false); +applicationCache.addEventListener('error', function(e) { + //log('appcache error', e); +}, false); +applicationCache.addEventListener('noupdate', function(e) { + //log('appcache noupdate', e); +}, false); +applicationCache.addEventListener('downloading', function(e) { + //log('appcache downloading', e); +}, false); +applicationCache.addEventListener('progress', function(e) { + //log('appcache progress', e); +}, false); +applicationCache.addEventListener('updateready', function(e) { + //log('appcache updateready', e); + applicationCache.swapCache(); + //log('appcache swapped', e); +}, false); +applicationCache.addEventListener('cached', function(e) { + //log('appcache cached', e); + map(function(res) { + appcache.get(res[0]); + }, appresources); +}, false); + +/** + * Handle network offline/online events. + */ +window.addEventListener('offline', function(e) { + //log('going offline'); +}, false); +window.addEventListener('online', function(e) { + //log('going online'); +}, false); + +//log(navigator.onLine? 'online' : 'offline'); + +/** + * 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 = ui.elementByID(contentdiv, 'style_' + e.id); + if (isNil(esheet)) { + var nesheet = document.createElement('style'); + nesheet.id = 'style_' + e.id; + nesheet.type = 'text/css'; + document.head.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(contentdiv, '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, appname) { + if (e.className == 'button') { + var b = car(childElements(e)); + b.name = e.id; + b.onclick = function() { return buttonClickHandler(b.value, appname); }; + 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), appname); + }; + 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 app data from the main app page component. + */ +function getpagedata(appname) { + 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, appname); + } + + // Setup the widgets + map(setupwidget, filter(function(e) { return !isNil(e.id); }, nodeList(ui.elementByID(contentdiv, 'page').childNodes))); + + // Get the component app data + startcomp.get(location.search, function(doc, e) { + if (isNil(doc)) { + log('error on get(start, ' + location.search + ')', e); + return false; + } + + // Display data on the page + displaypage(doc); + }); + + // Get and eval the optional timer, animation and location watch setup scripts + timercomp.get('setup', function(doc, e) { + if (isNil(doc)) { + log('error on get(timer, setup)', e); + return false; + } + + // Evaluate the component init expression + return evalcompinit(doc); + }); + animationcomp.get('setup', function(doc, e) { + if (isNil(doc)) { + log('error on get(animation, setup)', e); + return false; + } + + // Evaluate the component init expression + return evalcompinit(doc); + }); + locationcomp.get('setup', function(doc, e) { + if (isNil(doc)) { + log('error on get(location, setup)', e); + return false; + } + + // Evaluate the component init expression + return evalcompinit(doc); + }); + + return true; + + } catch(e) { + log('error 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(contentdiv, '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, appname) { + try { + var uri = compquery(); + return sca.component(id, appname).get(uri, function(doc, e) { + if (isNil(doc)) { + log('error on get(button, ' + uri + ')', e); + return false; + } + + // Inject data into the page + updatepage(docdata(doc)); + }); + } catch(e) { + log('error in buttonClickHandler()', e); + return true; + } +} + +/** + * Handle a timer interval event. + */ +function intervalHandler() { + try { + var uri = compquery(); + return timercomp.get(uri, function(doc, e) { + if (isNil(doc)) { + log('error on get(timer, ' + uri + ')', e); + return false; + } + + // Inject data into the page + updatepage(docdata(doc)); + }); + } catch(e) { + log('error in intervalHandler()', e); + return true; + } +} + +/** + * Setup an interval timer. + */ +function setupIntervalHandler(msec) { + intervalHandler(); + try { + return setInterval(intervalHandler, msec); + } catch(e) { + log('error in setupIntervalHandler()', e); + return true; + } +} + +/** + * Handle an animation event. + */ +var animationData = null; +var gettingAnimationData = false; +var currentAnimationData = null; +var animationLoop = 0; +var currentAnimationLoop = 0; + +function animationHandler() { + try { + function applyAnimation() { + // Update page with current 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; + } + + // Get new animation data if necessary + if (isNil(animationData)) { + if (gettingAnimationData) + return true; + var uri = compquery(); + return animationcomp.get(uri, function(doc, e) { + if (isNil(doc)) { + log('error on get(animation, ' + uri + ')', e); + return false; + } + + // Apply the new animation + currentAnimationData = docdata(doc); + currentAnimationLoop = animationLoop; + gettingAnimationData = false; + applyAnimation(); + }); + } + + // Apply the current animation + return applyAnimation(); + + } catch(e) { + log('error in animationHandler()', e); + return true; + } +} + +/** + * Setup an animation. + */ +function setupAnimationHandler(msec, loop) { + animationLoop = loop; + animationHandler(); + try { + return setInterval(animationHandler, msec); + } catch(e) { + log('error in setupAnimationHandler()', e); + return true; + } +} + +/** + * Handle a location watch event. + */ +var locationWatch = null; +var geoposition = null; + +function locationHandler(pos) { + try { + geoposition = pos; + var uri = compquery(); + return locationcomp.get(uri, function(doc, e) { + if (isNil(doc)) { + log('error on get(location, ' + uri + ')', e); + return false; + } + + // Inject data into the page + updatepage(docdata(doc)); + }); + } catch(e) { + return 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('error in installLocationHandler()', e); + } + return true; + } + + installLocationHandler(); + setInterval(installLocationHandler, 10000); + return true; +} + +/** + * Return the page in an ATOM entry. + */ +function atompage(doc) { + var entry = atom.readATOMEntry(mklist(doc)); + if (isNil(entry)) + return mklist(); + var content = namedElementChild("'content", car(entry)); + if (content == null) + return mklist(); + return elementChildren(content); +} + +// Load the app page +pagecomp.get(appname, function(doc, e) { + //log('page get'); + if (isNil(doc)) { + log('error getting app page', e); + return false; + } + + // Set the app HTML page into the content div + //log('page', doc); + var el = atompage(doc); + contentdiv.innerHTML = writeStrings(writeXML(el, false)); + + // Merge in the app data + getpagedata(appname); +}); + +/** + * Handle orientation change. + */ +document.body.onorientationchange = function(e) { + //log('onorientationchange'); + + // Scroll to the top and hide the address bar + window.scrollTo(0, 0); + + return true; +}; + +/** + * Document load post processing. + */ +function onload() { + //log('onload'); + + // Show the page + document.body.style.visibility = 'visible'; + + // Scroll to the top and hide the address bar + window.scrollTo(0, 0); + return true; +} + +</script> + +<div id="footdiv" class="fsection"> +</div> + +</div> +</body> +</html> + |