| <!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/cache-manifest.cmf"> |
| <head> |
| <!-- Firebug inspector --> |
| <!-- |
| <script type="text/javascript" src="https://getfirebug.com/releases/lite/1.3/firebug-lite.js"></script> |
| --> |
| <!-- Weinre inspector --> |
| <!-- |
| <script src="http://www.example.com:9998/target/target-script-min.js#anonymous"></script> |
| --> |
| <title></title> |
| <meta name="viewport" content="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-precomposed" href="/public/touchicon.png"/> |
| <base href="/"/> |
| <script type="text/javascript"> |
| try { |
| |
| (function apphead() { |
| |
| window.appcache = {}; |
| |
| /** |
| * Get and cache a resource. |
| */ |
| appcache.get = function(uri, mode) { |
| var h = uri.indexOf('#'); |
| var u = h == -1? uri : uri.substring(0, h); |
| |
| // Get resource from local storage first |
| var ls = window.lstorage || localStorage; |
| var item = null; |
| try { item = ls.getItem('ui.r.' + u); } catch(e) {} |
| if (item != null && item != '') |
| return item; |
| |
| // Get resource from network |
| var http = new XMLHttpRequest(); |
| http.open("GET", mode == 'remote'? (u + '?t=' + new Date().getTime() + '&r=' + Math.random()) : u, false); |
| http.setRequestHeader("Accept", "*/*"); |
| if (mode == 'remote') |
| http.setRequestHeader("If-Modified-Since", "Thu, 1 Jan 1970 00:00:00 GMT"); |
| http.send(null); |
| if (http.status == 200) { |
| if (http.getResponseHeader("X-Login") != null) { |
| if (window.debug) debug('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 (window.debug) debug('http error', u, 'No-Content'); |
| return null; |
| } |
| try { ls.setItem('ui.r.' + u, http.responseText); } catch(e) {} |
| return http.responseText; |
| } |
| if (window.debug) debug('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 appboot() { |
| |
| var bootjs = document.createElement('script'); |
| bootjs.type = 'text/javascript'; |
| bootjs.text = 'try {\n' + appcache.get('/all-min.js') + '\n' + appcache.get('/config-min.js') + '\n} catch(e) { console.log(e.stack); throw e; }\n'; |
| var head = document.getElementsByTagName('head')[0]; |
| head.appendChild(bootjs); |
| head.appendChild(ui.declareCSS(appcache.get('/ui-min.css'))); |
| |
| })(); |
| |
| } catch(e) { |
| if (window.debug) debug(e.stack); |
| throw e; |
| } |
| </script> |
| </head> |
| <body class="delayed"> |
| |
| <div id="content"> |
| </div> |
| |
| <script type="text/javascript"> |
| try { |
| |
| (function appbody() { |
| |
| /** |
| * Get the app name |
| */ |
| var appname = location.pathname.split('/')[1]; |
| |
| /** |
| * Set page title. |
| */ |
| document.title = appname; |
| |
| /** |
| * The main page div. |
| */ |
| var contentdiv = $('content'); |
| |
| /** |
| * The main app composite and page definitions. |
| */ |
| var appcomposite = null; |
| var apppage = null; |
| |
| /** |
| * Initialize the app HTTP clients. |
| */ |
| var appComp = sca.component('App'); |
| var pagecomp = sca.reference(appComp, 'pages'); |
| var composcomp = sca.reference(appComp, 'composites'); |
| 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) { |
| //debug('appcache checking', e); |
| }, false); |
| applicationCache.addEventListener('error', function(e) { |
| //debug('appcache error', e); |
| }, false); |
| applicationCache.addEventListener('noupdate', function(e) { |
| //debug('appcache noupdate', e); |
| }, false); |
| applicationCache.addEventListener('downloading', function(e) { |
| //debug('appcache downloading', e); |
| }, false); |
| applicationCache.addEventListener('progress', function(e) { |
| //debug('appcache progress', e); |
| }, false); |
| applicationCache.addEventListener('updateready', function(e) { |
| //debug('appcache updateready', e); |
| try { |
| applicationCache.swapCache(); |
| } catch(e) {} |
| //debug('appcache swapped', e); |
| }, false); |
| applicationCache.addEventListener('cached', function(e) { |
| //debug('appcache cached', e); |
| map(function(res) { |
| appcache.get(res[0], 'remote'); |
| }, appresources); |
| }, false); |
| |
| /** |
| * Handle network offline/online events. |
| */ |
| window.addEventListener('offline', function(e) { |
| //debug('going offline'); |
| }, false); |
| window.addEventListener('online', function(e) { |
| //debug('going online'); |
| }, false); |
| |
| //debug(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 (isNull(l)) |
| return null; |
| var e = car(l); |
| |
| // Element matches id segment |
| if (car(id) == elementName(e)) { |
| |
| // Found element matching the whole id path |
| if (isNull(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) && !isNull(elementValue(dv)))? mklist(mklist('value', isNull(elementValue(dv))? '' : elementValue(dv))) : mklist(); |
| } |
| |
| function sattr(dv) { |
| var s = namedElementChild("'htstyle", dv); |
| return isNull(s)? mklist() : mklist(mklist('style', elementHasValue(s)? elementValue(s) : elementChildren(s))) |
| } |
| |
| var attrs = append(append(isNull(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(document, 'style_' + e.id); |
| if (isNull(esheet)) { |
| var nesheet = document.createElement('style'); |
| nesheet.id = 'style_' + e.id; |
| nesheet.type = 'text/css'; |
| var head = document.getElementsByTagName('head')[0]; |
| 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 (!isNull(aname) && ce.style.webkitAnimationName == aname) { |
| ce.style.webkitAnimationName = ''; |
| ui.async(function restartanimation() { |
| ce.style.webkitAnimationName = aname; |
| }); |
| } |
| 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(isNull(dv)? mklist() : mklist(dv)); |
| e.innerHTML = dl; |
| return dl; |
| } |
| if (e.className == 'table') { |
| var dl = ui.datatable(isNull(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 (isNull(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 || isNull(dv)) |
| return e; |
| setwidgetvalue(e, dv); |
| return e; |
| } |
| |
| map(updatewidget, filter(function(e) { return !isNull(e.id) && e.id.substring(0, 5) != 'page:'; }, nodeList(ui.elementByID(document, 'page').childNodes))); |
| return true; |
| } |
| |
| /** |
| * Convert a document to application data. |
| */ |
| function docdata(doc) { |
| if (isNull(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; |
| ui.onclick(b, function(e) { |
| 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) { |
| ui.onclick(l, function(e) { |
| e.preventDefault(); |
| return buttonClickHandler(hr.substring(5), appname); |
| }); |
| 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 (!isNull(e.id) && e.id.substring(0, 5) != 'page:') |
| setwidgetvalue(e, mklist()); |
| return e; |
| } |
| |
| /** |
| * Return the component bound to a uri. |
| */ |
| function isbound(uri, comps) { |
| return !isNull(filter(function(comp) { |
| return !isNull(filter(function(svc) { |
| return !isNull(filter(function(b) { |
| return uri == scdl.uri(b); |
| }, scdl.bindings(svc))); |
| }, scdl.services(comp))); |
| }, comps)); |
| } |
| |
| /** |
| * Get app data from the main app page component. |
| */ |
| function getappdata(appname, page, compos) { |
| try { |
| |
| // Eval a component init script |
| function evalcompinit(doc) { |
| if (isNull(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 !isNull(e.id); }, nodeList(ui.elementByID(document, 'page').childNodes))); |
| |
| // Get the app components |
| var comps = scdl.components(compos); |
| |
| // Get the component app data |
| if (isbound("start", comps)) { |
| startcomp.get(location.search, function(doc, e) { |
| if (isNull(doc)) { |
| debug('error on get(start, ' + location.search + ')', e); |
| return false; |
| } |
| |
| // Display data on the page |
| updatepage(docdata(doc)); |
| }); |
| } |
| |
| // Get and eval the optional timer, animation and location watch setup scripts |
| if (isbound("timer", comps)) { |
| timercomp.get('setup', function(doc, e) { |
| if (isNull(doc)) { |
| debug('error on get(timer, setup)', e); |
| return false; |
| } |
| |
| // Evaluate the component init expression |
| return evalcompinit(doc); |
| }); |
| } |
| |
| if (isbound("animation", comps)) { |
| animationcomp.get('setup', function(doc, e) { |
| if (isNull(doc)) { |
| debug('error on get(animation, setup)', e); |
| return false; |
| } |
| |
| // Evaluate the component init expression |
| return evalcompinit(doc); |
| }); |
| } |
| |
| if (isbound("location", comps)) { |
| locationcomp.get('setup', function(doc, e) { |
| if (isNull(doc)) { |
| debug('error on get(location, setup)', e); |
| return false; |
| } |
| |
| // Evaluate the component init expression |
| return evalcompinit(doc); |
| }); |
| } |
| |
| return true; |
| |
| } catch(e) { |
| debug('error in getappdata()', e); |
| return true; |
| } |
| } |
| |
| /** |
| * Return the page in an ATOM entry. |
| */ |
| function atompage(doc) { |
| var entry = atom.readATOMEntry(mklist(doc)); |
| if (isNull(entry)) |
| return mklist(); |
| var content = namedElementChild("'content", car(entry)); |
| if (content == null) |
| return mklist(); |
| return elementChildren(content); |
| } |
| |
| /** |
| * Get the app page. |
| */ |
| function getapppage(appname, compos) { |
| pagecomp.get(appname, function(doc, e) { |
| //debug('page get'); |
| if (isNull(doc)) { |
| debug('error in getapppage', e); |
| return false; |
| } |
| |
| // Set the app HTML page into the content div |
| var page = atompage(doc); |
| contentdiv.innerHTML = writeStrings(writeXML(page, false)); |
| apppage = page; |
| |
| // Merge in the app data |
| if (!isNull(appcomposite)) |
| getappdata(appname, apppage, appcomposite); |
| }); |
| |
| } |
| |
| /** |
| * 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 !isNull(e.id) && !isNull(inputvalue(e)); }, childrenList(ui.elementByID(document, 'page')))); |
| |
| // Append current location properties if known |
| if (!isNull(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 (isNull(doc)) { |
| debug('error on get(button, ' + uri + ')', e); |
| return false; |
| } |
| |
| // Inject data into the page |
| updatepage(docdata(doc)); |
| }); |
| } catch(e) { |
| debug('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 (isNull(doc)) { |
| debug('error on get(timer, ' + uri + ')', e); |
| return false; |
| } |
| |
| // Inject data into the page |
| updatepage(docdata(doc)); |
| }); |
| } catch(e) { |
| debug('error in intervalHandler()', e); |
| return true; |
| } |
| } |
| |
| /** |
| * Setup an interval timer. |
| */ |
| function setupIntervalHandler(msec) { |
| intervalHandler(); |
| try { |
| return setInterval(intervalHandler, msec); |
| } catch(e) { |
| debug('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 (isNull(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 (isNull(animationData)) { |
| if (gettingAnimationData) |
| return true; |
| var uri = compquery(); |
| return animationcomp.get(uri, function(doc, e) { |
| if (isNull(doc)) { |
| debug('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) { |
| debug('error in animationHandler()', e); |
| return true; |
| } |
| } |
| |
| /** |
| * Setup an animation. |
| */ |
| function setupAnimationHandler(msec, loop) { |
| animationLoop = loop; |
| animationHandler(); |
| try { |
| return setInterval(animationHandler, msec); |
| } catch(e) { |
| debug('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 (isNull(doc)) { |
| debug('error on get(location, ' + uri + ')', e); |
| return false; |
| } |
| |
| // Inject data into the page |
| updatepage(docdata(doc)); |
| }); |
| } catch(e) { |
| return locationErrorHandler(e); |
| } |
| } |
| |
| function locationErrorHandler(e) { |
| debug('location error', e); |
| if (!isNull(locationWatch)) { |
| try { |
| navigator.geolocation.clearWatch(locationWatch); |
| } catch(e) {} |
| locationWatch = null; |
| } |
| return true; |
| } |
| |
| /** |
| * Setup a location watch handler. |
| */ |
| function setupLocationHandler() { |
| function installLocationHandler() { |
| if (!isNull(locationWatch)) |
| return true; |
| try { |
| locationWatch = navigator.geolocation.watchPosition(locationHandler, locationErrorHandler); |
| } catch(e) { |
| debug('error in installLocationHandler()', e); |
| } |
| return true; |
| } |
| |
| installLocationHandler(); |
| setInterval(installLocationHandler, 10000); |
| return true; |
| } |
| |
| /** |
| * Handle orientation change. |
| */ |
| document.body.onorientationchange = function(e) { |
| //debug('onorientationchange'); |
| ui.onorientationchange(e); |
| return true; |
| }; |
| |
| /** |
| * Return the composite in an ATOM entry. |
| */ |
| function atomcomposite(doc) { |
| var entry = atom.readATOMEntry(mklist(doc)); |
| if (isNull(entry)) |
| return mklist(); |
| var content = namedElementChild("'content", car(entry)); |
| if (content == null) |
| return mklist(); |
| return elementChildren(content); |
| } |
| |
| /** |
| * Get the app composite. |
| */ |
| function getappcomposite(appname) { |
| return composcomp.get(appname, function(doc, e) { |
| //debug('page get'); |
| if (isNull(doc)) { |
| debug('error in getappcomposite', e); |
| return false; |
| } |
| |
| var compos = atomcomposite(doc); |
| if (isNull(compos)) { |
| |
| // Create a default empty composite if necessary |
| var x = '<composite xmlns="http://docs.oasis-open.org/ns/opencsa/sca/200912" ' + |
| 'targetNamespace="http://app" name="app"></composite>'; |
| compos = readXML(mklist(x)); |
| } |
| appcomposite = compos; |
| |
| // Merge in the app data |
| if (!isNull(apppage)) |
| getappdata(appname, apppage, appcomposite); |
| }); |
| } |
| |
| /** |
| * Initialize the document. |
| */ |
| window.onload = function() { |
| //debug('onload'); |
| ui.onload(); |
| |
| // Initialize the app composite |
| getappcomposite(appname); |
| |
| // Initialize the app page |
| getapppage(appname); |
| |
| return true; |
| }; |
| |
| })(); |
| |
| } catch(e) { |
| debug(e.stack); |
| throw e; |
| } |
| </script> |
| |
| </body> |
| </html> |
| |