diff options
Diffstat (limited to '')
61 files changed, 4559 insertions, 2013 deletions
diff --git a/sca-cpp/trunk/hosting/server/htdocs/account/index.html b/sca-cpp/trunk/hosting/server/htdocs/account/index.html index a0c2e78c31..47c0ea0e9c 100644 --- a/sca-cpp/trunk/hosting/server/htdocs/account/index.html +++ b/sca-cpp/trunk/hosting/server/htdocs/account/index.html @@ -19,19 +19,25 @@ --> <div id="bodydiv" class="body"> -<div class="viewform"> +<div id="viewform" class="viewform"> <form id="userForm"> <table style="width: 100%;"> -<tr><tr><td><b>Photo:</b></td></tr> -<tr><td><img id="userimg" style="width: 50px; height: 50px; vertical-align: top;"></td></tr> -<tr><tr><td style="padding-top: 6px;"><b>Name:</b></td></tr> -<tr><td><input type="text" id="userTitle" class="flatentry" size="30" placeholder="Enter your name" style="width: 300px;"/></td></tr> -<tr><tr><td style="padding-top: 6px;"><b>About Me:</b></td></tr> -<tr><td><textarea id="userDescription" class="flatentry" cols="40" rows="3" placeholder="Enter a short description of yourself" style="width: 300px;"></textarea></td></tr> +<tr><tr><td class="label">Username:</td></tr> +<tr><td><input type="text" id="userName" class="readentry" size="30" readonly="readonly" placeholder="Your username" style="width: 300px;"/></td></tr> +<tr><tr><td class="label">Email:</td></tr> +<tr><td><input type="text" id="userEmail" class="readentry" size="30" readonly="readonly" placeholder="Your email address" style="width: 300px;"/></td></tr> +<tr><tr><td class="label">Picture:</td></tr> +<tr><td><img id="userPicture" style="width: 50px; height: 50px; vertical-align: top;"/><input id="uploadPicture" type="button" class="lightbutton" value="Upload"/><input id="uploadFile" type="file" accept="image/*" style="display:none;"/><span id="refreshingPicture" class="refreshing" style="display:none;"/></td></tr> +<tr><tr><td class="label">Name:</td></tr> +<tr><td><input type="text" id="userFullname" class="flatentry" size="30" placeholder="Your name" style="width: 300px;"/></td></tr> +<tr><tr><td class="label">Bio:</td></tr> +<tr><td><textarea id="userDescription" class="flatentry" cols="40" rows="3" placeholder="About yourself, in fewer than 120 characters" style="width: 300px;"></textarea></td></tr> </table> - <br/> + +<!-- +TODO Disabled for now <table style="width: 100%;"> <tr> <th class="thl thr" style="padding-top: 4px; padding-bottom: 4px; padding-left: 2px; padding-right: 2px; ">Calendar</th> @@ -66,60 +72,73 @@ <tr><td style="padding-right: 2px;"><input type="text" id="name10" class="flatentry" size="10" placeholder="Key name" style="width: 80px;"/></td><td><input type="text" id="value10" class="flatentry" size="2048" placeholder="Key value" style="width: 200px;"/></td></tr> </table> </form> +<br/> +--> </div> <script type="text/javascript"> -(function() { +(function accountbody() { /** - * Init service references. + * Setup page layout. */ -var editorComp = sca.component("Editor"); -var user= sca.defun(sca.reference(editorComp, "user")); -var accounts = sca.reference(editorComp, "accounts"); +(function layout() { + document.title = config.windowtitle() + ' - Account'; + $('viewhead').innerHTML = '<span class="cmenu">' + username + '</span>' + + '<input type="button" class="redbutton plusminus" style="position: absolute; top: 4px; left: 5px;" id="deleteUser" value="-" title="Delete your account" disabled="true"/>'; + if (!ui.isMobile()) + $('viewform').className = 'viewform flatscrollbars'; + $('userName').value = username; +})(); /** - * Set page titles. + * Set images. */ -document.title = config.windowtitle() + ' - Account'; -$('viewhead').innerHTML = '<span class="cmenu">' + username + '</span>'; +$('userPicture').src = ui.b64png(appcache.get('/public/user.b64')); /** - * Set images. + * Initialize service references. */ -$('userimg').src = ui.b64img(appcache.get('/public/user.b64')); +var editorComp = sca.component("Editor"); +var user= sca.defun(sca.reference(editorComp, "user")); +var accounts = sca.reference(editorComp, "accounts"); +var pictures = sca.reference(editorComp, "pictures"); /** * The current account entry and corresponding saved XML content. */ -var accountentry; -var savedaccountentryxml = ''; +var savedacctxml = ''; +var savedpicxml = ''; /** * Get and display the user's account. */ -function getaccount() { - showStatus('Loading'); +(function getacct() { + workingstatus(true); + showstatus('Loading'); return accounts.get('', function(doc) { // Stop now if we didn't get an account if (doc == null) { - showError('Account info not available'); + errorstatus('Account info not available'); + workingstatus(false); return false; } - showOnlineStatus(); - accountentry = car(elementsToValues(atom.readATOMEntry(mklist(doc)))); - $('userTitle').value = cadr(assoc("'title", cdr(accountentry))); + var acctentry = car(elementsToValues(atom.readATOMEntry(mklist(doc)))); + $('userFullname').value = cadr(assoc("'title", acctentry)); + + var acct = cadr(assoc("'content", acctentry)); - var content = cadr(assoc("'content", cdr(accountentry))); - var acct = isNil(content)? mklist() : cdr(content); + var email = assoc("'email", acct); + $('userEmail').value = isNil(email) || isNil(cdr(email))? '' : cadr(email); var desc = assoc("'description", acct); $('userDescription').innerHTML = isNil(desc) || isNil(cdr(desc))? '' : cadr(desc); + /* TODO disabled for now var cal = assoc("'calendar", acct); reduce(function(i, evt) { var sched = assoc("'@schedule", evt); @@ -137,27 +156,126 @@ function getaccount() { $('value' + i).value = isNil(kv)? '' : cadr(kv); return i + 1; }, 1, isNil(keys)? mklist() : cadr(cadr(keys))); + */ + + savedacctxml = car(atom.writeATOMEntry(valuesToElements(mklist(acctentry)))); + return true; + }); + return true; +})(); + +/** + * Get and display the user's picture. + */ +(function getpic() { + workingstatus(true); + showstatus('Loading'); - savedaccountentryxml = car(atom.writeATOMEntry(valuesToElements(mklist(accountentry)))); + return pictures.get('', function(doc) { + // Stop now if we didn't get a picture + if (doc == null) { + errorstatus('Picture not available'); + workingstatus(false); + return false; + } + + var picentry = car(elementsToValues(atom.readATOMEntry(mklist(doc)))); + savedpicxml = car(atom.writeATOMEntry(valuesToElements(mklist(picentry)))); + var content = assoc("'content", picentry); + var picture = assoc("'picture", content); + var img = assoc("'image", picture); + if (!isNil(img)) + $('userPicture').src = cadr(img); + + onlinestatus(); + workingstatus(false); return true; }); + return true; +})(); + +/** + * Refresh picture. + */ +var refreshingpic = false; +function refreshpic() { + if (!refreshingpic) + return false; + $('refreshingPicture').style.display = 'inline-block'; + return pictures.get('', function(doc) { + if (doc == null) { + errorstatus('Picture not available'); + $('refreshingPicture').style.display = 'none'; + refreshingpic = false; + return false; + } + + var picentry = car(elementsToValues(atom.readATOMEntry(mklist(doc)))); + var content = assoc("'content", picentry); + var picture = assoc("'picture", content); + var token = assoc("'token", picture); + + // Update picture + if (isNil(token)) { + var entryxml = car(atom.writeATOMEntry(valuesToElements(mklist(picentry)))); + savedpicxml = entryxml; + var img = assoc("'image", picture); + if (!isNil(img)) + $('userPicture').src = cadr(img); + $('refreshingPicture').style.display = 'none'; + refreshingpic = false; + return true; + } + + // Refresh in 2 secs + return ui.delay(refreshpic, 2000); + }, 'remote'); + return true; } /** * Save the user's account. */ -function save(entryxml) { +function saveacct(entryxml) { + if (isNil(username)) + return false; + workingstatus(true); + showstatus('Saving'); + + savedacctxml = entryxml; + accounts.put('', savedacctxml, function(e) { + if (e) { + showstatus('Local copy'); + workingstatus(false); + return false; + } + + showstatus('Saved'); + workingstatus(false); + return true; + }); + return true; +} + +/** + * Save the user's picture. + */ +function savepic(entryxml) { if (isNil(username)) return false; - showStatus('Saving'); - savedaccountentryxml = entryxml; - accounts.put('', savedaccountentryxml, function(e) { + workingstatus(true); + showstatus('Uploading'); + + savedpicxml = entryxml; + pictures.put('', savedpicxml, function(e) { if (e) { - showStatus('Local copy'); + showstatus('Local copy'); + workingstatus(false); return false; } - showStatus('Saved'); + showstatus('Uploaded'); + workingstatus(false); return true; }); return true; @@ -167,8 +285,27 @@ function save(entryxml) { * Handle a change event */ function onaccountchange() { - var title = $('userTitle').value; - var desc = $('userDescription').value; + + // Validate user input + var title = $('userFullname').value; + if (title.length == 0) { + errorstatus('Name cannot be empty'); + return false; + } + if (title.length > 40) { + errorstatus('Name cannot be longer than 40 characters'); + return false; + } + + var email = $('userEmail').value; + + var description = $('userDescription').value; + if (description.length > 120) { + errorstatus('Bio cannot be longer than 120 characters'); + return false; + } + + /* TODO disabled for now var cal = map(function(i) { var sched = $('sched' + i).value; var svc = $('service' + i).value; @@ -180,18 +317,24 @@ function onaccountchange() { return mklist("'key", mklist("'@name", kn), mklist("'@value", kv)); }, range(1, 11)); - var accountentry = mklist("'entry", mklist("'title", title != ''? title : username), mklist("'id", username), - mklist("'content", mklist("'account", mklist("'description", desc), cons("'keys", keys), cons("'calendar", cal)))); - var entryxml = car(atom.writeATOMEntry(valuesToElements(mklist(accountentry)))); - if (savedaccountentryxml == entryxml) + var acctentry = mklist("'entry", mklist("'title", title != ''? title : username), mklist("'id", username), + mklist("'content", mklist("'account", mklist("'email", email), mklist("'description", description), cons("'keys", keys), cons("'calendar", cal)))); + */ + + var acctentry = mklist("'entry", mklist("'title", title != ''? title : username), mklist("'id", username), + mklist("'content", mklist("'account", mklist("'email", email), mklist("'description", description)))); + var entryxml = car(atom.writeATOMEntry(valuesToElements(mklist(acctentry)))); + if (savedacctxml == entryxml) return false; - showStatus('Modified'); - return save(entryxml); + showstatus('Modified'); + return saveacct(entryxml); } -$('userTitle').onchange = onaccountchange; +$('userFullname').onchange = onaccountchange; $('userDescription').onchange = onaccountchange; + +/* TODO disabled for now map(function(i) { $('sched' + i).onchange = onaccountchange; $('service' + i).onchange = onaccountchange; @@ -202,6 +345,19 @@ map(function(i) { $('value' + i).onchange = onaccountchange; return true; }, range(1, 11)); +*/ + +/** + * Handle a key event. + */ +var lastkeyup = null; +$('userFullname').onkeyup = $('userDescription').onkeyup = function() { + var t = new Date().getTime(); + lastkeyup = t; + ui.delay(function() { + return t == lastkeyup? onaccountchange() : true; + }, 2000); +}; /** * Handle a form submit event. @@ -212,9 +368,96 @@ $('userForm').onsubmit = function() { }; /** - * Get the user's account. + * Read and upload icon file. + */ +function readpic(files) { + if (!files || files.length == 0) + return false; + if (!files[0].type.match('image.*')) { + errorstatus('Please select an image'); + return false; + } + workingstatus(true); + showstatus('Loading'); + + // Read the selected file into a 50x50 image + return ui.readimage(files[0], + function(e) { + errorstatus('Couldn\'t read the file'); + workingstatus(false); + }, + function(p) { + showstatus('Loading ' + p + '%'); + }, + function(url) { + // Update the user picture + $('userPicture').src = url; + showstatus('Loaded'); + + // Now upload it + ui.delay(function() { + var picentry = mklist("'entry", mklist("'title", username), mklist("'id", username), mklist("'author", username), mklist("'content", mklist("'picture", mklist("'image", url)))); + var entryxml = car(atom.writeATOMEntry(valuesToElements(mklist(picentry)))); + if (savedpicxml == entryxml) { + onlinestatus(); + workingstatus(false); + return false; + } + return savepic(entryxml); + }); + }, 50, 50); +} + +/** + * Upload a picture in an email. */ -getaccount(); +function emailpicture() { + + // Generate and put a picture email upload token + workingstatus(true); + showstatus('Uploading'); + var token = uuid4(); + var picentry = mklist("'entry", mklist("'title", username), mklist("'id", username), mklist("'author", username), mklist("'content", mklist("'picture", mklist("'token", token)))); + var entryxml = car(atom.writeATOMEntry(valuesToElements(mklist(picentry)))); + pictures.put('', entryxml, function(e) { + if (e) { + showstatus('Local copy'); + workingstatus(false); + return false; + } + workingstatus(false); + + // Open the email app + var mailto = safeb64encode('p/' + username + '/' + token); + ui.navigate('mailto:' + mailto + '@' + topdomainname(window.location.hostname) + '?subject=Email to upload&body=Paste picture here', '_self'); + + // Refresh app icon + refreshingpic = true; + return ui.delay(refreshpic, 500); + }, 'remote'); +} + +/** + * Handle picture upload events. + */ +$('uploadPicture').onclick = function() { + if (ui.isMobile()) + return emailpicture(); + return $('uploadFile').click(); +}; +$('uploadFile').onchange = function(e) { + return readpic(e.target.files); +}; +$('userPicture').ondrag = function(e) { + e.stopPropagation(); + e.preventDefault(); + e.dataTransfer.dropEffect = 'copy'; +}; +$('userPicture').ondrop = function(e) { + e.stopPropagation(); + e.preventDefault(); + return readpic(e.dataTransfer.files); +}; })(); </script> diff --git a/sca-cpp/trunk/hosting/server/htdocs/app/cache-template.cmf b/sca-cpp/trunk/hosting/server/htdocs/app/cache/cache-template.cmf index 5881cf83dd..40da327179 100644 --- a/sca-cpp/trunk/hosting/server/htdocs/app/cache-template.cmf +++ b/sca-cpp/trunk/hosting/server/htdocs/app/cache/cache-template.cmf @@ -4,7 +4,7 @@ CACHE MANIFEST # App resources /favicon.ico -/public/iframe-min.html +/login/ /public/img.png /public/notauth/ /public/notfound/ diff --git a/sca-cpp/trunk/hosting/server/htdocs/app/index.html b/sca-cpp/trunk/hosting/server/htdocs/app/index.html index cddf4fb477..cd033118a3 100644 --- a/sca-cpp/trunk/hosting/server/htdocs/app/index.html +++ b/sca-cpp/trunk/hosting/server/htdocs/app/index.html @@ -17,37 +17,51 @@ * specific language governing permissions and limitations * under the License. --> -<html manifest="cache-manifest.cmf"> +<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="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"/> +--> +<link rel="apple-touch-icon-precomposed" href="/public/touchicon.png"/> <base href="/"/> <script type="text/javascript"> -(function() { +try { + +(function apphead() { window.appcache = {}; /** * Get and cache a resource. */ -appcache.get = function(uri) { +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(u); } catch(e) {} + 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", u, false); + 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) { @@ -59,7 +73,7 @@ appcache.get = function(uri) { if (window.debug) debug('http error', u, 'No-Content'); return null; } - try { ls.setItem(u, http.responseText); } catch(e) {} + try { ls.setItem('ui.r.' + u, http.responseText); } catch(e) {} return http.responseText; } if (window.debug) debug('http error', u, http.status, http.statusText); @@ -74,46 +88,32 @@ appcache.get = function(uri) { /** * Load Javascript and CSS. */ -(function() { +(function appboot() { 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. - */ -(function() { - -if (document.location.protocol == 'https:' && !hasauthcookie()) - document.location = '/login/'; +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="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"> -(function() { +try { + +(function appbody() { /** * Get the app name @@ -186,7 +186,7 @@ applicationCache.addEventListener('updateready', function(e) { applicationCache.addEventListener('cached', function(e) { //debug('appcache cached', e); map(function(res) { - appcache.get(res[0]); + appcache.get(res[0], 'remote'); }, appresources); }, false); @@ -316,7 +316,8 @@ function setwidgetvalue(e, dv) { var nesheet = document.createElement('style'); nesheet.id = 'style_' + e.id; nesheet.type = 'text/css'; - document.head.appendChild(nesheet); + var head = document.getElementsByTagName('head')[0]; + head.appendChild(nesheet); nesheet.innerHTML = s; } else { esheet.innerHTML = s; @@ -331,9 +332,9 @@ function setwidgetvalue(e, dv) { // Restart current animation if necessary if (!isNil(aname) && ce.style.webkitAnimationName == aname) { ce.style.webkitAnimationName = ''; - setTimeout(function() { + ui.async(function restartanimation() { ce.style.webkitAnimationName = aname; - }, 0); + }); } return a; } @@ -930,10 +931,7 @@ function setupLocationHandler() { */ document.body.onorientationchange = function(e) { //debug('onorientationchange'); - - // Scroll to the top and hide the address bar - window.scrollTo(0, 0); - + ui.onorientationchange(e); return true; }; @@ -980,14 +978,9 @@ function getappcomposite(appname) { /** * Initialize the document. */ -function onload() { +window.onload = function() { //debug('onload'); - - // Scroll to the top and hide the address bar - window.scrollTo(0, 0); - - // Show the page - document.body.style.visibility = 'visible'; + ui.onload(); // Initialize the app composite getappcomposite(appname); @@ -996,17 +989,16 @@ function onload() { getapppage(appname); return true; -} - -onload(); +}; })(); -</script> -<div id="footdiv" class="fsection"> -</div> +} catch(e) { + debug(e.stack); + throw e; +} +</script> -</div> </body> </html> diff --git a/sca-cpp/trunk/hosting/server/htdocs/cache-template.cmf b/sca-cpp/trunk/hosting/server/htdocs/cache/cache-template.cmf index 8d9aa26f7d..8347c5553a 100644 --- a/sca-cpp/trunk/hosting/server/htdocs/cache-template.cmf +++ b/sca-cpp/trunk/hosting/server/htdocs/cache/cache-template.cmf @@ -5,7 +5,7 @@ CACHE MANIFEST # App resources / /favicon.ico -/public/iframe-min.html +/login/ /public/img.png /public/notauth/ /public/notfound/ diff --git a/sca-cpp/trunk/hosting/server/htdocs/cache/index.html b/sca-cpp/trunk/hosting/server/htdocs/cache/index.html new file mode 100644 index 0000000000..f5c81791f2 --- /dev/null +++ b/sca-cpp/trunk/hosting/server/htdocs/cache/index.html @@ -0,0 +1,51 @@ +<!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> +<script type="text/javascript"> +applicationCache.addEventListener('checking', function(e) { + return window.parent.onappcachechecking(e); +}, false); +applicationCache.addEventListener('error', function(e) { + return window.parent.onappcacheerror(e); +}, false); +applicationCache.addEventListener('noupdate', function(e) { + return window.parent.onappcachenoupdate(e); +}, false); +applicationCache.addEventListener('downloading', function(e) { + return window.parent.onappcachedownloading(e); +}, false); +applicationCache.addEventListener('progress', function(e) { + return window.parent.onappcacheprogress(e); +}, false); +applicationCache.addEventListener('updateready', function(e) { + return window.parent.onappcacheupdateready(e); +}, false); +applicationCache.addEventListener('cached', function(e) { + return window.parent.onappcachecached(e); +}, false); +window.onload = function() { + window.parent.onloadappcache(); +}; +</script> +</head> +<body> +</body> +</html> diff --git a/sca-cpp/trunk/hosting/server/htdocs/clone/index.html b/sca-cpp/trunk/hosting/server/htdocs/clone/index.html index 0a2f7733bc..c6a9658ce0 100644 --- a/sca-cpp/trunk/hosting/server/htdocs/clone/index.html +++ b/sca-cpp/trunk/hosting/server/htdocs/clone/index.html @@ -19,29 +19,24 @@ --> <div id="bodydiv" class="body"> -<div class="viewform"> +<div id="viewform" class="viewform"> <form id="cloneAppForm"> <table style="width: 100%;"> -<tr><td><b>New App Name:</b></td></tr> -<tr><td><input type="text" id="appName" class="flatentry" size="15" autocapitalize="off" placeholder="Your app name"/></td></tr> -<tr><tr><td style="padding-top: 6px;"><b>Icon:</b></td></tr> -<tr><td><img id="appimg" style="width: 50px; height: 50px; vertical-align: top;"></td></tr> -<tr><tr><td style="padding-top: 6px;"><b>Title:</b></td></tr> -<tr><td><input type="text" id="appTitle" class="flatentry" size="30" placeholder="Enter the title of your app" style="width: 300px;"/></td></tr> -<tr><tr><td style="padding-top: 6px;"><b>Description:</b></td></tr> -<tr><td><textarea id="appDescription" class="flatentry" cols="40" rows="3" placeholder="Enter a short description of your app" style="width: 300px;"></textarea></td></tr> -<tr><td> -<input id="cloneAppOKButton" type="submit" class="graybutton bluebutton" style="font-weight: bold;" value="Clone" title="Clone the app"/> +<tr><td class="label">New URL:</td></tr> +<tr><td><span id="hostname" class="readentry"></span><input type="text" id="appName" class="flatentry" size="18" autocapitalize="off" placeholder="New app name"/></td></tr> +<tr><td style="padding-top: 20px;"> +<input id="cloneAppOKButton" type="submit" class="bluebutton" style="font-weight: bold;" value="Clone" title="Clone this app"/> <input id="cloneAppCancelButton" type="button" class="graybutton" value="Cancel"/> </td></tr> </table> </form> +<br/> </div> <script type="text/javascript"> -(function() { +(function clonebody() { /** * Get the app name. @@ -49,20 +44,20 @@ var appname = ui.fragmentParams(location)['app']; /** - * Set page titles. + * Setup page layout. */ -document.title = config.windowtitle() + ' - ' + config.clone() + ' - ' + appname; -$('viewhead').innerHTML = '<span class="smenu">' + config.clone() + ' ' + appname + '</span>'; -$('cloneAppOKButton').value = config.clone(); -$('cloneAppOKButton').title = config.clone() + ' this app'; - -/** - * Set images. - */ -$('appimg').src = ui.b64img(appcache.get('/public/app.b64')); +(function layout() { + document.title = config.windowtitle() + ' - ' + config.clone() + ' - ' + appname; + $('viewhead').innerHTML = '<span class="smenu">' + config.clone() + ' ' + appname + '</span>'; + if (!ui.isMobile()) + $('viewform').className = 'viewform flatscrollbars'; + $('hostname').innerHTML = window.location.hostname + '/'; + $('cloneAppOKButton').value = config.clone(); + $('cloneAppOKButton').title = config.clone() + ' this app'; +})(); /** - * Init service references. + * Initialize service references. */ var editorComp = sca.component("Editor"); var apps = sca.reference(editorComp, "apps"); @@ -71,50 +66,60 @@ var apps = sca.reference(editorComp, "apps"); * The current app entry and corresponding saved XML content. */ var appentry; -var savedappentryxml = ''; +var savedappxml = ''; /** - * Get and display an app. + * Get and display the requested app. */ -function getapp(name) { - if (isNil(name)) +(function getapp() { + if (isNil(appname)) return false; - showStatus('Loading'); + workingstatus(true); + showstatus('Loading'); - return apps.get(name, function(doc) { + return apps.get(appname, function(doc) { // Stop now if we didn't get the app if (doc == null) { - showError('App not available'); + errorstatus('Couldn\'t get the app info'); + workingstatus(false); return false; } - showOnlineStatus(); - - appentry = doc != null? car(elementsToValues(atom.readATOMEntry(mklist(doc)))) : mklist("'entry", mklist("'title", ''), mklist("'id", name)); - $('appTitle').value = cadr(assoc("'title", cdr(appentry))); - var content = cadr(assoc("'content", cdr(appentry))); - var description = assoc("'description", content); - $('appDescription').value = isNil(description) || isNil(cadr(description))? '' : cadr(description); - savedappentryxml = car(atom.writeATOMEntry(valuesToElements(mklist(appentry)))); + + appentry = doc != null? car(elementsToValues(atom.readATOMEntry(mklist(doc)))) : mklist("'entry", mklist("'title", ''), mklist("'id", appname)); + var content = cadr(assoc("'content", appentry)); + savedappxml = car(atom.writeATOMEntry(valuesToElements(mklist(appentry)))); + + onlinestatus(); + workingstatus(false); return true; }); -} +})(); /** * Save an app. */ -function save(name, entryxml) { - showStatus('Saving'); - savedappentryxml = entryxml; - apps.put(name, savedappentryxml, function(e) { +function saveapp(name, entryxml) { + workingstatus(true); + showstatus('Saving'); + + savedappxml = entryxml; + apps.put(name, savedappxml, function(e) { if (e) { - showStatus('Local copy'); + if (e.code && e.code == 404) { + errorstatus('App name is taken, please pick another name'); + workingstatus(false); + return false; + } + showstatus('Local copy'); + workingstatus(false); return false; } - showStatus('Saved'); + showstatus('Saved'); + workingstatus(false); - // Open it in the page editor - ui.navigate('/#view=page&app=' + name, '_view'); + // Open the app in the page editor + ui.navigate('/#view=info&app=' + name, '_view'); return false; }); return false; @@ -124,19 +129,36 @@ function save(name, entryxml) { * Clone an app. */ $('cloneAppForm').onsubmit = function() { + + // Validate app name var name = $('appName').value; - if (name == '') { - showError('Missing app name'); + if (name.length < 3 || name.length > 10) { + errorstatus('App name must be between 3 and 10 characters'); + return false; + } + name = name.toLowerCase(); + var anum = name.split('').reduce(function(p, c, i, a) { return p && ((c >= 'a' && c <= 'z') || (c >= '0' && c<= '9')); }, true); + if (!anum) { + errorstatus('App name is taken, please pick another name'); + return false; + } + if (name.charAt(0) < 'a' || name.charAt(0) > 'z') { + errorstatus('App name must start with a letter'); + return false; + } + + // Check reserved app names + var reserved = mklist('account', 'app', 'cache', 'clone', 'create', 'delete', 'graph', 'home', 'login', 'new', 'page', 'proxy', 'public', 'private', 'info', 'store'); + if (!isNil(assoc(name, map(function(r) { return mklist(r, r); }, reserved)))) { + errorstatus('App name is taken, please pick another name'); return false; } - showStatus('Saving'); // Clone the app - var title = $('appTitle').value; - var description = $('appDescription').value; - appentry = mklist("'entry", mklist("'title", title != ''? title : name), mklist("'id", appname), mklist("'content", mklist("'stats", mklist("'description", description)))); + showstatus('Modified'); + appentry = mklist("'entry", mklist("'title", name), mklist("'id", appname), mklist("'author", username)); var entryxml = car(atom.writeATOMEntry(valuesToElements(mklist(appentry)))); - return save(name, entryxml); + return saveapp(name, entryxml); }; /** @@ -146,11 +168,6 @@ $('cloneAppCancelButton').onclick = function() { history.back(); }; -/** - * Get the current app. - */ -getapp(appname); - })(); </script> diff --git a/sca-cpp/trunk/hosting/server/htdocs/config.js b/sca-cpp/trunk/hosting/server/htdocs/config.js index 70d3ea1195..355174e6f7 100644 --- a/sca-cpp/trunk/hosting/server/htdocs/config.js +++ b/sca-cpp/trunk/hosting/server/htdocs/config.js @@ -32,7 +32,7 @@ config.pagetitle = function() { }; config.hometitle = function() { - return '<br/><span style="font-weight: bold;">Create SCA Composite Apps</span><br/><br/>'; + return '<br/><span style="font-weight: bold;">Create SCA Apps</span><br/><br/>'; }; config.clone = function() { diff --git a/sca-cpp/trunk/hosting/server/htdocs/create/index.html b/sca-cpp/trunk/hosting/server/htdocs/create/index.html index d8d2b30f3c..a11c0958f5 100644 --- a/sca-cpp/trunk/hosting/server/htdocs/create/index.html +++ b/sca-cpp/trunk/hosting/server/htdocs/create/index.html @@ -19,43 +19,38 @@ --> <div id="bodydiv" class="body"> -<div class="viewform"> +<div id="viewform" class="viewform"> <form id="createAppForm"> <table style="width: 100%;"> -<tr><td><b>App Name:</b></td></tr> -<tr><td><input type="text" id="appName" class="flatentry" size="15" autocapitalize="off" placeholder="Your app name"/></td></tr> -<tr><tr><td style="padding-top: 6px;"><b>App Icon:</b></td></tr> -<tr><td><img id="appimg" style="width: 50px; height: 50px; vertical-align: top;"></td></tr> -<tr><tr><td style="padding-top: 6px;"><b>App Title:</b></td></tr> -<tr><td><input type="text" id="appTitle" class="flatentry" size="30" placeholder="Enter the title of your app" style="width: 300px;"/></td></tr> -<tr><tr><td style="padding-top: 6px;"><b>Description:</b></td></tr> -<tr><td><textarea id="appDescription" class="flatentry" cols="40" rows="3" placeholder="Enter a short description of your app" style="width: 300px;"></textarea></td></tr> -<tr><td> -<input id="createAppOKButton" type="submit" class="graybutton bluebutton" style="font-weight: bold;" value="Create" title="Create the app"/> +<tr><td class="label">URL:</td></tr> +<tr><td><span id="hostname" class="readentry"></span><input type="text" id="appName" class="flatentry" size="18" autocapitalize="off" placeholder="New app name"/></td></tr> +<tr><td style="padding-top: 20px;"> +<input id="createAppOKButton" type="submit" class="bluebutton" style="font-weight: bold;" value="Create" title="Create the app"/> <input id="createAppCancelButton" type="button" class="graybutton" value="Cancel"/> </td></tr> </table> </form> +<br/> </div> <script type="text/javascript"> -(function() { +(function createbody() { /** - * Set page titles. + * Setup page layout. */ -document.title = config.windowtitle() + ' - Create App'; -$('viewhead').innerHTML = '<span class="smenu">Create an App</span>'; - -/** - * Set images. - */ -$('appimg').src = ui.b64img(appcache.get('/public/app.b64')); +(function layout() { + document.title = config.windowtitle() + ' - New App'; + $('viewhead').innerHTML = '<span class="smenu">New App</span>'; + if (!ui.isMobile()) + $('viewform').className = 'viewform flatscrollbars'; + $('hostname').innerHTML = window.location.hostname + '/'; +})(); /** - * Init service references. + * Initialize service references. */ var editorComp = sca.component("Editor"); var apps = sca.reference(editorComp, "apps"); @@ -64,23 +59,32 @@ var apps = sca.reference(editorComp, "apps"); * The current app entry and corresponding saved XML content. */ var appentry; -var savedappentryxml = ''; +var savedappxml = ''; /** * Save an app. */ -function save(name, entryxml) { - showStatus('Saving'); - savedappentryxml = entryxml; - apps.put(name, savedappentryxml, function(e) { +function saveapp(name, entryxml) { + workingstatus(true); + showstatus('Saving'); + + savedappxml = entryxml; + apps.put(name, savedappxml, function(e) { if (e) { - showStatus('Local copy'); + if (e.code && e.code == 404) { + errorstatus('App name is taken, please pick another name'); + workingstatus(false); + return false; + } + showstatus('Local copy'); + workingstatus(false); return false; } - showStatus('Saved'); + showstatus('Saved'); + workingstatus(false); - // Open it in the page editor - ui.navigate('/#view=page&app=' + name, '_view'); + // Open the app in the page editor + ui.navigate('/#view=info&app=' + name, '_view'); return false; }); return false; @@ -90,19 +94,36 @@ function save(name, entryxml) { * Create an app. */ $('createAppForm').onsubmit = function() { + + // Validate app name var name = $('appName').value; - if (name == '') { - showError('Missing app name'); + if (name.length < 3 || name.length > 10) { + errorstatus('App name must be between 3 and 10 characters'); + return false; + } + name = name.toLowerCase(); + var anum = name.split('').reduce(function(p, c, i, a) { return p && ((c >= 'a' && c <= 'z') || (c >= '0' && c<= '9')); }, true); + if (!anum) { + errorstatus('App name can only use numbers and letters'); + return false; + } + if (name.charAt(0) < 'a' || name.charAt(0) > 'z') { + errorstatus('App name must start with a letter'); + return false; + } + + // Check reserved app names + var reserved = mklist('account', 'app', 'cache', 'clone', 'create', 'delete', 'graph', 'home', 'login', 'new', 'page', 'proxy', 'public', 'private', 'info', 'store'); + if (!isNil(assoc(name, map(function(r) { return mklist(r, r); }, reserved)))) { + errorstatus('App name is taken, please pick another name'); return false; } - showStatus('Modified'); // Clone the 'new' app template - var title = $('appTitle').value; - var description = $('appDescription').value; - appentry = mklist("'entry", mklist("'title", title != ''? title : name), mklist("'id", 'new'), mklist("'content", mklist("'stats", mklist("'description", description)))); + showstatus('Modified'); + appentry = mklist("'entry", mklist("'title", name), mklist("'id", 'new'), mklist("'author", username)); var entryxml = car(atom.writeATOMEntry(valuesToElements(mklist(appentry)))); - return save(name, entryxml); + return saveapp(name, entryxml); }; /** @@ -115,7 +136,7 @@ $('createAppCancelButton').onclick = function() { /** * Show the status. */ -showOnlineStatus(); +onlinestatus(); })(); </script> diff --git a/sca-cpp/trunk/hosting/server/htdocs/delete/index.html b/sca-cpp/trunk/hosting/server/htdocs/delete/index.html index 5a668af401..81cfa0b625 100644 --- a/sca-cpp/trunk/hosting/server/htdocs/delete/index.html +++ b/sca-cpp/trunk/hosting/server/htdocs/delete/index.html @@ -19,31 +19,32 @@ --> <div id="bodydiv" class="body"> -<div class="viewform"> +<div id="viewform" class="viewform"> <form id="deleteAppForm"> <table style="width: 100%;"> -<tr><tr><td style="padding-top: 6px;"><b>App Icon:</b></td></tr> -<tr><td><img id="appimg" style="width: 50px; height: 50px; vertical-align: top;"></td></tr> -<tr><tr><td style="padding-top: 6px;"><b>App Title:</b></td></tr> -<tr><td><input type="text" id="appTitle" class="flatentry" size="30" readonly="readonly" style="width: 300px;"/></td></tr> -<tr><tr><td style="padding-top: 6px;"><b>Author:</b></td></tr> -<tr><td><span id="appAuthor"></span></td></tr> -<tr><tr><td style="padding-top: 6px;"><b>Updated:</b></td></tr> -<tr><td><span id="appUpdated"></span></td></tr> -<tr><tr><td style="padding-top: 6px;"><b>Description:</b></td></tr> -<tr><td><textarea id="appDescription" class="flatentry" cols="40" rows="3" readonly="readonly" style="width: 300px;"></textarea></td></tr> +<tr><tr><td class="label">URL:</td></tr> +<tr><td><input type="text" id="appURL" class="readentry" size="30" readonly="readonly" placeholder="App URL" style="width: 300px;"/></td></tr> +<tr><tr><td class="label">Icon:</td></tr> +<tr><td><img id="appIcon" style="width: 50px; height: 50px; vertical-align: top;"></td></tr> +<tr><tr><td class="label">Author:</td></tr> +<tr><td><img id="authorPhoto" style="width: 50px; height: 50px; vertical-align: middle;"><input type="text" id="appAuthor" class="readentry" size="30" readonly="readonly" placeholder="Author of the app" style="width: 248px;"/></td></tr> +<tr><tr><td class="label">Updated:</td></tr> +<tr><td><input type="text" id="appUpdated" class="readentry" size="30" readonly="readonly" placeholder="App update date" style="width: 300px;"/></td></tr> +<tr><tr><td class="label">Description:</td></tr> +<tr><td><textarea id="appDescription" class="readentry" cols="40" rows="3" readonly="readonly" placeholder="No description for this app" style="width: 300px;"></textarea></td></tr> <tr><td> -<input id="deleteAppOKButton" type="submit" class="graybutton bluebutton" style="font-weight: bold;" value="Delete" title="Delete the app"/> +<input id="deleteAppOKButton" type="submit" class="bluebutton" style="font-weight: bold;" value="Delete" title="Delete the app"/> <input id="deleteAppCancelButton" type="button" class="graybutton" value="Cancel"/> </td></tr> </table> </form> +<br/> </div> <script type="text/javascript"> -(function() { +(function deletebody() { /** * Get the app name. @@ -51,18 +52,24 @@ var appname = ui.fragmentParams(location)['app']; /** - * Set page titles. + * Setup page layout. */ -document.title = config.windowtitle() + ' - ' + 'Delete' + ' - ' + appname; -$('viewhead').innerHTML = '<span class="smenu">Delete ' + appname + '</span>'; +(function layout() { + document.title = config.windowtitle() + ' - ' + 'Delete' + ' - ' + appname; + $('viewhead').innerHTML = '<span class="smenu">Delete ' + appname + '</span>'; + if (!ui.isMobile()) + $('viewform').className = 'viewform flatscrollbars'; + $('appURL').value = window.location.hostname + '/' + appname + '/'; +})(); /** * Set images. */ -$('appimg').src = ui.b64img(appcache.get('/public/app.b64')); +$('appIcon').src = ui.b64png(appcache.get('/public/app.b64')); +$('authorPhoto').src = ui.b64png(appcache.get('/public/user.b64')); /** - * Init service references. + * Initialize service references. */ var editorComp = sca.component("Editor"); var apps = sca.reference(editorComp, "apps"); @@ -73,49 +80,56 @@ var apps = sca.reference(editorComp, "apps"); var appentry; /** - * Get and display an app. + * Get and display the requested app. */ -function getapp(name) { - if (isNil(name)) +(function getapp() { + if (isNil(appname)) return false; - showStatus('Loading'); + workingstatus(true); + showstatus('Loading'); - return apps.get(name, function(doc) { + return apps.get(appname, function(doc) { // Stop now if we didn't get the app if (doc == null) { - showError('App not available'); + errorstatus('Couldn\'t get the app info'); + workingstatus(false); return false; } - showOnlineStatus(); - appentry = doc != null? car(elementsToValues(atom.readATOMEntry(mklist(doc)))) : mklist("'entry", mklist("'title", ''), mklist("'id", name)); - $('appTitle').value = cadr(assoc("'title", cdr(appentry))); - $('appAuthor').innerHTML = cadr(assoc("'author", cdr(appentry))); - $('appUpdated').innerHTML = cadr(assoc("'updated", cdr(appentry))); - var content = cadr(assoc("'content", cdr(appentry))); + appentry = doc != null? car(elementsToValues(atom.readATOMEntry(mklist(doc)))) : mklist("'entry", mklist("'title", ''), mklist("'id", appname)); + var author = cadr(assoc("'author", appentry)); + $('appAuthor').value = author.split('@')[0]; + $('appUpdated').value = xmldatetime(cadr(assoc("'updated", appentry))).toLocaleDateString(); + var content = cadr(assoc("'content", appentry)); var description = assoc("'description", content); $('appDescription').value = isNil(description) || isNil(cadr(description))? '' : cadr(description); + + onlinestatus(); + workingstatus(false); return true; }); -} +})(); /** - * Delete an app. + * Delete the app. */ $('deleteAppForm').onsubmit = function() { - showStatus('Deleting'); + workingstatus(true); + showstatus('Deleting'); // Delete the app apps.del(appname, function(e) { if (e) { - showStatus('Local copy'); + showstatus('Local copy'); + workingstatus(false); return false; } - showOnlineStatus(); + onlinestatus(); + workingstatus(false); // Return to the app store - ui.navigate('/#view=store', '_view'); + ui.navigate('/#view=store&category=myapps&idx=5', '_view'); return false; }); return false; @@ -128,11 +142,6 @@ $('deleteAppCancelButton').onclick = function() { history.back(); }; -/** - * Get the current app. - */ -getapp(appname); - })(); </script> diff --git a/sca-cpp/trunk/hosting/server/htdocs/favicon-16.xcf b/sca-cpp/trunk/hosting/server/htdocs/favicon-16.xcf Binary files differnew file mode 100644 index 0000000000..e43dcba033 --- /dev/null +++ b/sca-cpp/trunk/hosting/server/htdocs/favicon-16.xcf diff --git a/sca-cpp/trunk/hosting/server/htdocs/favicon-32.xcf b/sca-cpp/trunk/hosting/server/htdocs/favicon-32.xcf Binary files differnew file mode 100644 index 0000000000..c1736338ec --- /dev/null +++ b/sca-cpp/trunk/hosting/server/htdocs/favicon-32.xcf diff --git a/sca-cpp/trunk/hosting/server/htdocs/favicon.ico b/sca-cpp/trunk/hosting/server/htdocs/favicon.ico Binary files differindex a7b502b9e1..bd60462963 100644 --- a/sca-cpp/trunk/hosting/server/htdocs/favicon.ico +++ b/sca-cpp/trunk/hosting/server/htdocs/favicon.ico diff --git a/sca-cpp/trunk/hosting/server/htdocs/graph/index.html b/sca-cpp/trunk/hosting/server/htdocs/graph/index.html index d360336375..d01bfa1c02 100644 --- a/sca-cpp/trunk/hosting/server/htdocs/graph/index.html +++ b/sca-cpp/trunk/hosting/server/htdocs/graph/index.html @@ -19,13 +19,13 @@ --> <div id="bodydiv" class="body"> -<div id="contentdiv" class="viewcontent" style="width: 2500px;"> -<div id="graphdiv" class="graphdiv" style="top: 0px; left: -2500px; width: 5000px; height: 5000px;"></div> -<div id="playdiv" style="position: absolute; top: 0x; left: 0px; width: 2500px; height: 5000px; visibility: hidden"></div> +<div id="viewcontent" class="viewcontent" style="width: 100%;"> +<div id="graphdiv" class="graphcontent" style="top: 0px; left: -2500px; width: 5000px; height: 5000px;"></div> +<div id="playdiv" style="position: absolute; top: 0x; left: 0px; width: 2500px; height: 5000px; display: none"></div> </div> <script type="text/javascript"> -(function() { +(function graphbody() { /** * Get the current app name. @@ -49,11 +49,14 @@ document.title = config.windowtitle() + ' - ' + config.logic() + ' - ' + appname * Set header div. */ $('viewhead').innerHTML = '<span id="appTitle" class="cmenu">' + appname + '</span>' + -'<input type="button" id="deleteCompButton" title="Delete a component" class="graybutton redbutton plusminus" style="position: absolute; top: 4px; left: 5px;" disabled="true" value="-"/>' + -'<span style="position: absolute; top: 0px; left: 45px; right: 115px; padding: 0px; background: transparent;"><input id="compValue" type="text" value="" class="flatentry" title="Component value" autocapitalize="off" placeholder="Value" style="position: absolute; left: 0px; top: 4px; width: 100%; visibility: hidden;" readonly="readonly"/></span>' + +'<input type="button" id="deleteCompButton" title="Delete a component" class="redbutton plusminus" style="position: absolute; top: 4px; left: 5px;" disabled="true" value="-"/>' + +'<span style="position: absolute; top: 0px; left: 45px; right: 115px; padding: 0px; background: transparent;"><input id="compValue" type="text" value="" class="flatentry" title="Component value" autocapitalize="off" placeholder="Value" style="position: absolute; left: 0px; top: 4px; width: 100%; display: none;" readonly="readonly"/></span>' + '<input type="button" id="playCompButton" title="View component value" class="graybutton plusminus" style="position: absolute; top: 4px; right: 75px;" disabled="true" value=">"/>' + -'<input type="button" id="copyCompButton" title="Copy a component" class="graybutton bluebutton" style="position: absolute; top: 4px; right: 40px;" disabled="true" value="C"/>' + -'<input type="button" id="addCompButton" title="Add a component" class="graybutton bluebutton plusminus" style="position: absolute; top: 4px; right: 5px;" disabled="true" value="+"/>'; +'<input type="button" id="copyCompButton" title="Copy a component" class="bluebutton" style="position: absolute; top: 4px; right: 40px;" disabled="true" value="C"/>' + +'<input type="button" id="addCompButton" title="Add a component" class="bluebutton plusminus" style="position: absolute; top: 4px; right: 5px;" disabled="true" value="+"/>'; + +if (!ui.isMobile()) + $('viewcontent').className = 'viewcontent flatscrollbars'; /** * Track the current app composite, author, and saved XML content. @@ -159,8 +162,8 @@ graph.mkedit = function(graphdiv, pos, atitle, cvalue, cadd, ccopy, cdelete, onc graph.dragged = false; graph.selected = null; cvalue.readOnly = true; - cvalue.style.visibility = 'hidden'; - atitle.style.visibility = 'visible'; + cvalue.style.display = 'none'; + atitle.style.display = 'block'; ccopy.disabled = true; cdelete.disabled = true; cadd.disabled = !editable; @@ -182,6 +185,54 @@ graph.mkedit = function(graphdiv, pos, atitle, cvalue, cadd, ccopy, cdelete, onc } /** + * Render component move animation. + */ + function onmoveanimation() { + //debug('onmoveanimation'); + + // Stop animation if we're not dragging an element anymore + if (graph.dragging == null) + return true; + + // Request the next animation frame + ui.animation(onmoveanimation); + + // Nothing to do if the selected component has not moved + if (graph.moveX == graph.dragX && graph.moveY == graph.dragY) + return true; + + // Remember that the selected component has been dragged + graph.dragged = true; + + // Cut wire to the dragged component + if (graph.dragging.parentNode != graphdiv) { + var compos = scdl.composite(graphdiv.compos); + setElement(compos, graph.sortcompos(graph.cutwire(graph.dragging, compos, graphdiv))); + + // Bring component to the top + graph.bringtotop(graph.dragging, graphdiv); + } + + // Calculate new position of the dragged component + var gpos = graph.relpos(graph.dragging); + var newX = gpos.x + (graph.moveX - graph.dragX); + var newY = gpos.y + (graph.moveY - graph.dragY); + if (newX >= graph.palcx) + graph.dragX = graph.moveX + else + newX = graph.palcx; + if (newY >= 0) + graph.dragY = graph.moveY; + else + newY = 0; + + // Move it + graph.move(graph.dragging, graph.mkpath().pos(newX, newY)); + + return false; + }; + + /** * Handle a mouse down or touch start event. */ function onmousedown(e) { @@ -209,6 +260,9 @@ graph.mkedit = function(graphdiv, pos, atitle, cvalue, cadd, ccopy, cdelete, onc graph.dragX = pos.screenX; graph.dragY = pos.screenY; + // Start move animation + ui.animation(onmoveanimation); + e.preventDefault(); return true; }; @@ -393,69 +447,28 @@ graph.mkedit = function(graphdiv, pos, atitle, cvalue, cadd, ccopy, cdelete, onc /** * Handle a mouse or touch move event. */ - function onmousemove(e) { - if (graph.dragging == null) - return true; - - // Ignore duplicate mouse move events - if (graph.moveX == graph.dragX && graph.moveY == graph.dragY) - return true; - - // Remember that the component was dragged - graph.dragged = true; - - // Cut wire to component - if (graph.dragging.parentNode != graphdiv) { - var compos = scdl.composite(graphdiv.compos); - setElement(compos, graph.sortcompos(graph.cutwire(graph.dragging, compos, graphdiv))); - - // Bring component to the top - graph.bringtotop(graph.dragging, graphdiv); - } - - // Calculate new position of dragged element - var gpos = graph.relpos(graph.dragging); - var newX = gpos.x + (graph.moveX - graph.dragX); - var newY = gpos.y + (graph.moveY - graph.dragY); - if (newX >= graph.palcx) - graph.dragX = graph.moveX - else - newX = graph.palcx; - if (newY >= 0) - graph.dragY = graph.moveY; - else - newY = 0; - - // Move the dragged element - graph.move(graph.dragging, graph.mkpath().pos(newX, newY)); - - return false; - }; - if (!ui.isMobile()) { window.onmousemove = function(e) { //debug('onmousemove'); - // Remember mouse position + // Record mouse position graph.moveX = e.screenX; graph.moveY = e.screenY; - - return onmousemove(e); + if (graph.dragging == null) + return true; + return false; } } else { graphdiv.ontouchmove = function(e) { //debug('ontouchmove'); - // Remember touch position + // Record touch position var pos = e.touches[0]; - if (graph.moveX == pos.screenX && graph.moveY == pos.screenY) - return true; graph.moveX = pos.screenX; graph.moveY = pos.screenY; - if (graph.moveX == graph.dragX && graph.moveY == graph.dragY) + if (graph.dragging == null) return true; - - return onmousemove(e); + return false; } } @@ -465,7 +478,7 @@ graph.mkedit = function(graphdiv, pos, atitle, cvalue, cadd, ccopy, cdelete, onc function onvaluechange() { if (graph.selected == null) return false; - if (graphdiv.parentNode.style.visibility == 'hidden') + if (graphdiv.parentNode.style.display == 'none') return false; // Change component name and refactor references to it @@ -496,8 +509,8 @@ graph.mkedit = function(graphdiv, pos, atitle, cvalue, cadd, ccopy, cdelete, onc graph.setproperty(graph.selected.comp, cvalue.value); var hasprop = graph.hasproperty(graph.selected.comp); cvalue.readOnly = (hasprop? false : true) || !editable; - cvalue.style.visibility = hasprop? 'visible' : 'hidden'; - atitle.style.visibility = hasprop? 'hidden' : 'visible'; + cvalue.style.display = hasprop? 'block' : 'none'; + atitle.style.display = hasprop? 'none' : 'block'; cvalue.value = graph.property(graph.selected.comp); // Refresh the composite @@ -597,10 +610,11 @@ graph.mkedit = function(graphdiv, pos, atitle, cvalue, cadd, ccopy, cdelete, onc return false; }; - // Create a hidden SVG element to help compute the width - // of component and reference titles + // Create a hidden element to help compute the width of + // component and reference titles graph.offtitles = document.createElement('span'); graph.offtitles.style.visibility = 'hidden'; + graph.offtitles.style.display = 'block'; graph.offtitles.position = 'absolute'; graph.offtitles.top = -500; graph.offtitles.width = 500; @@ -792,8 +806,8 @@ graph.compselect = function(g, s, atitle, cvalue, ccopy, cdelete) { if (isNil(g) || !s) { cvalue.value = ''; cvalue.readOnly = true; - cvalue.style.visibility = 'hidden'; - atitle.style.visibility = 'visible'; + cvalue.style.display = 'none'; + atitle.style.display = 'block'; ccopy.disabled = true; cdelete.disabled = true; if (isNil(g)) @@ -806,8 +820,8 @@ graph.compselect = function(g, s, atitle, cvalue, ccopy, cdelete) { cvalue.value = graph.hasproperty(g.comp)? graph.property(g.comp) : g.id; cvalue.readOnly = false || !editable; - cvalue.style.visibility = 'visible'; - atitle.style.visibility = 'hidden'; + cvalue.style.display = 'block'; + atitle.style.display = 'none'; ccopy.disabled = false || !editable; cdelete.disabled = false || !editable; @@ -1817,13 +1831,15 @@ var bpalette = null; function getapp(name, g) { if (isNil(name)) return false; - showStatus('Loading'); + workingstatus(true); + showstatus('Loading'); return composites.get(name, function(doc) { // Stop now if we didn't get a composite if (doc == null) { - showError('App not available'); + errorstatus('Couldn\'t get the app info'); + workingstatus(false); return false; } @@ -1849,7 +1865,12 @@ function getapp(name, g) { author = elementValue(namedElementChild("'author", composentry)); editable = author == username; cadd.disabled = !editable; - showStatus(editable? onlineStatus() : 'Read only'); + if (editable) + onlinestatus(); + else + showstatus('Read only'); + + workingstatus(false); return true; }); } @@ -1912,17 +1933,21 @@ function installpalette(name, pos, g, bg, palette, gpalettes) { * Save the current composite. */ function save(savexml) { - showStatus('Saving'); + workingstatus(true); + showstatus('Saving'); + savedcomposxml = savexml; var entry = '<?xml version="1.0" encoding="UTF-8"?>\n' + '<entry xmlns="http://www.w3.org/2005/Atom">' + '<title type="text">' + appname + '</title><id>' + appname + '</id><author><email>' + author + '</email></author>' + '<content type="application/xml">' + savedcomposxml + '</content></entry>'; composites.put(appname, entry, function(e) { if (e) { - showStatus('Local copy'); + showstatus('Local copy'); + workingstatus(false); return false; } - showStatus('Saved'); + showstatus('Saved'); + workingstatus(false); return false; }); return true; @@ -1938,17 +1963,17 @@ function oncomposchange(prop) { var newxml = car(writeXML(composite, false)); if (savedcomposxml == newxml) return false; - showStatus('Modified'); + showstatus('Modified'); // Save property changes right away if (prop) return save(newxml); // Autosave other changes after 1 second - showStatus('Modified'); - setTimeout(function() { + showstatus('Modified'); + ui.delay(function autosave() { if (savedcomposxml == newxml) { - showStatus('Saved'); + showstatus('Saved'); return false; } return save(newxml); @@ -1997,7 +2022,7 @@ function showdata(gcomp) { cplay.value = '<'; gvisible = false; pdiv.innerHTML = ''; - pdiv.style.visibility = 'visible'; + pdiv.style.display = 'block'; // Get the component result data var comp = sca.component(gcomp.id, appname); @@ -2030,9 +2055,9 @@ function showdata(gcomp) { return displaydata(t, '100%'); }); - setTimeout(function() { - graphdiv.style.visibility = 'hidden' - }, 0); + ui.async(function hidegraphdiv() { + graphdiv.style.display = 'none' + }); return true; } @@ -2043,13 +2068,13 @@ function showgraph(gcomp) { if (gvisible) return true; cplay.value = '>'; - graphdiv.style.visibility = 'visible' + graphdiv.style.display = 'block' gvisible = true; graph.compselect(gcomp, true, atitle, cvalue, ccopy, cdelete); - setTimeout(function() { - pdiv.style.visibility = 'hidden'; + ui.async(function hideplaydiv() { + pdiv.style.display = 'none'; pdiv.innerHTML = ''; - }, 0); + }); return true; } diff --git a/sca-cpp/trunk/hosting/server/htdocs/home/home.b64 b/sca-cpp/trunk/hosting/server/htdocs/home/home.b64 deleted file mode 100644 index 9131135881..0000000000 --- a/sca-cpp/trunk/hosting/server/htdocs/home/home.b64 +++ /dev/null @@ -1 +0,0 @@ -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
\ No newline at end of file diff --git a/sca-cpp/trunk/hosting/server/htdocs/home/home.png b/sca-cpp/trunk/hosting/server/htdocs/home/home.png Binary files differdeleted file mode 100644 index 8f5a0b0d86..0000000000 --- a/sca-cpp/trunk/hosting/server/htdocs/home/home.png +++ /dev/null diff --git a/sca-cpp/trunk/hosting/server/htdocs/home/index.html b/sca-cpp/trunk/hosting/server/htdocs/home/index.html index 130c05fda0..d7a098e998 100644 --- a/sca-cpp/trunk/hosting/server/htdocs/home/index.html +++ b/sca-cpp/trunk/hosting/server/htdocs/home/index.html @@ -19,7 +19,7 @@ --> <div id="bodydiv" class="body"> -<div class="viewcontent" style="margin-left: auto; margin-right: auto; text-align: center;"> +<div id="viewcontent" class="viewcontent" style="margin-left: auto; margin-right: auto; text-align: center;"> <br/> <div id="hometitle" style="font-size: 28px;"></div> @@ -29,22 +29,27 @@ <div id="homeanimation" style="width: 320px; height: 280px; padding: 0px; margin: 0px auto;"></div> --> -<input type="button" class="graybutton bluebutton" style="font-size: 21px; padding: 10px; height: 50px;" id="getstarted" title="Get Started" value="Get Started"/> +<input type="button" class="bluebutton" style="font-size: 21px; padding: 10px; height: 50px;" id="getstarted" title="Get Started" value="Get Started"/> <br/><br/> -<div class="note">Requires Safari 5+, Chrome 11+, Firefox 4+, IE 9+</div> +<div class="note">Requires Safari 5+, Chrome 11+, Firefox 4+ or IE 9+</div> +<br/> </div> <script type="text/javascript"> -(function() { +(function homebody() { /** - * Set page titles. + * Setup page layout. */ -document.title = config.windowtitle(); -$('viewhead').innerHTML = '<span class="bcmenu">' + config.pagetitle() + '</span>'; -$('hometitle').innerHTML = config.hometitle(); +(function layout() { + document.title = config.windowtitle(); + $('viewhead').innerHTML = '<span class="bcmenu">' + config.pagetitle() + '</span>'; + $('hometitle').innerHTML = config.hometitle(); + if (!ui.isMobile()) + $('viewcontent').className = 'viewcontent flatscrollbars'; +})(); $('getstarted').onclick = function() { return ui.navigate('/#view=store', '_view'); @@ -53,22 +58,24 @@ $('getstarted').onclick = function() { /** * Display animation. */ -var anim = $('homeanimation'); -if (!isNil(anim)) { - anim.style.background = 'url(\'' + ui.b64img(appcache.get('/home/home.b64')) + '\')'; - var bgpos = 0; - setInterval(function() { - bgpos = bgpos -280; - if (bgpos == -2800) - bgpos = 0; - anim.style.backgroundPosition = '0px ' + ui.pixpos(bgpos); - }, 2000); -} +(function homeanimation() { + var anim = $('homeanimation'); + if (!isNil(anim)) { + anim.style.background = 'url(\'' + ui.b64png(appcache.get('/home/home.b64')) + '\')'; + var bgpos = 0; + setInterval(function homeanimation() { + bgpos = bgpos -280; + if (bgpos == -2800) + bgpos = 0; + anim.style.backgroundPosition = '0px ' + ui.pixpos(bgpos); + }, 2000); + } +})(); /** * Show the status. */ -showOnlineStatus(); +onlinestatus(); })(); </script> diff --git a/sca-cpp/trunk/hosting/server/htdocs/index.html b/sca-cpp/trunk/hosting/server/htdocs/index.html index e3e046136d..6ea6f80939 100644 --- a/sca-cpp/trunk/hosting/server/htdocs/index.html +++ b/sca-cpp/trunk/hosting/server/htdocs/index.html @@ -17,50 +17,69 @@ * specific language governing permissions and limitations * under the License. --> -<html manifest="/cache-manifest.cmf"> +<html> <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="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"/> +--> +<link rel="apple-touch-icon-precomposed" href="/public/touchicon.png"/> <base href="/"/> <script type="text/javascript"> -(function() { +try { + +(function roothead() { window.appcache = {}; /** * Get and cache a resource. */ -appcache.get = function(uri) { +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(u); } catch(e) {} - if (item != null && item != '') - return item; + if (mode != 'remote') { + var item = null; + try { item = ls.getItem('ui.r.' + u); } catch(e) {} + if (item != null && item != '') + return item; + if (mode == 'local') + return null; + } // Get resource from network //if (window.debug) debug('appcache.get', u); var http = new XMLHttpRequest(); - http.open("GET", u, false); + http.open("GET", mode == 'remote'? (u + '?t=' + new Date().getTime() + '&r=' + Math.random()) : u, false); http.setRequestHeader("Accept", "*/*"); http.send(null); if (http.status == 200) { - if (http.getResponseHeader("X-Login") != null) { + var xl = http.getResponseHeader("X-Login"); + if (xl != null && xl != '') { 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) { + } + var ct = http.getResponseHeader("Content-Type"); + if (http.responseText == '' || ct == null || ct == '') { if (window.debug) debug('http error', u, 'No-Content'); return null; } - try { ls.setItem(u, http.responseText); } catch(e) {} + try { ls.setItem('ui.r.' + u, http.responseText); } catch(e) {} return http.responseText; } if (window.debug) debug('http error', u, http.status, http.statusText); @@ -83,82 +102,68 @@ appcache.remove = function(uri) { /** * Load Javascript and CSS. */ -(function() { +(function rootboot() { -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'))); +window.eval.call(window, 'try {\n' + appcache.get('/all-min.js') + '\n' + appcache.get('/config-min.js') + '\n} catch(e) { console.log(e.stack); throw e; }\n'); +ui.includeCSS(appcache.get('/ui-min.css')); // Disable cache for testing //lstorage.enabled = false; })(); -/** - * Redirect to login page if not signed in. - */ -(function() { - -if (document.location.protocol == 'https:' && !hasauthcookie()) - document.location = '/login/'; - -})(); +} catch(e) { + if (window.debug) debug(e.stack); + throw e; +} </script> </head> <body class="delayed"> -<div id="mainbodydiv" class="mainbody"> - -<div id="headdiv" class="hsection"> -<script type="text/javascript"> -(function() { -$('headdiv').appendChild(ui.declareScript(appcache.get('/config-min.js'))); - -})(); -</script> +<div id="menucontainer" class="tbarmenu"> +<div id="menu"></div> </div> -<div id="menubackground" class="tbarbackground fixed"></div> -<div id="menu" class="tbarmenu fixed"></div> +<div id="viewheadcontainer" class="viewhead"> +<div id="viewhead"></div> +</div> -<div id="viewheadbackground" class="viewheadbackground fixed"></div> -<div id="viewhead" class="viewhead fixed"></div> +<div id="working" class="working" style="display: none;"></div> <div id="viewcontainer"></div> -<div id="viewfootbackground" class="viewfootbackground fixed"></div> -<div id="viewfoot" class="viewfoot fixed"></div> -<div id="status" class="status fixed" style="visibility: hidden;"></div> +<div id="viewfootcontainer" class="viewfoot"> +<div id="viewfoot"></div> +<div id="status"></div> +</div> + +<div id="installer" class="installer"></div> <script type="text/javascript"> -(function() { +try { -/** - * Init service references. - */ -var editorComp = sca.component("Editor"); -var user= sca.defun(sca.reference(editorComp, "user")); -var accounts = sca.reference(editorComp, "accounts"); +(function rootbody() { /** - * Set page title. + * Setup page layout. */ -document.title = config.windowtitle(); +(function layout() { + + document.title = config.windowtitle(); + $('viewcontainer').className = ui.isMobile()? 'viewcontainer3dm' : 'viewcontainer3d'; + $('status').className = ui.isMobile()? 'status3dm' : 'status3d'; + +})(); /** - * Init div variables. + * Initialize service references. */ -var bdiv = $('mainbodydiv'); -var mdiv = $('menu'); -var hdiv = $('viewhead'); -var vcontainer = $('viewcontainer'); -vcontainer.className = ui.isMobile()? 'viewcontainer3dm' : 'viewcontainer3d'; -var fdiv = $('viewfoot'); +var editorComp = sca.component("Editor"); +var user = sca.defun(sca.reference(editorComp, "user")); +var accounts = sca.reference(editorComp, "accounts"); /** - * The current user name and account entry. + * The current user name. */ window.username = 'anonymous'; @@ -169,134 +174,95 @@ var storecat = 'top'; var storeidx = 0; /** - * Pre-fetch app resources. + * Populate cache with app resources. */ var appresources = [ ['/all-min.js'], ['/ui-min.css'], ['/account/', 9], - ['/clone/', 3], - ['/create/', 2], - ['/delete/', 3], + ['/clone/', 4], + ['/create/', 3], + ['/delete/', 4], ['/graph/', 5], ['/config-min.js'], ['/home/', 0], - ['/home/home.b64'], ['/page/', 4], ['/public/app.b64'], ['/public/config-min.js'], - ['/public/grid72.b64'], - ['/public/iframe-min.html'], ['/public/img.b64'], + ['/public/rate.b64'], + ['/public/ratings.b64'], ['/public/user.b64'], - ['/stats/', 2], + ['/rate/', 4], + ['/search/', 2], + ['/info/', 3], ['/store/', 1] ]; /** - * Show a status message. + * Init status message area. */ -window.showStatus = function(s, c) { - //debug('status', s); - var sdiv = $('status'); - if (isNil(sdiv)) - return s; - sdiv.innerHTML = '<span class="' + (c? c : 'okstatus') + '">' + s + '</span>'; - sdiv.className = 'status fixed'; - sdiv.style.visibility = 'visible'; +(function initstatus() { + if (isNil($('status'))) + return; + $('status').style.display = 'none'; function divtransitionend(e) { - e.target.style.visibility = 'hidden'; - e.target.className = 'status fixed'; + e.target.style.display = 'none'; + e.target.className = ui.isMobile()? 'status3dm' : 'status3d'; + e.target.error = false; } - if (!sdiv.addedTransitionEnd) { - sdiv.addEventListener('webkitTransitionEnd', divtransitionend, false); - sdiv.addEventListener('transitionend', divtransitionend, false); - sdiv.addedTransitionEnd = true; - } - sdiv.className = 'statusout3 fixed'; - return s; -} + $('status').addEventListener('webkitTransitionEnd', divtransitionend, false); + $('status').addEventListener('transitionend', divtransitionend, false); +})(); /** - * Show an error message. + * Show a status message. */ -window.showError = function(s) { - //debug('error', s); - return showStatus(s, 'errorstatus'); -} +window.showstatus = function(s, c) { + //debug('show status', s); + if (isNil($('status')) || $('status').error) + return s; + $('status').innerHTML = '<span class="' + (c? c : 'okstatus') + '">' + s + '</span>'; + $('status').className = ui.isMobile()? 'status3dm' : 'status3d'; + $('status').style.display = 'block'; + $('status').error = c == 'errorstatus'; + if ($('status').delay) + ui.cancelDelay($('status').delay); + $('status').delay = ui.delay(function hidestatus() { + $('status').className = ui.isMobile()? 'statusout3dm' : 'statusout3d'; + $('status').error = false; + }, 3000); + return s; +}; /** - * Show the online/offline status. + * Show an error message. */ -window.showOnlineStatus = function() { - return navigator.onLine? showStatus('Online') : showError('Offline'); -} +window.errorstatus = function(s) { + //debug('error', s); + return showstatus(s, 'errorstatus'); +}; /** - * Handle application cache events. + * Show working status. */ -applicationCache.addEventListener('checking', function(e) { - //debug('appcache checking', e); - showStatus('Checking'); -}, false); -applicationCache.addEventListener('error', function(e) { - //debug('appcache error', e); - showOnlineStatus(); -}, false); -applicationCache.addEventListener('noupdate', function(e) { - //debug('appcache noupdate', e); - showOnlineStatus(); -}, false); -applicationCache.addEventListener('downloading', function(e) { - //debug('appcache downloading', e); - showStatus('Updating'); -}, false); -applicationCache.addEventListener('progress', function(e) { - //debug('appcache progress', e); - showStatus('Updating'); -}, false); -applicationCache.addEventListener('updateready', function(e) { - //debug('appcache updateready', e); - try { - applicationCache.swapCache(); - } catch(e) {} - showOnlineStatus(); - //debug('appcache swapped', e); - - // Update offline resources in local storage and reload the page - map(function(res) { - showStatus('Updating'); - appcache.remove(res[0]); - appcache.get(res[0]); - }, append(appresources, config.appresources())); - window.location.reload(); -}, false); -applicationCache.addEventListener('cached', function(e) { - //debug('appcache cached', e); - showOnlineStatus(); - - // Install offline resources in local storage - map(function(res) { - showStatus('Installing'); - appcache.remove(res[0]); - appcache.get(res[0]); - }, append(appresources, config.appresources())); -}, false); +window.workingstatus = function(w, c) { + //debug('show working', w); + if (isNil($('working'))) + return w; + if (!ui.isMobile()) + $('working').style.top = ui.pixpos(Math.round(window.clientHeight / 2)); + $('working').style.display = w? 'block' : 'none'; + return w; +}; /** - * Handle network offline/online events. + * Show the online/offline status. */ -window.addEventListener('offline', function(e) { - //debug('going offline'); - showStatus('Offline'); -}, false); -window.addEventListener('online', function(e) { - //debug('going online'); - showStatus('Online'); -}, false); - -//debug(navigator.onLine? 'online' : 'offline'); +window.onlinestatus = function() { + return navigator.onLine? (ui.isMobile()? showstatus('Online') : showstatus('Online')) : errorstatus('Offline'); +}; /** * Handle view transitions. @@ -351,32 +317,36 @@ function mkviewdiv(cname) { * Return the last visited location. */ function lastvisited() { - if (username != lstorage.getItem('ui.lastvisit.user')) + if (username != lstorage.getItem('ui.v.user')) return null; - return lstorage.getItem('ui.lastvisit.url'); + return lstorage.getItem('ui.v.url'); } /** * Build and show the menu bar. */ -function showmenu(mdiv, view, appname) { - mdiv.innerHTML = ui.menubar( +function showmenu(view, appname) { + $('menu').innerHTML = ui.menubar( append(mklist(ui.menu('menuhome', 'Home', '/', '_view', view == 'home'), - ui.menu('menustore', 'Store', '/#view=store&category=' + storecat + '&idx=' + storeidx, '_view', view === 'store')), + ui.menu('menustore', 'Store', '/#view=store&category=' + storecat + '&idx=' + storeidx, '_view', view == 'store'), + ui.menu('menusearch', 'Search', '/#view=search', '_view', view == 'search')), (isNil(appname) || appname == 'undefined')? mklist() : mklist( - ui.menu('menustats', 'Stats', '/#view=stats&app=' + appname, '_view', view == 'stats'), - ui.menu('menupage', 'Page', '/#view=page&app=' + appname, '_view', view == 'page'), + ui.menu('menuinfo', 'Info', '/#view=info&app=' + appname, '_view', view == 'info'), + ui.menu('menupage', 'Edit', '/#view=page&app=' + appname, '_view', view == 'page') + /* TODO disabled for now + , ui.menu('menulogic', config.logic(), '/#view=graph&app=' + appname, '_view', view == 'graph'), - ui.menu('menurun', '<span class="greentext" style="font-weight: bold">Run!</span>', '/' + appname + '/', '_blank', false))), + ui.menu('menurun', '<span class="greentext" style="font-weight: bold">Run!</span>', '/' + appname + '/', '_blank', false) + */ + )), (isNil(appname) || appname == 'undefined')? mklist( - hasauthcookie()? ui.menufunc('menusignout', 'Sign out', 'return logout();', false) : ui.menu('menusignin', 'Sign in', '/login/', '_self', false), + ui.menufunc('menusignout', 'Sign out', 'return logout();', false), ui.menu('menuaccount', 'Account', '/#view=account', '_view', view == 'account')) : mklist()); - if (fdiv.innerHTML == '') - fdiv.innerHTML = config.viewfoot(); + $('viewfoot').innerHTML = config.viewfoot(); } /** @@ -390,7 +360,7 @@ function getaccount() { return false; var accountentry = car(elementsToValues(atom.readATOMEntry(mklist(doc)))); - username = cadr(assoc("'id", cdr(accountentry))); + username = cadr(assoc("'id", accountentry)); return true; } @@ -401,8 +371,8 @@ function showview(url) { //debug('showview', url); // Save last visited location - lstorage.setItem('ui.lastvisit.user', username); - lstorage.setItem('ui.lastvisit.url', url); + lstorage.setItem('ui.v.user', username); + lstorage.setItem('ui.v.url', url); // Determine the view to show var params = ui.fragmentParams(url); @@ -426,10 +396,11 @@ function showview(url) { // Show the menu bar var appname = params['app']; - showmenu(mdiv, view, appname); + showmenu(view, appname); - // Scroll to the top and hide the address bar - window.scrollTo(0, 0); + // Make sure that the document is visible + if (document.body.style.display != 'block') + document.body.style.display = 'block'; // Start to unload the front view and create a new view if (ui.isMobile()) { @@ -444,21 +415,17 @@ function showview(url) { var vdiv = mkviewdiv(vtransition + 'viewloading3dm'); var vdoc = appcache.get(uri); vdiv.innerHTML = vdoc; - vcontainer.appendChild(vdiv); + $('viewcontainer').appendChild(vdiv); map(ui.evalScript, ui.innerScripts(vdiv)); - // Make sure the top document is visible - if (document.body.style.visibility != 'visible') - document.body.style.visibility = 'visible'; - - setTimeout(function() { + ui.async(function mtransitionview() { // Transition the old view out if (!isNil(ovdiv)) ovdiv.className = vtransition + 'viewunloaded3dm'; // Transition the new view in vdiv.className = 'viewloaded3dm'; - }, 100); + }); } else { // Prepare current view for transition out @@ -470,21 +437,17 @@ function showview(url) { var vdiv = mkviewdiv('viewloading3d'); var vdoc = appcache.get(uri); vdiv.innerHTML = vdoc; - vcontainer.appendChild(vdiv); + $('viewcontainer').appendChild(vdiv); map(ui.evalScript, ui.innerScripts(vdiv)); - // Make sure the top document is visible - if (document.body.style.visibility != 'visible') - document.body.style.visibility = 'visible'; - - setTimeout(function() { + ui.async(function transitionview() { // Transition the new view in vdiv.className = 'viewloaded3d'; // Transition the old view out if (!isNil(ovdiv)) ovdiv.parentNode.removeChild(ovdiv); - }, 100); + }); } // Track the current visible view @@ -501,12 +464,14 @@ function updatelocation(url) { // Add url to the history if necessary if (url != ui.pathandparams(location)) { - history.pushState(null, null, url); - //debug('pushstate', history.length); + if (history.pushState) { + history.pushState(null, null, url); + //debug('pushstate', history.length); + } // Update the location hash if necessary var f = ui.fragment(url); - if (f != '' && f != location.hash) { + if (f != location.hash) { location.hash = f; //debug('hash', f); } @@ -520,6 +485,10 @@ function updatelocation(url) { window.onnavigate = function(url) { //debug('onnavigate', url); + // Cleanup installer + if ($('installer').innerHTML != '') + $('installer').innerHTML = ''; + // Update the browser window location updatelocation(url); @@ -541,12 +510,11 @@ window.onloginredirect = function(e) { */ window.logout = function() { // Clear session cookie and user-specific local storage entries - clearauthcookie(); lstorage.removeItem('/r/Editor/accounts'); lstorage.removeItem('/r/Editor/dashboards'); - document.location = '/login/'; + document.location = '/logout/dologout/'; return false; -} +}; /** * Handle history. @@ -555,10 +523,13 @@ window.addEventListener('popstate', function(e) { //debug('onpopstate', history.length); var furl = ui.fragment(location); var url = location.pathname + (furl == ''? '' : '#' + furl); - - // Show the current view if (url == viewurl) return true; + + // Cleanup element lookups memoized in current document + ui.unmemo$(); + + // Show the current view return showview(url); }, false); @@ -567,10 +538,13 @@ window.addEventListener('hashchange', function(e) { //debug('onhashchange'); var furl = ui.fragment(location); var url = location.pathname + (furl == ''? '' : '#' + furl); - - // Show the current view if (url == viewurl) return true; + + // Cleanup element lookups memoized in current document + ui.unmemo$(); + + // Show the current view return showview(url); }, false); @@ -580,18 +554,128 @@ window.addEventListener('hashchange', function(e) { */ document.body.onorientationchange = function(e) { //debug('onorientationchange'); - ui.onorientationchange(e); - - // Resize menu and view header - mdiv.style.width = ui.pixpos(document.documentElement.clientWidth); - hdiv.style.width = ui.pixpos(document.documentElement.clientWidth); - return true; + return ui.onorientationchange(e); }; /** + * Install the application cache. + */ +(function installappcache() { + if (ui.isMobile()) { + // On mobile devices, trigger usage of an application cache manifest + window.onappcachechecking = function(e) { + //debug('appcache checking', e); + workingstatus(true); + showstatus('Checking'); + }; + window.onappcacheerror = function(e) { + //debug('appcache error', e); + onlinestatus(); + workingstatus(false); + }; + window.onappcachenoupdate = function(e) { + //debug('appcache noupdate', e); + onlinestatus(); + workingstatus(false); + }; + window.onappcachedownloading = function(e) { + //debug('appcache downloading', e); + workingstatus(true); + showstatus('Updating'); + }; + window.onappcacheprogress = function(e) { + //debug('appcache progress', e); + workingstatus(true); + showstatus('Updating'); + }; + window.onappcacheupdateready = function(e) { + //debug('appcache updateready', e); + try { + applicationCache.swapCache(); + } catch(e) {} + onlinestatus(); + workingstatus(false); + //debug('appcache swapped', e); + + // Update offline resources in local storage and reload the page + map(function(res) { + showstatus('Updating'); + appcache.remove(res[0]); + appcache.get(res[0], 'remote'); + }, append(appresources, config.appresources())); + window.location.reload(); + }; + window.onappcachecached = function(e) { + //debug('appcache cached', e); + onlinestatus(); + workingstatus(false); + + // Install offline resources in local storage + map(function(res) { + showstatus('Installing'); + appcache.remove(res[0]); + appcache.get(res[0], 'remote'); + }, append(appresources, config.appresources())); + }; + + window.onloadappcache = function() { + //debug('appcache iframe loaded'); + }; + + ui.delay(function() { + $('installer').innerHTML = '<iframe src="/cache/" class="installer"></iframe>'; + }); + + } else { + // On non-mobile devices, check for cache-manifest changes ourselves. + workingstatus(true); + showstatus('Checking'); + var lcmf = appcache.get('/cache/cache-manifest.cmf', 'local'); + var rcmf = appcache.get('/cache/cache-manifest.cmf', 'remote'); + if (lcmf == rcmf) { + onlinestatus(); + workingstatus(false); + return true; + } + + //debug('cache-manifest changed, reloading'); + ui.delay(function() { + workingstatus(true); + showstatus('Updating'); + ui.delay(function() { + workingstatus(true); + showstatus('Updating'); + map(function(res) { + appcache.remove(res[0]); + appcache.get(res[0], 'remote'); + }, append(appresources, config.appresources())); + if (!isNil(lcmf)) { + //debug('reloading'); + window.location.reload(); + } + onlinestatus(); + workingstatus(false); + }); + }); + } +})(); + +/** + * Handle network offline/online events. + */ +window.addEventListener('offline', function(e) { + //debug('going offline'); + showstatus('Offline'); +}, false); +window.addEventListener('online', function(e) { + //debug('going online'); + showstatus('Online'); +}, false); + +/** * Initialize the document. */ -function onload() { +window.onload = function() { //debug('onload', history.length); ui.onload(); @@ -625,16 +709,15 @@ function onload() { if (url == viewurl) return true; return showview(url); -} - -onload(); +}; })(); -</script> -<div id="footdiv" class="fsection"> -</div> +} catch(e) { + debug(e.stack); + throw e; +} +</script> -</div> </body> </html> diff --git a/sca-cpp/trunk/hosting/server/htdocs/info/index.html b/sca-cpp/trunk/hosting/server/htdocs/info/index.html new file mode 100644 index 0000000000..0d72062719 --- /dev/null +++ b/sca-cpp/trunk/hosting/server/htdocs/info/index.html @@ -0,0 +1,494 @@ +<!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. +--> +<div id="bodydiv" class="body"> + +<div id="viewform" class="viewform"> + +<form id="appForm"> +<table style="width: 100%;"> +<tr><td class="label">URL:</td></tr> +<tr><td><input type="text" id="appURL" class="readentry" size="30" readonly="readonly" placeholder="App URL" style="width: 300px;"/></td></tr> +<tr><td class="label">Icon:</td></tr> +<tr><td><img id="appIcon" style="width: 50px; height: 50px; vertical-align: top;"/><input id="uploadIcon" type="button" class="lightbutton" value="Upload" style="display:none;"/><input id="uploadFile" type="file" accept="image/*" style="display: none;"/><span id="refreshingIcon" class="refreshing" style="display:none;"/></td></tr> +<tr><td class="label">Author:</td></tr> +<tr><td><img id="authorPicture" style="width: 50px; height: 50px; vertical-align: middle;"/><input type="text" id="appAuthor" class="readentry" size="30" readonly="readonly" placeholder="Author of the app" style="width: 248px;"/></td></tr> +<tr><td class="label">Rating:</td></tr> +<tr><td><span id="appRating" class="ratings"> </span><input id="rateApp" type="button" class="lightbutton" value="Rate this app"/></td></tr> +<tr><td><input type="text" id="appRatings" class="readentry" size="20" readonly="readonly" placeholder="Number of ratings" style="font-size: 12px;"/></td></tr> +<tr><td class="label">Updated:</td></tr> +<tr><td><input type="text" id="appUpdated" class="readentry" size="30" readonly="readonly" placeholder="App update date" style="width: 300px;"/></td></tr> +<tr><td class="label">Description:</td></tr> +<tr><td><textarea id="appDescription" class="readentry" cols="40" rows="3" readonly="readonly" placeholder="Short description of the app" style="width: 300px;"></textarea></td></tr> +</table> +</form> +<br/> + +</div> + +<script type="text/javascript"> +(function infobody() { + +/** + * Get the app name. + */ +var appname = ui.fragmentParams(location)['app']; + +/** + * Setup page layout. + */ +(function layout() { + document.title = config.windowtitle() + ' - Info - ' + appname; + $('viewhead').innerHTML = '<span id="appname" class="cmenu">' + appname + '</span>' + + '<input type="button" class="redbutton plusminus" style="position: absolute; top: 4px; left: 5px;" id="deleteApp" value="-" title="Delete this app" disabled="true"/>' + + '<span style="position: absolute; top: 0px; right: 5px;">' + + '<input type="button" class="greenbutton" id="runApp" value="Run" title="Run this app"/>' + + '<input type="button" class="bluebutton" id="cloneApp" value="'+ config.clone() +'" title="' + config.clone() + ' this app"/>' + + '</span>'; + if (!ui.isMobile()) + $('viewform').className = 'viewform flatscrollbars'; + $('appURL').value = window.location.hostname + '/' + appname + '/'; + + $('viewform').appendChild(ui.declareCSS( + '.ratings { ' + + 'background: url(\'' + ui.b64png(appcache.get('/public/ratings.b64')) + '\'); ' + + 'vertical-align: middle; width: 50px; height: 14px; display: inline-block; ' + + ' }')); +})(); + +/** + * Set images. + */ +(function drawImages() { + $('appIcon').src = ui.b64png(appcache.get('/public/app.b64')); + $('authorPicture').src = ui.b64png(appcache.get('/public/user.b64')); +})(); + +/** + * Initialize service references. + */ +var editorComp = sca.component("Editor"); +var apps = sca.reference(editorComp, "apps"); +var icons = sca.reference(editorComp, "icons"); +var pictures = sca.reference(editorComp, "pictures"); +var ratings = sca.reference(editorComp, "ratings"); + +/** + * The current app entry, author and saved XML content. + */ +var savedappxml = ''; +var author; +var savediconxml; + +/** + * Get and display the requested app. + */ +(function getapp() { + if (isNil(appname)) + return false; + workingstatus(true); + showstatus('Loading'); + + return apps.get(appname, function(doc) { + + // Stop now if we didn't get the app + if (doc == null) { + errorstatus('Couldn\'t get the app info'); + workingstatus(false); + return false; + } + + var appentry = car(elementsToValues(atom.readATOMEntry(mklist(doc)))); + author = cadr(assoc("'author", appentry)); + $('appAuthor').value = author.split('@')[0]; + var updated = assoc("'updated", appentry); + $('appUpdated').value = isNil(updated)? '' : xmldatetime(cadr(updated)).toLocaleDateString(); + var content = cadr(assoc("'content", appentry)); + var description = assoc("'description", content); + $('appDescription').value = isNil(description) || isNil(cadr(description))? '' : cadr(description); + //var ratingy = -20 * (4 - Math.floor(Math.random() * 4)); + //$('appRating').style.backgroundPosition = '0px ' + ratingy + 'px'; + //$('appRatings').value = ''; + savedappxml = car(atom.writeATOMEntry(valuesToElements(mklist(appentry)))); + + // Enable author to edit and delete the app + if (username == author) { + $('appDescription').readOnly = false; + $('appDescription').className = 'flatentry'; + $('uploadIcon').style.display = 'inline'; + $('deleteApp').disabled = false; + $('deleteApp').onclick = function() { + return ui.navigate('/#view=delete&app=' + appname, '_view'); + } + onlinestatus(); + } else { + showstatus('Read only'); + } + workingstatus(false); + return true; + }); +})(); + +/** + * Get and display the author's picture. + */ +(function getpic(author) { + workingstatus(true); + showstatus('Loading'); + + return pictures.get(author, function(doc) { + + // Stop now if we didn't get a picture + if (doc == null) { + errorstatus('Author picture not available'); + workingstatus(false); + return false; + } + + var picentry = car(elementsToValues(atom.readATOMEntry(mklist(doc)))); + var content = assoc("'content", picentry); + var picture = assoc("'picture", content); + var img = assoc("'image", picture); + if (!isNil(img)) + $('authorPicture').src = cadr(img); + + onlinestatus(); + workingstatus(false); + return true; + }); + return true; +})(); + +/** + * Get and display the app icon. + */ +(function geticon() { + if (isNil(appname)) + return false; + workingstatus(true); + showstatus('Loading'); + + return icons.get(appname, function(doc) { + // Stop now if we didn't get an icon + if (doc == null) { + errorstatus('Icon not available'); + workingstatus(false); + return false; + } + + var iconentry = car(elementsToValues(atom.readATOMEntry(mklist(doc)))); + savediconxml = car(atom.writeATOMEntry(valuesToElements(mklist(iconentry)))); + var content = assoc("'content", iconentry); + var icon = assoc("'icon", content); + var img = assoc("'image", icon); + if (!isNil(img)) + $('appIcon').src = cadr(img); + + onlinestatus(); + workingstatus(false); + return true; + }); + return true; +})(); + +/** + * Refresh icon. + */ +var refreshingicon = false; +function refreshicon() { + if (isNil(appname)) + return false; + if (!refreshingicon) + return false; + $('refreshingIcon').style.display = 'inline-block'; + return icons.get(appname, function(doc) { + if (doc == null) { + errorstatus('Icon not available'); + $('refreshingIcon').style.display = 'none'; + refreshingicon = false; + return false; + } + + var iconentry = car(elementsToValues(atom.readATOMEntry(mklist(doc)))); + var content = assoc("'content", iconentry); + var icon = assoc("'icon", content); + var token = assoc("'token", icon); + + // Update icon + if (isNil(token)) { + var entryxml = car(atom.writeATOMEntry(valuesToElements(mklist(iconentry)))); + savediconxml = entryxml; + var img = assoc("'image", icon); + if (!isNil(img)) + $('appIcon').src = cadr(img); + $('refreshingIcon').style.display = 'none'; + refreshingicon = false; + return true; + } + + // Refresh in 2 secs + return ui.delay(refreshicon, 2000); + }, 'remote'); + return true; +} + +/** + * Get and display the app ratings. + */ +(function getratings() { + if (isNil(appname)) + return false; + workingstatus(true); + showstatus('Loading'); + + return ratings.get(appname, function(doc) { + // Stop now if we didn't get an icon + if (doc == null) { + errorstatus('Ratings not available'); + workingstatus(false); + return false; + } + + var ratingsentry = car(elementsToValues(atom.readATOMEntry(mklist(doc)))); + var aratings = assoc("'ratings", assoc("'content", ratingsentry)); + var ar = assoc("'rating", aratings); + var ar1 = assoc("'rating1", aratings); + var ar2 = assoc("'rating2", aratings); + var ar3 = assoc("'rating3", aratings); + var ar4 = assoc("'rating4", aratings); + var rating = isNil(ar)? 0 : Number(cadr(ar)); + var reviews = (isNil(ar1)? 0 : Number(cadr(ar1))) + (isNil(ar2)? 0 : Number(cadr(ar2))) + (isNil(ar3)? 0 : Number(cadr(ar3))) + (isNil(ar4)? 0 : Number(cadr(ar4))); + + var ratingy = -20 * (4 - Math.floor(rating)); + $('appRating').style.backgroundPosition = '0px ' + ratingy + 'px'; + $('appRatings').value = reviews + (reviews > 1? ' ratings' : ' rating'); + + onlinestatus(); + workingstatus(false); + return true; + }); + return true; +})(); + +/** + * Save the current app. + */ +function saveapp(entryxml) { + workingstatus(true); + showstatus('Saving'); + savedappxml = entryxml; + apps.put(appname, savedappxml, function(e) { + if (e) { + showstatus('Local copy'); + workingstatus(false); + return false; + } + + showstatus('Saved'); + workingstatus(false); + return false; + }); + return true; +} + +/** + * Save the app icon. + */ +function saveicon(entryxml) { + workingstatus(true); + showstatus('Uploading'); + savedappxml = entryxml; + icons.put(appname, savedappxml, function(e) { + if (e) { + showstatus('Local copy'); + workingstatus(false); + return false; + } + + showstatus('Uploaded'); + workingstatus(false); + return true; + }); + return true; +} + +/** + * Handle a change event + */ +function onappchange() { + if (username != author) + return false; + + // Validate user input + var description = $('appDescription').value; + if (description.length > 120) { + errorstatus('Description cannot be longer than 120 characters'); + return false; + } + + // Save the changes + var appentry = mklist("'entry", mklist("'title", appname), mklist("'id", appname), mklist("'content", mklist("'info", mklist("'description", description)))); + var entryxml = car(atom.writeATOMEntry(valuesToElements(mklist(appentry)))); + if (savedappxml == entryxml) + return false; + showstatus('Modified'); + return saveapp(entryxml); +} + +$('appDescription').onchange = onappchange; + +/** + * Handle a key event. + */ +var lastkeyup = null; +$('appDescription').onkeyup = function() { + var t = new Date().getTime(); + lastkeyup = t; + ui.delay(function() { + return t == lastkeyup? onappchange() : true; + }, 2000); +}; + +/** + * Handle a form submit event. + */ +$('appForm').onsubmit = function() { + onappchange(); + return false; +}; + +/** + * Handle Clone button event. + */ +$('cloneApp').onclick = function() { + return ui.navigate('/#view=clone&app=' + appname, '_view'); +}; + +/** + * Handle Run button event. + */ +$('runApp').onclick = function() { + return ui.navigate('/' + appname + '/', '_blank'); +}; + +/** + * Read and upload icon file. + */ +function uploadicon(files) { + if (username != author) + return false; + if (!files || files.length == 0) + return false; + if (!files[0].type.match('image.*')) { + errorstatus('Please select an image'); + return false; + } + workingstatus(true); + showstatus('Loading'); + + // Read the selected file into a 50x50 image + return ui.readimage(files[0], + function(e) { + errorstatus('Couldn\'t read the file'); + workingstatus(false); + }, + function(p) { + showstatus('Loading ' + p + '%'); + }, + function(url) { + // Update the app icon + $('appIcon').src = url; + showstatus('Loaded'); + + // Now upload it + ui.delay(function() { + var iconentry = mklist("'entry", mklist("'title", appname), mklist("'id", appname), mklist("'author", username), mklist("'content", mklist("'icon", mklist("'image", url)))); + var entryxml = car(atom.writeATOMEntry(valuesToElements(mklist(iconentry)))); + if (savediconxml == entryxml) { + onlinestatus(); + workingstatus(false); + return false; + } + return saveicon(entryxml); + }); + }, 50, 50); +} + +/** + * Upload an icon in an email. + */ +function emailicon() { + + // Generate and put an icon email upload token + workingstatus(true); + showstatus('Uploading'); + var token = uuid4(); + var iconentry = mklist("'entry", mklist("'title", appname), mklist("'id", appname), mklist("'author", username), mklist("'content", mklist("'icon", mklist("'token", token)))); + var entryxml = car(atom.writeATOMEntry(valuesToElements(mklist(iconentry)))); + icons.put(appname, entryxml, function(e) { + if (e) { + showstatus('Local copy'); + workingstatus(false); + return false; + } + workingstatus(false); + + // Open the email app + var mailto = safeb64encode('i/' + appname + '/' + token); + ui.navigate('mailto:' + mailto + '@' + topdomainname(window.location.hostname) + '?subject=Email to upload&body=Paste icon here', '_self'); + + // Refresh app icon + refreshingicon = true; + return ui.delay(refreshicon, 500); + }, 'remote'); +} + +/** + * Handle icon upload events. + */ +$('uploadIcon').onclick = function() { + if (ui.isMobile()) + return emailicon(); + return $('uploadFile').click(); +}; +$('uploadFile').onchange = function(e) { + return uploadicon(e.target.files); +}; +$('appIcon').ondrag = function(e) { + e.stopPropagation(); + e.preventDefault(); + e.dataTransfer.dropEffect = 'copy'; +}; +$('appIcon').ondrop = function(e) { + e.stopPropagation(); + e.preventDefault(); + return uploadicon(e.dataTransfer.files); +}; + +/** + * Handle rate button event. + */ +$('rateApp').onclick = function() { + return ui.navigate('/#view=rate&app=' + appname, '_view'); +}; + +})(); +</script> + +</div> diff --git a/sca-cpp/trunk/hosting/server/htdocs/login/index.html b/sca-cpp/trunk/hosting/server/htdocs/login/index.html index bf09339927..efc3feaeaa 100644 --- a/sca-cpp/trunk/hosting/server/htdocs/login/index.html +++ b/sca-cpp/trunk/hosting/server/htdocs/login/index.html @@ -19,87 +19,113 @@ --> <html> <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>Sign in</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-precomposed" href="/public/touchicon.png"/> <base href="/login/"/> <script type="text/javascript"> -(function() { +try { + +(function loginhead() { window.appcache = {}; /** * Get and cache a resource. */ -appcache.get = function(uri) { +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(u); } catch(e) {} - if (item != null && item != '') - return item; + if (mode != 'remote') { + var item = null; + try { item = ls.getItem('ui.r.' + u); } catch(e) {} + if (item != null && item != '') + return item; + if (mode == 'local') + return null; + } // Get resource from network + //if (window.debug) debug('appcache.get', u); var http = new XMLHttpRequest(); - http.open("GET", u, false); + http.open("GET", mode == 'remote'? (u + '?t=' + new Date().getTime() + '&r=' + Math.random()) : u, false); http.setRequestHeader("Accept", "*/*"); http.send(null); if (http.status == 200) { - if (http.getResponseHeader("X-Login") != null) { + var xl = http.getResponseHeader("X-Login"); + if (xl != null && xl != '') { if (window.debug) debug('http error', u, 'X-Login'); return null; - } else if (http.responseText == '' || http.getResponseHeader("Content-Type") == null) { + } + var ct = http.getResponseHeader("Content-Type"); + if (http.responseText == '' || ct == null || ct == '') { if (window.debug) debug('http error', u, 'No-Content'); return null; } - try { ls.setItem(u, http.responseText); } catch(e) {} + try { ls.setItem('ui.r.' + u, http.responseText); } catch(e) {} return http.responseText; } if (window.debug) debug('http error', u, http.status, http.statusText); return null; }; +appcache.remove = function(uri) { + var h = uri.indexOf('#'); + var u = h == -1? uri : uri.substring(0, h); + var ls = window.lstorage || localStorage; + try { ls.removeItem(u); } catch(e) {} + return true; +}; + })(); /** * Load Javascript and CSS. */ -(function() { +(function loginboot() { + +window.eval.call(window, 'try {\n' + appcache.get('/all-min.js') + '\n' + appcache.get('/public/config-min.js') + '\n} catch(e) { console.log(e.stack); throw e; }\n'); +ui.includeCSS(appcache.get('/ui-min.css')); -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'))); +// Disable cache for testing +//lstorage.enabled = false; })(); +} catch(e) { + if (window.debug) debug(e.stack); + throw e; +} </script> </head> -<body class="delayed""> -<div id="mainbodydiv" class="bodydiv"> - -<div id="headdiv" class="hsection"> -<script type="text/javascript"> -(function() { +<body class="delayed"> -$('headdiv').appendChild(ui.declareScript(appcache.get('/public/config-min.js'))); - -})(); -</script> +<div id="menucontainer" class="tbarmenu"> +<div id="menu"></div> </div> -<div id="menubackground" class="tbarbackground fixed"></div> -<div id="menu" class="tbarmenu fixed"></div> - -<div id="viewheadbackground" class="viewheadbackground fixed"></div> -<div id="viewhead" class="viewhead fixed"> +<div id="viewheadcontainer" class="viewhead"> +<div id="viewhead"> <span class="cmenu">Sign in</span> </div> +</div> + +<div id="working" class="working" style="display: none;"></div> <div id="viewcontainer"> <div id="view"> @@ -109,9 +135,9 @@ $('headdiv').appendChild(ui.declareScript(appcache.get('/public/config-min.js')) <form id="formSignin" name="formSignin" method="POST" action="/login/dologin" style="width: 100%;"> <table style="width: 100%;"> <tr><td><span id="loginprompt" style="font-size: 16px;"></span></tr></td> -<tr><td><input type="text" class="flatentry" name="httpd_username" value="" placeholder="User id"/></td></tr> +<tr><td><input type="text" class="flatentry" name="httpd_username" value="" placeholder="Username or email"/></td></tr> <tr><td><input type="password" class="flatentry" name="httpd_password" value="" placeholder="Password"/></td></tr> -<tr><td><input type="submit" class="graybutton bluebutton" style="font-size: 16px; line-height: 16px; padding: 6px; height: 32px" value="Sign in"/></td></tr> +<tr><td><input type="submit" class="bluebutton" style="font-size: 16px; line-height: 16px; padding: 6px; height: 32px" value="Sign in"/></td></tr> </table> <input type="hidden" name="httpd_location" value="/"/> </form> @@ -120,7 +146,7 @@ $('headdiv').appendChild(ui.declareScript(appcache.get('/public/config-min.js')) <form name="facebookOAuth2Form" style="width: 100%;"> <table style="width: 100%;"> <tr><td><span style="font-size: 16px;">Sign in with your <span style="font-weight: bold;">Facebook</span> account</span></td></tr> -<tr><td><input type="button" id="facebookOAuth2Signin" value="Sign in" class="graybutton bluebutton" style="font-size: 16px; line-height: 16px; padding: 6px; height: 32px"/></td></tr> +<tr><td><input type="button" id="facebookOAuth2Signin" value="Sign in" class="bluebutton" style="font-size: 16px; line-height: 16px; padding: 6px; height: 32px"/></td></tr> </table> </form> <br/> @@ -128,7 +154,7 @@ $('headdiv').appendChild(ui.declareScript(appcache.get('/public/config-min.js')) <form name="googleOAuth2Form" style="width: 100%;"> <table style="width: 100%;"> <tr><td><span style="font-size: 16px;">Sign in with your <span style="font-weight: bold;" >Google</span> account</span></td></tr> -<tr><td><input type="button" id="googleOAuth2Signin" value="Sign in" class="graybutton bluebutton" style="font-size: 16px; line-height: 16px; padding: 6px; height: 32px"/></td></tr> +<tr><td><input type="button" id="googleOAuth2Signin" value="Sign in" class="bluebutton" style="font-size: 16px; line-height: 16px; padding: 6px; height: 32px"/></td></tr> </table> </form> <br/> @@ -147,78 +173,110 @@ $('headdiv').appendChild(ui.declareScript(appcache.get('/public/config-min.js')) </div> </div> -<div id="viewfootbackground" class="viewfootbackground fixed"></div> -<div id="viewfoot" class="viewfoot fixed"></div> -<div id="status" class="status fixed" style="visibility: hidden;"></div> +<div id="viewfootcontainer" class="viewfoot"> +<div id="viewfoot"></div> +<div id="status"></div> +</div> + +<div id="installer" class="installer"></div> <script type="text/javascript"> -(function() { +try { + +(function loginbody() { /** - * Init div variables. + * Setup page layout. */ -var mbdiv = $('menubackground'); -var mdiv = $('menu'); -var hdiv = $('viewhead'); -var hbdiv = $('viewheadbackground'); -$('viewcontainer').className = ui.isMobile()? 'viewcontainer3d' : 'viewcontainer3dm'; -$('view').className = ui.isMobile()? 'viewloaded3d' : 'viewloaded3dm'; -$('loginprompt').innerHTML = config.loginprompt(); -var fdiv = $('viewfoot'); +(function layout() { + $('viewcontainer').className = ui.isMobile()? 'viewcontainer3dm' : 'viewcontainer3d'; + $('view').className = ui.isMobile()? 'viewloaded3dm' : 'viewloaded3d'; + $('loginprompt').innerHTML = config.loginprompt(); + document.title = config.windowtitle() + ' - Sign in'; + $('viewhead').innerHTML = '<span class="bcmenu">' + config.pagetitle() + '</span>' + + '<span class="rmenu"><input type="button" id="signUp" class="redbutton" style="font-size: 16px; line-height: 16px; padding: 6px; height: 32px" title="' + config.signuptitle() + '" value="Sign up"/></span>'; + if (!ui.isMobile()) + $('viewcontent').className = 'viewcontent flatscrollbars'; + $('status').className = ui.isMobile()? 'status3dm' : 'status3d'; +})(); /** - * Set page titles. + * Setup menu bar. */ -document.title = config.windowtitle() + ' - Sign in'; -$('viewhead').innerHTML = '<span class="bcmenu">' + config.pagetitle() + '</span>'; +(function showmenu() { + $('menu').innerHTML = ui.menubar(mklist(ui.menu('menuhome', 'Home', '/', '_self', false)), mklist()); + $('viewfoot').innerHTML = config.viewfoot(); +})(); /** - * Build and show the menu bar. + * Initialize status message area. */ -function showmenu(mdiv) { - mdiv.innerHTML = ui.menubar(mklist(ui.menu('menuhome', 'Home', '/', '_self', false)), mklist()); - fdiv.innerHTML = config.viewfoot(); -} - -showmenu(mdiv); +(function initstatus() { + if (isNil($('status'))) + return; + $('status').style.display = 'none'; + + function divtransitionend(e) { + e.target.style.display = 'none'; + e.target.className = ui.isMobile()? 'status3dm' : 'status3d'; + e.target.error = false; + } + $('status').addEventListener('webkitTransitionEnd', divtransitionend, false); + $('status').addEventListener('transitionend', divtransitionend, false); +})(); /** * Show a status message. */ -window.showStatus = function(s, c) { - //debug('status', s); - var sdiv = $('status'); - if (isNil(sdiv)) +window.showstatus = function(s, c) { + //debug('show status', s); + if (isNil($('status')) || $('status').error) return s; - sdiv.innerHTML = '<span class="' + (c? c : 'okstatus') + '">' + s + '</span>'; - sdiv.className = 'status fixed'; - sdiv.style.visibility = 'visible'; - - function divtransitionend(e) { - e.target.style.visibility = 'hidden'; - e.target.className = 'status fixed'; - } - if (!sdiv.addedTransitionEnd) { - sdiv.addEventListener('webkitTransitionEnd', divtransitionend, false); - sdiv.addEventListener('transitionend', divtransitionend, false); - sdiv.addedTransitionEnd = true; - } - sdiv.className = 'statusout3 fixed'; + $('status').innerHTML = '<span class="' + (c? c : 'okstatus') + '">' + s + '</span>'; + $('status').className = ui.isMobile()? 'status3dm' : 'status3d'; + $('status').style.display = 'block'; + $('status').error = c == 'errorstatus'; + if ($('status').delay) + ui.cancelDelay($('status').delay); + $('status').delay = ui.delay(function hidestatus() { + $('status').className = ui.isMobile()? 'statusout3dm' : 'statusout3d'; + $('status').error = false; + }, 3000); return s; -} +}; /** * Show an error message. */ -window.showError = function(s) { +window.errorstatus = function(s) { //debug('error', s); - return showStatus(s, 'errorstatus'); -} + return showstatus(s, 'errorstatus'); +}; + +/** + * Show working status. + */ +window.workingstatus = function(w, c) { + //debug('show working', w); + if (isNil($('working'))) + return w; + if (!ui.isMobile()) + $('working').style.top = ui.pixpos(Math.round(window.clientHeight / 2)); + $('working').style.display = w? 'block' : 'none'; + return w; +}; + +/** + * Show the online/offline status. + */ +window.onlinestatus = function() { + return navigator.onLine? (ui.isMobile()? showstatus('Online') : showstatus('Online')) : errorstatus('Offline'); +}; /** - * Parse the query parameeters. + * Parse the query parameters. */ -function queryParams() { +function qparams() { var qp = new Array(); var qs = window.location.search.substring(1).split('&'); for (var i = 0; i < qs.length; i++) { @@ -232,20 +290,17 @@ function queryParams() { /** * Show login status. */ -function showLoginStatus() { - var a = queryParams()['openauth_attempt']; - debug('a', a); +function loginstatus() { + var a = qparams()['openauth_attempt']; if (typeof(a) != 'undefined' && a == '1') - showError('Incorrect email or password, please try again'); + errorstatus('Incorrect email or password, please try again'); } -showLoginStatus(); - /** * Return the referrer URL. */ -function openauthReferrer() { - var r = queryParams()['openauth_referrer']; +function openauthreferrer() { + var r = qparams()['openauth_referrer']; if (typeof(r) == 'undefined' || domainname(r) != domainname(window.location.hostname)) return '/'; var q = r.indexOf('?'); @@ -257,9 +312,8 @@ function openauthReferrer() { /** * Signin with OAuth 2.0. */ -function submitOAuth2Signin(w) { +function submitoauth2signin(w) { parms = w(); - clearauthcookie(); lstorage.removeItem('/r/Editor/accounts'); lstorage.removeItem('/r/Editor/dashboards'); document.oauth2Signin.oauth2_authorize.value = parms[0]; @@ -268,70 +322,195 @@ function submitOAuth2Signin(w) { document.oauth2Signin.oauth2_info.value = parms[3]; document.oauth2Signin.oauth2_scope.value = parms[4]; document.oauth2Signin.oauth2_display.value = parms[5]; - document.oauth2Signin.openauth_referrer.value = openauthReferrer(); + document.oauth2Signin.openauth_referrer.value = openauthreferrer(); document.oauth2Signin.action = '/oauth2/authorize/'; document.oauth2Signin.submit(); } -function withFacebook() { +function withfacebook() { var parms = ['https://graph.facebook.com/oauth/authorize', 'https://graph.facebook.com/oauth/access_token', 'facebook.com', 'https://graph.facebook.com/me', 'email', ui.isMobile()? 'touch' : 'page']; return parms; } -function withGoogle() { +function withgoogle() { var parms = ['https://accounts.google.com/o/oauth2/auth', 'https://accounts.google.com/o/oauth2/token', 'google.com', 'https://www.googleapis.com/oauth2/v1/userinfo', 'https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile', '']; return parms; } $('facebookOAuth2Signin').onclick = function() { - return submitOAuth2Signin(withFacebook); + return submitoauth2signin(withfacebook); }; $('googleOAuth2Signin').onclick = function() { - return submitOAuth2Signin(withGoogle); + return submitoauth2signin(withgoogle); }; /** - * Signin with a userid and password. + * Signin with a username and password. */ -function submitFormSignin() { - clearauthcookie(); +$('formSignin').onsubmit = function submitformsignin() { document.formSignin.httpd_location.value = '/'; document.formSignin.submit(); -} +}; -$('formSignin').onsubmit = submitFormSignin; +/** + * Signup. + */ +$('signUp').onclick = function submitsignup() { + ui.navigate('/public/notyet/', '_self'); +}; /** * Handle orientation change. */ document.body.onorientationchange = function(e) { //debug('onorientationchange'); - ui.onorientationchange(e); - - // Resize menu and view header - mdiv.style.width = ui.pixpos(document.documentElement.clientWidth); - hdiv.style.width = ui.pixpos(document.documentElement.clientWidth); - return true; + return ui.onorientationchange(e); }; /** + * Populate cache with app resources. + */ +var appresources = [ + ['/all-min.js'], + ['/ui-min.css'], + ['/public/config-min.js'] +]; + +/** + * Install the application cache. + */ +(function installappcache() { + if (ui.isMobile()) { + // On mobile devices, trigger usage of an application cache manifest + window.onappcachechecking = function(e) { + //debug('appcache checking', e); + workingstatus(true); + showstatus('Checking'); + }; + window.onappcacheerror = function(e) { + //debug('appcache error', e); + onlinestatus(); + workingstatus(false); + }; + window.onappcachenoupdate = function(e) { + //debug('appcache noupdate', e); + onlinestatus(); + workingstatus(false); + }; + window.onappcachedownloading = function(e) { + //debug('appcache downloading', e); + workingstatus(true); + showstatus('Updating'); + }; + window.onappcacheprogress = function(e) { + //debug('appcache progress', e); + workingstatus(true); + showstatus('Updating'); + }; + window.onappcacheupdateready = function(e) { + //debug('appcache updateready', e); + try { + applicationCache.swapCache(); + } catch(e) {} + onlinestatus(); + workingstatus(false); + //debug('appcache swapped', e); + + // Update offline resources in local storage and reload the page + map(function(res) { + showstatus('Updating'); + appcache.remove(res[0]); + appcache.get(res[0], 'remote'); + }, append(appresources, config.appresources())); + window.location.reload(); + }; + window.onappcachecached = function(e) { + //debug('appcache cached', e); + onlinestatus(); + workingstatus(false); + + // Install offline resources in local storage + map(function(res) { + showstatus('Updating'); + appcache.remove(res[0]); + appcache.get(res[0], 'remote'); + }, append(appresources, config.appresources())); + }; + + window.onloadappcache = function() { + //debug('appcache iframe loaded'); + }; + + ui.delay(function() { + $('installer').innerHTML = '<iframe src="/public/cache/" class="installer"></iframe>'; + }); + + } else { + // On non-mobile devices, check for cache-manifest changes ourselves. + workingstatus(true); + showstatus('Checking'); + var lcmf = appcache.get('/public/cache/cache-manifest.cmf', 'local'); + var rcmf = appcache.get('/public/cache/cache-manifest.cmf', 'remote'); + if (lcmf == rcmf) { + onlinestatus(); + workingstatus(false); + return true; + } + + //debug('cache-manifest changed, reloading'); + ui.delay(function() { + workingstatus(true); + showstatus('Updating'); + ui.delay(function() { + workingstatus(true); + showstatus('Updating'); + map(function(res) { + appcache.remove(res[0]); + appcache.get(res[0], 'remote'); + }, append(appresources, config.appresources())); + if (!isNil(lcmf)) { + //debug('reloading'); + window.location.reload(); + } + onlinestatus(); + workingstatus(false); + }); + }); + } +})(); + +/** + * Handle network offline/online events. + */ +window.addEventListener('offline', function(e) { + //debug('going offline'); + showstatus('Offline'); +}, false); +window.addEventListener('online', function(e) { + //debug('going online'); + showstatus('Online'); +}, false); + +/** * Initialize the document. */ -function onload() { +window.onload = function() { //debug('onload'); ui.onload(); - // Show the page - document.body.style.visibility = 'visible'; + // Show the login status + loginstatus(); return true; -} - -onload(); +}; })(); + +} catch(e) { + debug(e.stack); + throw e; +} </script> -</div> </body> </html> diff --git a/sca-cpp/trunk/hosting/server/htdocs/page/index.html b/sca-cpp/trunk/hosting/server/htdocs/page/index.html index 6a6e042c74..c6e1108ce5 100644 --- a/sca-cpp/trunk/hosting/server/htdocs/page/index.html +++ b/sca-cpp/trunk/hosting/server/htdocs/page/index.html @@ -19,59 +19,69 @@ --> <div id="bodydiv" class="body"> -<div id="contentdiv" class="viewcontent" style="width: 2500px;"> -<div id="pagediv" class="pagediv" style="top: 0px; left: -2500px; width: 5000px; height: 5000px;"> +<div id="viewcontent" class="viewcontent"> +<div id="pagecontainer"> +<div id="pagediv" class="pagediv"> +</div> <!-- -<div class="guide" style="position: absolute; left: 2500px; top: 0px; width: 320px; height: 460px;"></div> -<div class="guide" style="position: absolute; left: 2500px; top: 0px; width: 480px; height: 300px;"></div> -<div class="guide" style="position: absolute; left: 2500px; top: 0px; width: 768px; height: 911px;"></div> -<div class="guide" style="position: absolute; left: 2500px; top: 0px; width: 1024px; height: 655px;"></div> +<div class="guide" style="position: absolute; left: 0px; top: 0px; width: 320px; height: 460px;"></div> +<div class="guide" style="position: absolute; left: 0px; top: 0px; width: 480px; height: 300px;"></div> +<div class="guide" style="position: absolute; left: 0px; top: 0px; width: 768px; height: 911px;"></div> +<div class="guide" style="position: absolute; left: 0px; top: 0px; width: 1024px; height: 655px;"></div> --> -<span class="h1" id="palette:h1" style="position: absolute; left: 0px; top: 0px;"><h1>Header Level 1</h1></span> -<span class="h2" id="palette:h2" style="position: absolute; left: 0px; top: 30px;"><h2>Header Level 2</h2></span> -<span class="section" id="palette:section" style="position: absolute; left: 0px; top: 60px; width: 220px;"><span class="Section">Section</span></span> -<span class="text" id="palette:text" style="position: absolute; left: 0px; top: 90px;"><span>Some text</span></span> -<span class="link" id="palette:link" style="position: absolute; left: 80px; top: 90px;"><a href="/"><span>Link</span></a></span> -<span class="button" id="palette:graybutton" style="position: absolute; left: 0px; top: 120px;"><input type="button" value="Button" class="graybutton"/></span> -<span class="button" id="palette:bluebutton" style="position: absolute; left: 80px; top: 120px;"><input type="button" value="Button" class="graybutton bluebutton"/></span> -<span class="button" id="palette:redbutton" style="position: absolute; left: 160px; top: 120px;"><input type="button" value="Button" class="graybutton redbutton"/></span> -<span class="entry" id="palette:entry" style="position: absolute; left: 0px; top: 160px;"><input type="text" value="Entry Field" class="flatentry" size="20" autocapitalize="off"/></span> -<span class="password" id="palette:password" style="position: absolute; left: 0px; top: 190px;"><input type="password" value="Password" class="flatentry" size="20"/></span> -<span class="checkbox" id="palette:checkbox" style="position: absolute; left: 0px; top: 220px;"><input type="checkbox" value="Checkbox" class="flatcheckbox"/><span>Checkbox</span></span> +</div> + +<div id="playdiv" class="playdiv" style="display: none;"></div> + +</div> + +<div id="palettecontainer"> +<div id="paletteview" style="display: none;"> + +<div id="palettecontent" class="palettecontent"> +<table class="palettetable"> +<tr><td class="palettetd"><span class="hd1" id="palette:h1"><span>Header 1</span></span></td></tr> +<tr><td class="palettetd"><span class="hd2" id="palette:h2"><span>Header 2</span></span></td></tr> +<tr><td class="palettetd"><span class="section" id="palette:section"><span>Section</span></span></td></tr> +<tr><td class="palettetd"><span class="text" id="palette:text"><span>Some text</span></span></td></tr> +<tr><td class="palettetd"><span class="link" id="palette:link"><a href="/"><span>Link</span></a></span></td></tr> +<tr><td class="palettetd"><span class="button" id="palette:graybutton"><input type="button" value="Button" class="graybutton"/></span></td></tr> +<tr><td class="palettetd"><span class="button" id="palette:redbutton"><input type="button" value="Button" class="redbutton"/></span></td></tr> +<tr><td class="palettetd"><span class="button" id="palette:greenbutton"><input type="button" value="Button" class="greenbutton"/></span></td></tr> +<tr><td class="palettetd"><span class="button" id="palette:bluebutton"><input type="button" value="Button" class="bluebutton"/></span></td></tr> +<tr><td class="palettetd"><span class="entry" id="palette:entry"><input type="text" value="Entry Field" class="flatentry" size="10" autocapitalize="off" readonly="true" style="cursor: default;"/></span></td></tr> +<tr><td class="palettetd"><span class="password" id="palette:password"><input type="password" value="Password" class="flatentry" size="10" readonly="true" style="cursor: default;"/></span></td></tr> +<tr><td class="palettetd"><span class="checkbox" id="palette:checkbox"><input type="checkbox" value="Checkbox" class="flatcheckbox"/><span>Checkbox</span></span></td></tr> <!-- -<span class="select" id="palette:select" style="position: absolute; left: 80px; top: 220px;"><select><option value="select">Selection</option></select></span> +<tr><td class="palettetd"><span class="select" id="palette:select"><select disabled="true"><option value="select">Selection</option></select></span></td></tr> --> -<span class="list" id="palette:list" style="position: absolute; left: 0px; top: 250px; width: 220px;"> -<table class="datatable" style="width: 220px;"> -<tr><td class="datatd">List</td></tr> -<tr><td class="datatd">List</td></tr> -<tr><td class="datatd">List</td></tr> +<tr><td class="palettetd"><span class="list" id="palette:list"> +<table class="datatable"> +<tr><td class="datatd"><span>List</span></td></tr> +<tr><td class="datatd"><span>List</span></td></tr> +<tr><td class="datatd"><span>List</span></td></tr> </table> -</span> -<span class="table" id="palette:table" style="position: absolute; left: 0px; top: 320px; width: 220px;"> -<table class="datatable" style="width: 220px;"> -<tr><td class="datatdl">Table</td><td class="datatdr">Table</td></tr> -<tr><td class="datatdl">Table</td><td class="datatdr">Table</td></tr> -<tr><td class="datatdl">Table</td><td class="datatdr">Table</td></tr> +</span></td></tr> +<tr><td class="palettetd"><span class="table" id="palette:table"> +<table class="datatable"> +<tr><td class="datatdl"><span>Table</span></td><td class="datatdr"><span>Table</span></td></tr> +<tr><td class="datatdl"><span>Table</span></td><td class="datatdr"><span>Table</span></td></tr> +<tr><td class="datatdl"><span>Table</span></td><td class="datatdr"><span>Table</span></td></tr> +</table> +</span></td></tr> +<tr><td class="palettetd"><span class="img" id="palette:img"><img id="imgimg"/></span></td></tr> </table> -</span> -<!-- -<span class="iframe fakeframe" id="palette:iframe" style="position: absolute; left: 0px; top: 380px; width: 200px;"><a href="/public/iframe-min.html"><span class="fakeframe"><span>Frame ...</span></span></a></span> ---> -<span class="img" id="palette:img" style="position: absolute; left: 0px; top: 410px;"><img id="imgimg"/></span> </div> -<div id="playdiv" style="visibility: hidden; position: absolute; top: 0px; left: 0px; width: 2500px; height: 5000px;"> </div> - </div> -<div id="buffer" style="visibility: hidden; width: 0px; height: 0px"></div> +<div id="xhtmlbuffer" style="display: none;"></div> <script type="text/javascript"> -(function() { +(function pagebody() { /** * Get the current app name. @@ -79,402 +89,247 @@ var appname = ui.fragmentParams(location)['app']; /** - * Return the link to an app. + * Setup page layout. */ -function applink(appname) { - var protocol = location.protocol; - var host = location.hostname; - var port = ':' + location.port; - if (port == ':80' || port == ':443' || port == ':') - port = ''; - var link = protocol + '//' + host + port + '/' + appname + '/'; - return link; -} - -/** - * Set page titles. - */ -document.title = config.windowtitle() + ' - Page - ' + appname; +(function layout() { + document.title = config.windowtitle() + ' - Page - ' + appname; + + $('viewhead').innerHTML = '<span id="appTitle" class="cmenu">' + appname + '</span>' + + '<input type="button" id="deleteWidgetButton" title="Delete a Widget" class="redbutton plusminus" style="position: absolute; top: 4px; left: 5px;" disabled="true" value="-"/>' + + '<span style="position: absolute; top: 0px; left: 45px; right: 115px; padding: 0px; background: transparent;"><input id="widgetValue" type="text" value="" class="flatentry" title="Widget value" autocapitalize="off" placeholder="Value" style="position: absolute; left: 0px; top: 4px; width: 100%; display: none;" readonly="readonly"/></span>' + + '<input type="button" id="playPageButton" title="View page" class="greenbutton plusminus" style="position: absolute; top: 4px; right: 75px;" value=">"/>' + + '<input type="button" id="copyWidgetButton" title="Copy a Widget" class="bluebutton" style="position: absolute; top: 4px; right: 40px; font-size: 16px;" disabled="true" value="C"/>' + + '<input type="button" id="addWidgetButton" title="Add a Widget" class="bluebutton plusminus" style="position: absolute; top: 4px; right: 5px;" disabled="true" value="+"/>'; + + if (ui.isMobile()) { + $('palettecontainer').className = 'palettecontainer3dm'; + $('paletteview').className = 'paletteloaded3dm'; + } else { + $('viewcontent').className = 'viewcontent flatscrollbars'; + $('palettecontainer').className = 'palettecontainer3d'; + $('paletteview').className = 'paletteloaded3d'; + $('palettecontent').className = 'palettecontent flatscrollbars'; + } -/** - * Set header div. - */ -$('viewhead').innerHTML = '<span id="appTitle" class="cmenu">' + appname + '</span>' + -'<input type="button" id="deleteWidgetButton" title="Delete a Widget" class="graybutton redbutton plusminus" style="position: absolute; top: 4px; left: 5px;" disabled="true" value="-"/>' + -'<span style="position: absolute; top: 0px; left: 45px; right: 115px; padding: 0px; background: transparent;"><input id="widgetValue" type="text" value="" class="flatentry" title="Widget value" autocapitalize="off" placeholder="Value" style="position: absolute; left: 0px; top: 4px; width: 100%; visibility: hidden;" readonly="readonly"/></span>' + -'<input type="button" id="playPageButton" title="View page" class="graybutton plusminus" style="position: absolute; top: 4px; right: 75px;" value=">"/>' + -'<input type="button" id="copyWidgetButton" title="Copy a Widget" class="graybutton bluebutton" style="position: absolute; top: 4px; right: 40px; font-size: 16px;" disabled="true" value="C"/>' + -'<input type="button" id="addWidgetButton" title="Add a Widget" class="graybutton bluebutton plusminus" style="position: absolute; top: 4px; right: 5px;" disabled="true" value="+"/>'; + $('imgimg').src = ui.b64png(appcache.get('/public/img.b64')); +})(); /** * Track the current page, author, and saved XHTML content. */ var author = ''; var editable = false; -var savedpagexhtml = ''; +var savedxhtml = ''; /** - * Page editor area, widget value field, add, delete and play page buttons. + * Initialize component references. */ -var cdiv = $('contentdiv'); -var pagediv = $('pagediv'); -var evisible = true; -var pdiv = $('playdiv'); -var wadd = $('addWidgetButton'); -var wdelete = $('deleteWidgetButton'); -var wcopy = $('copyWidgetButton'); -var wvalue = $('widgetValue'); -var atitle = $('appTitle'); -var pplay = $('playPageButton'); +var editorComp = sca.component('Editor'); +var pages = sca.reference(editorComp, 'pages'); /** - * Set images. + * Return the transform property of a widget. */ -$('imgimg').src = ui.b64img(appcache.get('/public/img.b64')); +var msiefixupbounds = ui.isMSIE(); +function widgettransform(e) { + if (!isNil(e.xtranslate)) + return [e.xtranslate, e.ytranslate]; + var t = e.style.getPropertyValue('-webkit-transform') || e.style.getPropertyValue('-moz-transform') || + e.style.getPropertyValue('-ms-transform') || e.style.getPropertyValue('-o-transform') || + e.style.getPropertyValue('transform'); + if (t) { + var xy = t.split('(')[1].split(')')[0].split(','); + return [ui.numpos(xy[0]), ui.numpos(xy[1])]; + } + if (e.id.substring(0, 8) == 'palette:') { + // On Internet Explorer get the view bounding rect as the palette + // doesn't return a correct bounding rect + var pbr = msiefixupbounds? $('viewcontent').getBoundingClientRect() : $('palettecontent').getBoundingClientRect(); + var br = e.getBoundingClientRect(); + return [br.left - pbr.left, br.top - pbr.top]; + } + return [0, 0]; +} /** - * Init component references. + * Return the x position of a widget. */ -var editorComp = sca.component('Editor'); -var pages = sca.reference(editorComp, 'pages'); +function widgetxpos(e) { + var t = widgettransform(e)[0]; + return ui.numpos(e.style.left) + (isNil(t)? 0 : t); +} /** - * Page editing functions. + * Return the y position of a widget. */ -var page = {}; +function widgetypos(e) { + var t = widgettransform(e)[1]; + return ui.numpos(e.style.top) + (isNil(t)? 0 : t); +} /** - * Default positions and sizes. + * Return the class of a widget. */ -page.palcx = 2500; +function widgetclass(e) { + return e.className.split(' ')[0]; +} /** - * Init a page editor. + * Initialize a widget. */ -page.mkedit = function(pagediv, atitle, wvalue, wadd, wcopy, wdelete, onchange, onselect) { - - // Track element dragging and selection - page.dragging = null; - page.selected = null; - wvalue.readOnly = true; - wvalue.style.visibility = 'hidden'; - atitle.style.visibility = 'visible'; - page.mousemoved = false; - wcopy.disabled = true; - wdelete.disabled = true; - wadd.disabled = !editable; - - // Trigger widget select and page change events - page.onpagechange = onchange; - page.onselectwidget = onselect; - - /** - * Handle a mouse down event. - */ - function onmousedown(e) { - // On mouse controlled devices, run component selection logic right away - var selected = page.selected; - if (typeof e.touches == 'undefined') { - //debug('onmousedown-click'); - onclick(e); - } - - // Find a draggable element - var dragging = page.draggable(e.target, pagediv); - if (dragging == null || dragging != page.selected) - return true; - page.dragging = dragging; - - // Remember mouse position - var pos = typeof e.touches != "undefined"? e.touches[0] : e; - page.mousemoved = false; - page.dragX = pos.screenX; - page.dragY = pos.screenY; - page.moveX = pos.screenX; - page.moveY = pos.screenY; - - // Prevent default behavior on first click on a widget - if (e.preventDefault) - e.preventDefault(); - else - e.returnValue = false; - - return true; +function fixupwidget(e) { + + // Add draggable class + var wc = e.className; + e.className = ui.isMobile()? (wc + ' draggable3dm') : (wc + ' draggable3d'); + + // Convert widget position to a CSS transform + var x = ui.numpos(e.style.left); + var y = ui.numpos(e.style.top); + var t = 'translate(' + x + 'px,' + y + 'px)'; + e.style.setProperty('-webkit-transform', t, null); + e.style.setProperty('-moz-transform', t, null); + e.style.setProperty('-o-transform', t, null); + e.style.setProperty('-ms-transform', t, null); + e.style.setProperty('transform', t, null); + e.xtranslate = x; + e.ytranslate = y; + e.style.left = ui.pixpos(0); + e.style.top = ui.pixpos(0); + + if (wc == 'entry' || wc == 'password') { + var i = car(childElements(e)); + i.readOnly = true; + i.style.cursor = 'default'; + return e; } - - if (!ui.isMobile()) { - pagediv.onmousedown = function(e) { - //debug('onmousedown'); - return onmousedown(e); - }; - } else { - pagediv.ontouchstart = function(e) { - //debug('ontouchstart'); - return onmousedown(e); - }; + if (wc == 'link') { + var l = car(childElements(e)); + l.onclick = function(e) { return false; }; + return e; } + return e; +} - /** - * Handle a mouse up event. - */ - function onmouseup(e) { - if (page.dragging == null) - return true; - - // Snap to grid - var newX = page.gridsnap(ui.numpos(page.dragging.style.left)); - var newY = page.gridsnap(ui.numpos(page.dragging.style.top)); - page.dragging.style.left = ui.pixpos(newX); - page.dragging.style.top = ui.pixpos(newY); - - // Fixup widget style - page.initwidget(page.dragging); +/** + * Cleanup a widget before saving it. + */ +function cleanupwidget(e) { + //debug('cleanupwidget', e); - // Forget dragged element - page.dragging = null; + // Adjust widget class + var wc = widgetclass(e); + e.className = wc; - // Trigger page change event - page.onpagechange(false); + // Convert CSS transform to an absolute position + e.style.left = ui.pixpos(widgetxpos(e)); + e.style.top = ui.pixpos(widgetypos(e)); + e.style.removeProperty('-webkit-transform'); + e.style.removeProperty('-moz-transform'); + e.style.removeProperty('-o-transform'); + e.style.removeProperty('-ms-transform'); + e.style.removeProperty('transform'); + e.xtranslate = null; + e.ytranslate = null; - // Simulate onclick event - onclick(e); + // Clear outline + e.style.removeProperty('outline'); - return true; + if (wc == 'entry' || wc == 'password') { + var i = car(childElements(e)); + i.readOnly = false; + i.style.cursor = null; + return e; } - - if (!ui.isMobile()) { - pagediv.onmouseup = function(e) { - //debug('onmouseup'); - return onmouseup(e); - }; - } else { - pagediv.ontouchend = function(e) { - //debug('ontouchend'); - return onmouseup(e); - } + if (wc == 'link') { + var l = car(childElements(e)); + l.onclick = null; + return e; } + return e; +} + +/** + * Clone a widget. + */ +function clonewidget(e) { /** - * Handle a mouse move event. + * Clone an element's HTML. */ - function onmousemove(e) { - - // Track mouse moves - page.mousemoved = true; - - if (page.dragging == null) - return true; - - // Ignore duplicate mouse move events - if (page.moveX == page.dragX && page.moveY == 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 newX = curX + (page.moveX - page.dragX); - var newY = curY + (page.moveY - page.dragY); - if (newX >= page.palcx) - page.dragX = page.moveX; - else - newX = page.palcx; - if (newY >= 0) - page.dragY = page.moveY; - else - newY = 0; - - // Move the dragged element - page.dragging.style.left = ui.pixpos(newX); - page.dragging.style.top = ui.pixpos(newY); - page.constrainwidget(page.dragging); - - return true; - } - - if (!ui.isMobile()) { - window.onmousemove = function(e) { + function mkclone(e) { + var ne = document.createElement('span'); - // Remember mouse position - page.moveX = e.screenX; - page.moveY = e.screenY; + // Skip the palette: prefix + ne.id = 'page:' + e.id.substr(8); - return onmousemove(e); - }; - } else { - pagediv.ontouchmove = function(e) { + // Copy the class and HTML content + ne.className = widgetclass(e); + ne.innerHTML = e.innerHTML; - // Remember touch position - var pos = e.touches[0]; - if (page.moveX == pos.screenX && page.moveY == pos.screenY) - return true; - page.moveX = pos.screenX; - page.moveY = pos.screenY; - if (page.moveX == page.dragX && page.moveY == page.dragY) - return true; + // Fixup the widget + fixupwidget(ne); - onmousemove(e); - }; + return ne; } /** - * Handle a mouse click event. + * Clone an element's position. */ - function onclick(e) { - - // Find selected element - var selected = page.draggable(e.target, pagediv); - if (selected == null) { - if (page.selected != null) { - - // Reset current selection - page.selectwidget(page.selected, false, atitle, wvalue, wcopy, wdelete); - page.selected = null; - - // Trigger widget select event - page.onselectwidget(null); - } - - // Dismiss the palette - if (ui.numpos(pagediv.style.left) != (page.palcx * -1)) - pagediv.style.left = ui.pixpos(page.palcx * -1); - - return true; - } - - // Deselect the previously selected element - page.selectwidget(page.selected, false, atitle, wvalue, wcopy, 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) + page.palcx); - page.initwidget(page.selected); - pagediv.style.left = ui.pixpos(page.palcx * -1); - page.constrainwidget(page.selected); - - // Bring it to the top - page.bringtotop(page.selected); - - // Trigger page change event - page.onpagechange(true); - - // Select the element - page.selectwidget(page.selected, true, atitle, wvalue, wcopy, wdelete); - - // Trigger widget select event - page.onselectwidget(page.selected); - - return true; + function posclone(ne, e) { + ne.style.position = 'absolute'; + movewidget(ne, widgetxpos(e), widgetypos(e)); + return ne; + } - } + return posclone(mkclone(e), e); +} - // Bring selected element to the top - page.selected = selected; - page.bringtotop(page.selected); +/** + * Select a widget. + */ +function selectwidget(n, s) { + //debug('selectwidget', n, s); + if (isNil(n) || !s) { + // Clear the widget value field + $('widgetValue').value = ''; + $('widgetValue').readOnly = true; + $('widgetValue').style.display = 'none'; - // Select the element - page.selectwidget(page.selected, true, atitle, wvalue, wcopy, wdelete); + // Show the app title + $('appTitle').style.display = 'block'; - // Trigger widget select event - page.onselectwidget(page.selected); + // Update the copy and delete buttons + $('copyWidgetButton').disabled = true; + $('deleteWidgetButton').disabled = true; + // Clear the widget outline + if (!isNil(n)) + n.style.removeProperty('outline'); return true; } - if (!ui.isMobile()) { - pagediv.onclick = function(e) { - //debug('onclick'); - return onclick(e); - }; - } else { - pagediv.onclick = function(e) { - //debug('onclick'); - return onclick(e); - }; - } - - /** - * Handle field on change events. - */ - wvalue.onchange = wvalue.onblur = function() { - if (page.selected == null) - return false; - page.settext(page.selected, wvalue.value); - - // Trigger page change event - page.onpagechange(true); - return false; - }; - - // Handle add widget event. - wadd.onclick = function() { - - // Show the palette - pagediv.style.left = ui.pixpos(0); - return false; - }; - - // Handle delete event. - wdelete.onclick = function() { - if (page.selected == null) - return false; - - // Reset current selection - page.selectwidget(page.selected, false, atitle, wvalue, wcopy, wdelete); - - // Remove selected widget - page.selected.parentNode.removeChild(page.selected); - page.selected = null; - - // Trigger widget select event - page.onselectwidget(null); - - // Trigger page change event - page.onpagechange(true); - return false; - }; - - // Handle copy event. - wcopy.onclick = function() { - if (page.selected == null) - return false; - if (page.selected.id.substring(0, 8) == 'palette:') - return false; - - // Reset current selection - page.selectwidget(page.selected, false, atitle, wvalue, wcopy, wdelete); - - // Clone selected widget - page.selected = page.clone(page.selected); - - // Move 10 pixels down right - page.selected.style.left = ui.pixpos(ui.numpos(page.selected.style.left) + 10); - page.selected.style.top = ui.pixpos(ui.numpos(page.selected.style.top) + 10); - page.constrainwidget(page.selected); - - // Bring it to the top - page.bringtotop(page.selected); - - // Select the element - page.selectwidget(page.selected, true, atitle, wvalue, wcopy, wdelete); + // Outline the widget + n.style.outline = '2px solid #598edd'; - // Trigger widget select event - page.onselectwidget(page.selected); + // Update the widget value field + $('widgetValue').value = widgettext(n); + $('widgetValue').readOnly = false || !editable; + $('widgetValue').style.display = 'block'; - // Trigger page change event - page.onpagechange(true); - return false; - }; + // Hide the app title + $('appTitle').style.display = 'none'; - return pagediv; -}; + // Update the copy and delete buttons + $('copyWidgetButton').disabled = false || !editable; + $('deleteWidgetButton').disabled = false || !editable; + return true; +} /** * Return the text of a widget. */ -page.text = function(e) { +function widgettext(e) { function formula(e) { var f = e.id; if (f.substring(0, 5) != 'page:') @@ -483,43 +338,36 @@ page.text = function(e) { } function constant(e, f) { - if (e.className == 'h1' || e.className == 'h2' || e.className == 'text' || e.className == 'section') { + var wc = widgetclass(e); + if (wc == 'hd1' || wc == 'hd2' || wc == 'text' || wc == 'section') { var t = car(childElements(e)).innerHTML; return t == f? '' : t; } - if (e.className == 'button' || e.className == 'checkbox') { + if (wc == 'button' || wc == 'checkbox') { var t = car(childElements(e)).value; return t == f? '' : t; } - if (e.className == 'entry' || e.className == 'password') { + if (wc == 'entry' || wc == 'password') { var t = car(childElements(e)).defaultValue; return t == f? '' : t; } - /* - if (e.className == 'select') { + if (wc == 'select') { var t = car(childElements(car(childElements(e)))).value; return t == f? '' : t; } - */ - if (e.className == 'link') { + if (wc == 'link') { var lhr = car(childElements(e)).href; var hr = lhr.substring(0, 5) == 'link:'? lhr.substring(5) : ''; var t = car(childElements(car(childElements(e)))).innerHTML; return t == f? hr : (t == hr? hr : (t == ''? hr : hr + ',' + t)); } - if (e.className == 'img') { + if (wc == 'img') { var src = car(childElements(e)).src; return src == location.href? '' : src; } - /* - if (e.className == 'iframe') { - var hr = car(childElements(e)).href; - return hr == location.href? '' : hr; - } - */ - if (e.className == 'list') + if (wc == 'list') return ''; - if (e.className == 'table') + if (wc == 'table') return ''; return ''; } @@ -527,41 +375,36 @@ page.text = function(e) { var f = formula(e); var c = constant(e, f); return f == ''? c : (c == ''? f : f + ',' + c); -}; +} /** * Return true if a widget has editable text. */ -page.hastext = function(e) { - if (e.className == 'h1' || e.className == 'h2' || e.className == 'text' || e.className == 'section') +function widgethastext(e) { + var wc = widgetclass(e); + if (wc == 'hd1' || wc == 'hd2' || wc == 'text' || wc == 'section') return true; - if (e.className == 'button' || e.className == 'checkbox') + if (wc == 'button' || wc == 'checkbox') return true; - if (e.className == 'entry' || e.className == 'password') + if (wc == 'entry' || wc == 'password') return true; - /* - if (e.className == 'select') + if (wc == 'select') return false; - */ - if (e.className == 'link') - return true; - if (e.className == 'img') + if (wc == 'link') return true; - /* - if (e.className == 'iframe') + if (wc == 'img') return true; - */ - if (e.className == 'list') + if (wc == 'list') return false; - if (e.className == 'table') + if (wc == 'table') return false; return false; -}; +} /** * Set the text of a widget. */ -page.settext = function(e, t) { +function setwidgettext(e, t) { function formula(t) { if (t.length > 1 && t.substring(0, 1) == '=') return car(t.split(',')); @@ -575,268 +418,690 @@ page.settext = function(e, t) { var f = formula(t); var c = constant(t); - e.id = f != ''? f.substring(1) : ('page:' + e.className); + var wc = widgetclass(e); + e.id = f != ''? f.substring(1) : ('page:' + wc); - if (e.className == 'h1' || e.className == 'h2' || e.className == 'text' || e.className == 'section') { + if (wc == 'hd1' || wc == 'hd2' || wc == 'text' || wc == 'section') { car(childElements(e)).innerHTML = isNil(c)? f : car(c); return t; } - if (e.className == 'button') { + if (wc == 'button') { car(childElements(e)).value = isNil(c)? f : car(c); return t; } - if (e.className == 'entry' || e.className == 'password') { + if (wc == 'entry' || wc == 'password') { car(childElements(e)).defaultValue = isNil(c)? f : car(c); return t; } - if (e.className == 'checkbox') { + if (wc == 'checkbox') { car(childElements(e)).value = isNil(c)? f : car(c); map(function(n) { if (n.nodeName == "SPAN") n.innerHTML = isNil(c)? f : car(c); return n; }, nodeList(e.childNodes)); return t; } - /* - if (e.className == 'select') { + if (wc == 'select') { var ce = car(childElements(car(childElements(e)))); ce.value = isNil(c)? f : car(c); ce.innerHTML = isNil(c)? f : car(c); return t; } - */ - if (e.className == 'list') { + if (wc == 'list') { e.innerHTML = '<table class="datatable" style="width: 100%;;"><tr><td class="datatd">' + (isNil(c)? f : car(c)) + '</td></tr><tr><td class="datatd">...</td></tr></table>'; return t; } - if (e.className == 'table') { + if (wc == 'table') { e.innerHTML = '<table class="datatable" style="width: 100%;"><tr><td class="datatdl">' + (isNil(c)? f : car(c)) + '</td><td class="datatdr">...</td></tr><tr><td class="datatdl">...</td><td class="datatdr">...</td></tr></table>'; return t; } - if (e.className == 'link') { + if (wc == 'link') { var ce = car(childElements(e)); ce.href = isNil(c)? 'link:/index.html' : ('link:' + car(c)); car(childElements(ce)).innerHTML = isNil(c)? (f != ''? f : '/index.html') : isNil(cdr(c))? (f != ''? f : car(c)) : cadr(c); return t; } - if (e.className == 'img') { + if (wc == 'img') { car(childElements(e)).src = isNil(c)? '/public/img.png' : car(c); return t; } - /* - if (e.className == 'iframe') { - car(childElements(e)).href = isNil(c)? '/public/iframe-min.html' : car(c); - return t; - } - */ return ''; -}; +} /** - * Initialize a widget. + * Align a pos along a 9pixel grid. */ -page.initwidget = function(e) { - - // Add a Webkit transform to leverage hardware acceleration - e.style.setProperty('-webkit-transform', 'translate(0px, 0px)', null); - - /* - if (e.className == 'iframe') { - var f = car(childElements(e)); - //e.innerHTML = '<iframe src="' + f.href + '" frameborder="no" scrolling="no"></iframe>'; - return e; - } - */ +function snaptogrid(x) { + return Math.round(x / 10) * 10; +} - if (e.className == 'section') { - e.style.width = '100%'; - return e; - } - if (e.className == 'text' || e.className == 'h1' || e.className == 'h2') { - return e; - } - if (e.className == 'button') { - return e; - } - if (e.className == 'checkbox') { - return e; - } - if (e.className == 'list' || e.className == 'table') { - e.style.width = '100%'; - var t = car(childElements(e)); - t.style.width = '100%'; - return e; - } - if (e.className == 'img') { - var i = car(childElements(e)); - if (i.src != '' && i.src.substring(0, 5) == 'data:') - i.src = '/public/img.png'; - return e; - } - if (e.className == 'entry' || e.className == 'password') { - var i = car(childElements(e)); - i.readOnly = true; - i.style.cursor = 'default'; - return e; - } - if (e.className == 'link') { - var l = car(childElements(e)); - l.onclick = function(e) { return false; }; - return e; - } - return e; +/** + * Bring a node to the top. + */ +function bringtotop(n) { + n.parentNode.appendChild(n); } /** - * Enforce widget position and style constraints. + * Move a widget. */ -page.constrainwidget = function(e) { - if (e.className == 'section' || e.className == 'list' || e.className == 'table') { - e.style.left = ui.pixpos(page.palcx); - return e; - } +var iefixuptransform = ui.isMSIE(); +var fffixupoutline = ui.isFirefox() && (ui.firefoxVersion() > 4); +function movewidget(e, x, y) { + var t = 'translate(' + x + 'px,' + y + 'px)'; + e.style.setProperty('-webkit-transform', t, null); + e.style.setProperty('-moz-transform', t, null); + e.style.setProperty('-o-transform', t, null); + // On Internet Explorer set the property directly as setProperty + // doesn't seem to apply + if (iefixuptransform) + e.style.msTransform = t; + e.style.setProperty('transform', t, null); + e.xtranslate = x; + e.ytranslate = y; return e; -}; +} /** - * Cleanup of a widget before saving it. + * Return a widget bounding rect. */ -page.cleanupwidget = function(e) { - //debug('cleanupwidget', e); +var fffixupbounds = ui.isFirefox() && (ui.firefoxVersion() < 12); +function widgetbounds(e) { + var br = e.getBoundingClientRect(); + if (!fffixupbounds) + return br; + + // On Firefox < 12, apply CSS transform translation to bounding rect manually + //debug('fixup br', e, br.left, br.top, br.right, br.bottom, t[0], t[1]); + function fixuptransform(e) { + var t = widgettransform(e); + if (!isNil(e.xtranslate)) + return [e.xtranslate, e.ytranslate]; + var t = e.style.getPropertyValue('-webkit-transform') || e.style.getPropertyValue('-moz-transform') || + e.style.getPropertyValue('-ms-transform') || e.style.getPropertyValue('-o-transform') || + e.style.getPropertyValue('transform'); + if (t) { + var xy = t.split('(')[1].split(')')[0].split(','); + return [ui.numpos(xy[0]), ui.numpos(xy[1])]; + } + return [0, 0]; + } - // Clear outline - e.style.outline = null; + var t = fixuptransform(e); + var fbr = new Object(); + fbr.left = br.left + t[0]; + fbr.top = br.top + t[1]; + fbr.right = fbr.left + e.offsetWidth; + fbr.bottom = fbr.top + e.offsetHeight; + return fbr; +} - // Clear the Webkit transform - e.style.removeProperty('-webkit-transform'); +/** + * Find a draggable element in a list. + */ +function draggable(x, y, l) { + //debug('draggable?', x, y, l); + if (isNil(l)) + return null; + var n = car(l); + if (isNil(n.id) || n.id == '') { + var d = draggable(x, y, reverse(nodeList(n.childNodes))); + if (!isNil(d)) + return d; + return draggable(x, y, cdr(l)); + } + var br = widgetbounds(n); + //debug('element br', n, br.left, br.top, br.right, br.bottom); + if (x >= br.left && x <= br.right && y >= br.top && y <= br.bottom) + return n; + return draggable(x, y, cdr(l)); +} - if (e.className == 'entry' || e.className == 'password') { - var i = car(childElements(e)); - i.readOnly = false; - i.style.cursor = null; - return e; +/** + * Play page in a frame. + */ +function showplaying() { + $('playPageButton').value = '<'; + $('playdiv').style.display = 'block'; + $('playdiv').visible = true; + $('playdiv').innerHTML = ''; + $('playdiv').innerHTML = '<iframe id="playappframe" style="position: relative; border: 0px;" scrolling="no" frameborder="0" src="/' + appname + '"></iframe>'; + if ($('pagediv').visible) { + $('pagediv').style.display = 'none' + $('pagediv').visible = false; } - if (e.className == 'link') { - var l = car(childElements(e)); - l.onclick = null; - return e; + hidepalette(); + return true; +} + +/** + * Show the page editor. + */ +function showeditor() { + $('playPageButton').value = '>'; + $('pagediv').style.display = 'block' + $('pagediv').visible = true; + if ($('playdiv').visible) { + $('playdiv').style.display = 'none'; + $('playdiv').innerHTML = ''; + $('playdiv').visible = false; } - return e; + hidepalette(); + return true; } /** - * Find a draggable element in a hierarchy of elements. + * Palette animation. */ -page.draggable = function(n, e) { - if (n == e) - return null; - if (!isNil(n.id) && n.id != '') - return n; - return page.draggable(n.parentNode, e); +function palettetransitionend(e) { + if ($('paletteview').className == 'paletteunloaded3dm') + $('paletteview').style.display = 'none'; } +$('paletteview').addEventListener('webkitTransitionEnd', palettetransitionend, false); +$('paletteview').addEventListener('transitionend', palettetransitionend, false); + /** - * Align a pos along a 9pixel grid. + * Show the palette. */ -page.gridsnap = function(x) { - return Math.round(x / 9) * 9; +function showpalette() { + if (ui.isMobile()) { + $('paletteview').className = 'paletteloading3dm'; + $('paletteview').style.display = 'block'; + $('paletteview').visible = true; + ui.async(function transitionview() { + $('paletteview').className = 'paletteloaded3dm'; + }); + } else { + $('paletteview').className = 'paletteloaded3d'; + $('paletteview').style.display = 'block'; + $('paletteview').visible = true; + } + return true; } /** - * Bring an element and its parent to the top. + * Hide the palette. */ -page.bringtotop = function(n) { - n.parentNode.appendChild(n); +function hidepalette() { + if (ui.isMobile()) { + $('paletteview').className = 'paletteunloading3dm'; + $('paletteview').visible = false; + ui.async(function transitionview() { + $('paletteview').className = 'paletteunloaded3dm'; + }); + } else { + $('paletteview').className = 'paletteunloaded3d'; + $('paletteview').style.display = 'none'; + $('paletteview').visible = false; + } + return true; } /** - * Select a widget. + * Create page editor. */ -page.selectwidget = function(n, s, atitle, wvalue, wcopy, wdelete) { - //debug('selectwidget', n, s); - if (isNil(n) || !s) { - // Clear the widget value field - wvalue.value = ''; - wvalue.readOnly = true; - wvalue.style.visibility = 'hidden'; - atitle.style.visibility = 'visible'; - wcopy.disabled = true; - wdelete.disabled = true; +function mkeditor() { + + // Initialize header elements + $('widgetValue').readOnly = true; + $('widgetValue').style.display = 'none'; + $('appTitle').style.display = 'block'; + $('copyWidgetButton').disabled = true; + $('deleteWidgetButton').disabled = true; + $('addWidgetButton').disabled = !editable; + + // Track widget dragging and selection + var dragging = null; + var selected = null; + var moved = false; + var mdown = false; + var moveX = 0; + var moveY = 0; + var dragX = 0; + var dragY = 0; - // Clear the widget outline - if (!isNil(n)) - n.style.outline = null; + /** + * Handle a page change event + */ + function onpagechange(prop) { + if (!editable) + return false; + + var newxml = pagexhtml(); + if (savedxhtml == newxml) + return false; + showstatus('Modified'); + + // Save property changes right away + if (prop) + return save(newxml); + // Autosave other changes after 1 second + ui.delay(function autosave() { + if (savedxhtml == newxml) { + showstatus('Saved'); + return false; + } + return save(newxml); + }, 1000); return true; } - // Outline the widget - n.style.outline = '2px solid #598edd'; + /** + * Handle a widget select event. + */ + function onselectwidget(w) { + if (w == selected) + return true; + selected = w; + return true; + } - // Update the widget value field - wvalue.value = page.text(n); - wvalue.readOnly = false || !editable; - wvalue.style.visibility = 'visible'; - atitle.style.visibility = 'hidden'; - wcopy.disabled = false || !editable; - wdelete.disabled = false || !editable; + /** + * Render widget move animation. + */ + function onmoveanimation() { + //debug('onmoveanimation'); - return true; -}; + // Stop animation if we're not dragging an element anymore + if (dragging == null) + return true; -/** - * Clone a palette element. - */ -page.clone = function(e) { + // Request the next animation frame + ui.animation(onmoveanimation); + + // Nothing to do if the selected widget has not moved + if (moveX == dragX && moveY == dragY) + return true; + + // Compute position of dragged element + var curX = widgetxpos(dragging); + var curY = widgetypos(dragging); + var newX = curX + (moveX - dragX); + var newY = curY + (moveY - dragY); + + var okx = true; + if (newX + dragging.clientWidth > 1024) { + newX = 1024 - dragging.clientWidth; + okx = false; + } + if (newX < 0) { + newX = 0; + okx = false; + } + if (okx) + dragX = moveX; + var oky = true; + if (newY + dragging.clientHeight > 1024) { + newY = 1024 - dragging.clientHeight; + oky= false; + } + if (newY < 0) { + newY = 0; + oky = false; + } + if (oky) + dragY = moveY; + + // On Firefox > 4, remove outline before moving widget as it's not + // correctly painted + if (fffixupoutline) + dragging.style.removeProperty('outline'); + + // Move the dragged element + movewidget(dragging, newX, newY); + + return true; + } /** - * Clone an element's HTML. + * Handle a mouse down event. */ - function mkclone(e) { - var ne = document.createElement('span'); + function onmousedown(e) { + // On mouse controlled devices, run component selection logic right away + if (!ui.isMobile()) { + //debug('onmousedown-click'); + onclick(e); + } - // Skip the palette: prefix - ne.id = 'page:' + e.id.substr(8); + // Find a draggable widget + var d = draggable(moveX, moveY, reverse(nodeList($('pagediv').childNodes))); + //debug('dragging', d, 'selected', selected); + if (d == null || d != selected) + return true; + dragging = d; - // Copy the class and HTML content - ne.className = e.className; - ne.innerHTML = e.innerHTML; + // Remember mouse position + dragX = moveX; + dragY = moveY; - // Fixup the widget style - page.initwidget(ne); + // Start move animation + ui.animation(onmoveanimation); - return ne; + e.preventDefault(); + return true; + } + + if (!ui.isMobile()) { + $('pagediv').onmousedown = function(e) { + //debug('onmousedown', e.target); + mdown = true; + moveX = e.clientX; + moveY = e.clientY; + moved = false; + return onmousedown(e); + }; + $('palettecontent').onmousedown = function(e) { + //debug('onmousedown', e.target); + mdown = true; + moveX = e.clientX; + moveY = e.clientY; + moved = false; + return onmousedown(e); + }; + } else { + $('pagediv').ontouchstart = function(e) { + //debug('ontouchstart'); + mdown = true; + moveX = e.touches[0].clientX; + moveY = e.touches[0].clientY; + moved = false; + return onmousedown(e); + }; + $('pagediv').addEventListener('touchstart', function(e) { + //debug('ontouchstart'); + mdown = true; + moveX = e.touches[0].clientX; + moveY = e.touches[0].clientY; + moved = false; + return onmousedown(e); + }, false); + $('palettecontent').ontouchstart = function(e) { + //debug('ontouchstart'); + mdown = true; + moveX = e.touches[0].clientX; + moveY = e.touches[0].clientY; + moved = false; + return onmousedown(e); + }; } /** - * Clone an element's position. + * Handle a mouse up event. */ - function posclone(ne, e) { - ne.style.position = 'absolute'; - ne.style.left = ui.pixpos(ui.numpos(e.style.left)); - ne.style.top = ui.pixpos(ui.numpos(e.style.top)); - e.parentNode.appendChild(ne); - return ne; + function onmouseup(e) { + // Simulate onclick event + if (ui.isMobile() && !moved) { + //debug('ontouchend-click'); + return onclick(e); + } + + if (dragging == null) + return true; + + // Snap dragged widget to grid + var newX = snaptogrid(widgetxpos(dragging)); + var newY = snaptogrid(widgetypos(dragging)); + movewidget(dragging, newX, newY); + + // Forget dragged element + dragging = null; + + // Trigger page change event + onpagechange(false); + + // On Firefox > 4, re-apply the outline after the widget has been repositioned + if (fffixupoutline && !isNil(selected)) { + ui.delay(function() { + if (!isNil(selected)) + selected.style.outline = '2px solid #598edd'; + }, 32); + } + return true; } - return posclone(mkclone(e), e); -}; + if (!ui.isMobile()) { + window.onmouseup = function(e) { + //debug('onmouseup'); + if (!mdown) + return true; + return onmouseup(e); + }; + } else { + window.ontouchend = function(e) { + //debug('ontouchend'); + if (!mdown) + return true; + return onmouseup(e); + } + } -/** - * Track the current widget. - */ -var widget = null; + if (!ui.isMobile()) { + window.onmousemove = function(e) { + //debug('onmousemove'); + + // Record mouse position + if (e.clientX != moveX) { + moved = true; + moveX = e.clientX; + } + if (e.clientY != moveY) { + moved = true; + moveY = e.clientY; + } + if (dragging == null) + return true; + return false; + }; + } else { + window.ontouchmove = function(e) { + //debug('ontouchmove'); + + // Record touch position + var t = e.touches[0]; + if (t.clientX != moveX) { + moved = true; + moveX = t.clientX; + } + if (t.clientY != moveY) { + moved = true; + moveY = t.clientY; + } + if (dragging == null) + return true; + return false; + }; + } + + /** + * Handle a mouse click event. + */ + function onclick(e) { + + // Find selected element + var palvis = $('paletteview').visible? true : false; + var s = draggable(moveX, moveY, reverse(nodeList((palvis? $('palettecontent') : $('pagediv')).childNodes))); + //debug('selected', s); + if (s == null) { + if (selected != null) { + + // Reset current selection + selectwidget(selected, false); + selected = null; + + // Trigger widget select event + onselectwidget(null); + } + + // Dismiss the palette + if (palvis && isNil(draggable(moveX, moveY, mklist($('palettecontent'))))) + hidepalette(); + + return true; + } + + // Deselect the previously selected element + selectwidget(selected, false); + + // Clone widget dragged from palette + if (s.id.substring(0, 8) == 'palette:') { + selected = clonewidget(s); + + // Add it to the page + $('pagediv').appendChild(selected); + movewidget(selected, widgetxpos(selected) + $('viewcontent').scrollLeft, widgetypos(selected) + $('viewcontent').scrollTop); + + // Hide the palette + hidepalette(); + + // Trigger page change event + onpagechange(true); + + // Select the element + selectwidget(selected, true); + + // Trigger widget select event + onselectwidget(selected); + + return true; + } + + // Bring selected widget to the top + selected = s; + bringtotop(selected); + + // Select the widget + selectwidget(selected, true); + + // Trigger widget select event + onselectwidget(selected); + + return true; + } + + /* + if (!ui.isMobile()) { + $('pagediv').onclick = function(e) { + //debug('onclick'); + moveX = e.clientX; + moveY = e.clientY; + return onclick(e); + }; + } else { + window.onclick = function(e) { + //debug('onclick'); + moveX = e.touches[0].clientX; + moveY = e.touches[0].clientY; + return onclick(e); + }; + } + */ + + /** + * Handle field on change events. + */ + $('widgetValue').onchange = $('widgetValue').onblur = function() { + if (selected == null) + return false; + setwidgettext(selected, $('widgetValue').value); + + // Trigger page change event + onpagechange(true); + return false; + }; + + // Handle add widget event. + $('addWidgetButton').onclick = function() { + + // Show / hide the palette + if ($('paletteview').visible) + return hidepalette(); + return showpalette(); + }; + + // Handle delete event. + $('deleteWidgetButton').onclick = function() { + if (selected == null) + return false; + + // Reset current selection + selectwidget(selected, false); + + // Remove selected widget + selected.parentNode.removeChild(selected); + selected = null; + + // Trigger widget select event + onselectwidget(null); + + // Trigger page change event + onpagechange(true); + return false; + }; + + // Handle copy event. + $('copyWidgetButton').onclick = function() { + if (selected == null) + return false; + if (selected.id.substring(0, 8) == 'palette:') + return false; + + // Reset current selection + selectwidget(selected, false); + + // Clone selected widget + selected = clonewidget(selected); + + // Add it to the page + $('pagediv').appendChild(selected); + + // Move 10 pixels down right + movewidget(selected, widgetxpos(selected) + 10, widgetypos(selected) + 10); + + // Bring it to the top + bringtotop(selected); + + // Select the element + selectwidget(selected, true); + + // Trigger widget select event + onselectwidget(selected); + + // Trigger page change event + onpagechange(true); + return false; + }; + + /** + * Handle play page button event. + */ + $('playPageButton').onclick = function() { + + // Show / hide the page play frame + if ($('playdiv').visible) + return showeditor(); + return showplaying(); + } + + // Show the editor + showeditor(); + + return true; +}; /** - * Get and display an app page. + * Get and display the requested app page. */ -function getpage(name, pagediv) { - if (isNil(name)) +(function getpage() { + if (isNil(appname)) return false; - showStatus('Loading'); + workingstatus(true); + showstatus('Loading'); - return pages.get(name, function(doc) { + return pages.get(appname, function(doc) { // Stop now if we didn't get a page if (doc == null) { - showError('App not available'); + errorstatus('Couldn\'t get the app info'); + workingstatus(false); return false; } @@ -844,67 +1109,56 @@ function getpage(name, pagediv) { var pageentry = car(atom.readATOMEntry(mklist(doc))); var content = namedElementChild("'content", pageentry); var el = isNil(content)? mklist() : elementChildren(content); - var buffer = $('buffer'); if (isNil(el)) - buffer.innerHTML = '<div id="page"></div>'; + $('xhtmlbuffer').innerHTML = '<div id="page"></div>'; else - buffer.innerHTML = writeStrings(writeXML(el, false)); + $('xhtmlbuffer').innerHTML = writeStrings(writeXML(el, false)); // Remove any existing page nodes from the editor div var fnodes = filter(function(e) { - if (isNil(e.id) || e.id == '' || e.id.substr(0, 8) == 'palette:') - return false; - var x = ui.numpos(e.style.left) - 2500; - if (x < 0 || ui.numpos(e.style.top) < 0) + if (isNil(e.id) || e.id == '') return false; return true; - }, nodeList(pagediv.childNodes)); + }, nodeList($('pagediv').childNodes)); map(function(e) { - pagediv.removeChild(e); + $('pagediv').removeChild(e); }, fnodes); - // Append new page nodes to editor + // Fixup widgets and append them to the editor map(function(e) { - pagediv.appendChild(e); - if (!isNil(e.style)) - e.style.left = ui.pixpos(ui.numpos(e.style.left) + 2500); - page.initwidget(e); + $('pagediv').appendChild(e); + fixupwidget(e); return e; - }, nodeList(buffer.childNodes[0].childNodes)); + }, nodeList($('xhtmlbuffer').childNodes[0].childNodes)); - savedpagexhtml = pagexhtml(pagediv); + savedxhtml = pagexhtml($('pagediv')); // Enable author to edit the page author = elementValue(namedElementChild("'author", pageentry)); editable = author == username; - wadd.disabled = !editable; - showStatus(editable? onlineStatus() : 'Read only'); + $('addWidgetButton').disabled = !editable; + if (editable) + onlinestatus(); + else + showstatus('Read only'); + workingstatus(false); return true; }); -} - -/** - * Handle add widget button click event. - */ -wadd.onclick = function(e) { - // Show the widget palette - pagediv.style.left = ui.pixpos(0); -}; +})(); /** * Return the current page XHTML content. */ -function pagexhtml(pagediv) { +function pagexhtml() { // Copy page DOM to hidden buffer - var buffer = $('buffer'); - buffer.innerHTML = '<div id="page"></div>' - var div = buffer.childNodes[0]; + $('xhtmlbuffer').innerHTML = '<div id="page"></div>' + var div = $('xhtmlbuffer').childNodes[0]; // Capture the nodes inside the page div - div.innerHTML = pagediv.innerHTML; + div.innerHTML = $('pagediv').innerHTML; var nodes = nodeList(div.childNodes); map(function(e) { div.removeChild(e); @@ -915,30 +1169,25 @@ function pagexhtml(pagediv) { // part of the page, as well as nodes positioned out the // editing area var fnodes = filter(function(e) { - if (isNil(e.id) || e.id == '' || e.id.substr(0, 8) == 'palette:') - return false; - var x = ui.numpos(e.style.left) - 2500; - if (x < 0 || ui.numpos(e.style.top) < 0) + if (isNil(e.id) || e.id == '') return false; return true; }, nodes); // Reposition and cleanup nodes map(function(e) { - var x = ui.numpos(e.style.left) - 2500; - e.style.left = ui.pixpos(x); - page.cleanupwidget(e); + cleanupwidget(e); return e; }, fnodes); // Sort them by position var snodes = fnodes.sort(function(a, b) { - var ay = ui.numpos(a.style.top); - var by = ui.numpos(b.style.top); + var ay = widgetypos(a); + var by = widgetypos(b); if (ay < by) return -1; if (ay > by) return 1; - var ax = ui.numpos(a.style.left); - var bx = ui.numpos(b.style.left); + var ax = widgetxpos(a); + var bx = widgetxpos(b); if (ax < bx) return -1; if (ax > bx) return 1; return 0; @@ -960,10 +1209,11 @@ function pagexhtml(pagediv) { * Save the current page. */ function save(newxml) { - showStatus('Saving'); + workingstatus(true); + showstatus('Saving'); // Get the current page XHTML content - savedpagexhtml = newxml; + savedxhtml = newxml; // Update the page ATOM entry var entry = '<?xml version="1.0" encoding="UTF-8"?>\n' + '<entry xmlns="http://www.w3.org/2005/Atom">' + @@ -972,108 +1222,21 @@ function save(newxml) { pages.put(appname, entry, function(e) { if (e) { - showStatus('Local copy'); + showstatus('Local copy'); + workingstatus(false); return false; } - showStatus('Saved'); + showstatus('Saved'); + workingstatus(false); return false; }); return true; }; /** - * Handle a page change event - */ -function onpagechange(prop) { - if (!editable) - return false; - - var newxml = pagexhtml(pagediv); - if (savedpagexhtml == newxml) - return false; - showStatus('Modified'); - - // Save property changes right away - if (prop) - return save(newxml); - - // Autosave other changes after 1 second - setTimeout(function() { - if (savedpagexhtml == newxml) { - showStatus('Saved'); - return false; - } - return save(newxml); - }, 1000); - return true; -} - -/** - * Handle a widget select event. - */ -function onselectwidget(w) { - if (w == widget) - return true; - widget = w; - return true; -} - -/** - * Play page in a frame. - */ -function playpage() { - if (!evisible) - return true; - page.selectwidget(widget, false, atitle, wvalue, wcopy, wdelete); - page.selected = null; - pplay.value = '<'; - evisible = false; - pdiv.style.visibility = 'visible'; - pdiv.innerHTML = ''; - pdiv.innerHTML = '<iframe id="playappframe" style="position: relative; height: 5000px; width: 2500px; border: 0px;" scrolling="no" frameborder="0" src="/' + - appname + '"></iframe>'; - setTimeout(function() { - pagediv.style.visibility = 'hidden' - }, 0); - return true; -} - -/** - * Show the page editor. - */ -function showedit() { - if (evisible) - return true; - pplay.value = '>'; - pagediv.style.visibility = 'visible' - evisible = true; - page.selectwidget(widget, true, atitle, wvalue, wcopy, wdelete); - page.selected = widget; - setTimeout(function() { - pdiv.style.visibility = 'hidden'; - pdiv.innerHTML = ''; - }, 0); - return true; -} - -/** - * Handle play page button event. - */ -pplay.onclick = function() { - if (!evisible) - return showedit(); - return playpage(); -} - -/** * Initialize the page editor. */ -page.mkedit(pagediv, atitle, wvalue, wadd, wcopy, wdelete, onpagechange, onselectwidget); - -/** - * Get and display the current app page. - */ -getpage(appname, pagediv); +mkeditor(); })(); </script> diff --git a/sca-cpp/trunk/hosting/server/htdocs/proxy/public/cache/cache-template.cmf b/sca-cpp/trunk/hosting/server/htdocs/proxy/public/cache/cache-template.cmf new file mode 100644 index 0000000000..232b0f9a0e --- /dev/null +++ b/sca-cpp/trunk/hosting/server/htdocs/proxy/public/cache/cache-template.cmf @@ -0,0 +1,11 @@ +CACHE MANIFEST + +# Version SHA1 + +# App resources +/favicon.ico +/proxy/public/oops/ + +NETWORK: +* + diff --git a/sca-cpp/trunk/hosting/server/htdocs/proxy/public/cache/index.html b/sca-cpp/trunk/hosting/server/htdocs/proxy/public/cache/index.html new file mode 100644 index 0000000000..4006001435 --- /dev/null +++ b/sca-cpp/trunk/hosting/server/htdocs/proxy/public/cache/index.html @@ -0,0 +1,51 @@ +<!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="/proxy/public/cache/cache-manifest.cmf"> +<head> +<script type="text/javascript"> +applicationCache.addEventListener('checking', function(e) { + return window.parent.onappcachechecking(e); +}, false); +applicationCache.addEventListener('error', function(e) { + return window.parent.onappcacheerror(e); +}, false); +applicationCache.addEventListener('noupdate', function(e) { + return window.parent.onappcachenoupdate(e); +}, false); +applicationCache.addEventListener('downloading', function(e) { + return window.parent.onappcachedownloading(e); +}, false); +applicationCache.addEventListener('progress', function(e) { + return window.parent.onappcacheprogress(e); +}, false); +applicationCache.addEventListener('updateready', function(e) { + return window.parent.onappcacheupdateready(e); +}, false); +applicationCache.addEventListener('cached', function(e) { + return window.parent.onappcachecached(e); +}, false); +window.onload = function() { + window.parent.onloadappcache(); +}; +</script> +</head> +<body> +</body> +</html> diff --git a/sca-cpp/trunk/hosting/server/htdocs/proxy/public/oops/index.html b/sca-cpp/trunk/hosting/server/htdocs/proxy/public/oops/index.html index b1d118d59a..5ea9d7619d 100644 --- a/sca-cpp/trunk/hosting/server/htdocs/proxy/public/oops/index.html +++ b/sca-cpp/trunk/hosting/server/htdocs/proxy/public/oops/index.html @@ -19,33 +19,50 @@ --> <html> <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>Oops</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-precomposed" href="/proxy/public/touchicon.png"/> <base href="/proxy/public/oops/"/> <script type="text/javascript"> -(function() { +try { + +(function oopshead() { window.appcache = {}; /** * Get and cache a resource. */ -appcache.get = function(uri) { +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(u); } catch(e) {} - if (item != null && item != '') - return item; + if (mode != 'remote') { + var item = null; + try { item = ls.getItem('ui.r.' + u); } catch(e) {} + if (item != null && item != '') + return item; + if (mode == 'local') + return null; + } // Get resource from network var http = new XMLHttpRequest(); - http.open("GET", u, false); + http.open("GET", mode == 'remote'? (u + '?t=' + new Date().getTime() + '&r=' + Math.random()) : u, false); http.setRequestHeader("Accept", "*/*"); http.send(null); if (http.status == 200) { @@ -56,7 +73,7 @@ appcache.get = function(uri) { if (window.debug) debug('http error', u, 'No-Content'); return null; } - try { ls.setItem(u, http.responseText); } catch(e) {} + try { ls.setItem('ui.r.' + u, http.responseText); } catch(e) {} return http.responseText; } if (window.debug) debug('http error', u, http.status, http.statusText); @@ -68,36 +85,32 @@ appcache.get = function(uri) { /** * Load Javascript and CSS. */ -(function() { +(function oopsboot() { var bootjs = document.createElement('script'); bootjs.type = 'text/javascript'; -bootjs.text = appcache.get('/proxy/all-min.js'); -document.head.appendChild(bootjs); -document.head.appendChild(ui.declareCSS(appcache.get('/proxy/ui-min.css'))); +bootjs.text = 'try {\n' + appcache.get('/proxy/all-min.js') + '\n' + appcache.get('/proxy/public/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('/proxy/ui-min.css'))); })(); +} catch(e) { + if (window.debug) debug(e.stack); + throw e; +} </script> </head> <body class="delayed"> -<div id="mainbodydiv" class="mainbodydiv"> - -<div id="headdiv" class="hsection"> -<script type="text/javascript"> -(function() { -$('headdiv').appendChild(ui.declareScript(appcache.get('/proxy/public/config-min.js'))); - -})(); -</script> +<div id="menucontainer" class="tbarmenu"> +<div id="menu"></div> </div> -<div id="menubackground" class="tbarbackground fixed"></div> -<div id="menu" class="tbarmenu fixed"></div> - -<div id="viewheadbackground" class="viewheadbackground fixed"></div> -<div id="viewhead" class="viewhead fixed"></div> +<div id="viewheadcontainer" class="viewhead"> +<div id="viewhead"></div> +</div> <div id="viewcontainer"> <div id="view"> @@ -110,84 +123,250 @@ $('headdiv').appendChild(ui.declareScript(appcache.get('/proxy/public/config-min </div> </div> -<div id="viewfootbackground" class="viewfootbackground fixed"></div> -<div id="viewfoot" class="viewfoot fixed"></div> +<div id="viewfootcontainer" class="viewfoot"> +<div id="viewfoot"></div> +<div id="status"></div> +</div> + +<div id="installer" class="installer"></div> <script type="text/javascript"> -(function() { +try { + +(function oopsbody() { /** - * Init div variables. + * Setup page layout. */ -var mdiv = $('menu'); -var hdiv = $('viewhead'); -$('viewcontainer').className = ui.isMobile()? 'viewcontainer3d' : 'viewcontainer3dm'; -$('view').className = ui.isMobile()? 'viewloaded3d' : 'viewloaded3dm'; -var fdiv = $('viewfoot'); +(function layout() { + $('viewcontainer').className = ui.isMobile()? 'viewcontainer3dm' : 'viewcontainer3d'; + $('view').className = ui.isMobile()? 'viewloaded3dm' : 'viewloaded3d'; + document.title = config.windowtitle() + ' - Oops'; + $('viewhead').innerHTML = '<span class="bcmenu">' + config.pagetitle() + '</span>'; + if (!ui.isMobile()) + $('viewcontent').className = 'viewcontent flatscrollbars'; + $('status').className = ui.isMobile()? 'status3dm' : 'status3d'; +})(); /** - * Set page title. + * Setup menu bar. */ -document.title = config.windowtitle() + ' - Oops'; -$('viewhead').innerHTML = '<span class="bcmenu">' + config.pagetitle() + '</span>'; +(function showmenu() { + $('menu').innerHTML = ui.menubar( + mklist(ui.menu('menuhome', 'Home', '/', '_self', false)), mklist()); + $('viewfoot').innerHTML = config.viewfoot(); +})(); /** - * Build and show the menu bar. + * Initialize status message area. */ -function showmenu(mdiv) { - mdiv.innerHTML = ui.menubar( - mklist(ui.menu('menuhome', 'Home', '/', '_self', false)), - mklist(hasauthcookie()? ui.menufunc('menusignout', 'Sign out', 'return logout();', false) : ui.menu('menusignin', 'Sign in', '/login/', '_self', false))); - fdiv.innerHTML = config.viewfoot(); -} +(function initstatus() { + if (isNil($('status'))) + return; + $('status').style.display = 'none'; + + function divtransitionend(e) { + e.target.style.display = 'none'; + e.target.className = ui.isMobile()? 'status3dm' : 'status3d'; + e.target.error = false; + } + $('status').addEventListener('webkitTransitionEnd', divtransitionend, false); + $('status').addEventListener('transitionend', divtransitionend, false); +})(); -showmenu(mdiv); +/** + * Show a status message. + */ +window.showstatus = function(s, c) { + //debug('show status', s); + if (isNil($('status')) || $('status').error) + return s; + $('status').innerHTML = '<span class="' + (c? c : 'okstatus') + '">' + s + '</span>'; + $('status').className = ui.isMobile()? 'status3dm' : 'status3d'; + $('status').style.display = 'block'; + $('status').error = c == 'errorstatus'; + if ($('status').delay) + ui.cancelDelay($('status').delay); + $('status').delay = ui.delay(function hidestatus() { + $('status').className = ui.isMobile()? 'statusout3dm' : 'statusout3d'; + $('status').error = false; + }, 3000); + return s; +}; /** - * Log the current user out. + * Show an error message. */ -window.logout = function() { - // Clear session cookie and user-specific local storage entries - clearauthcookie(); - lstorage.removeItem('/r/Editor/accounts'); - lstorage.removeItem('/r/Editor/dashboards'); - document.location = '/login/'; - return false; -} +window.errorstatus = function(s) { + //debug('error', s); + return showstatus(s, 'errorstatus'); +}; + +/** + * Show working status. + */ +window.workingstatus = function(w, c) { + //debug('show working', w); + if (isNil($('working'))) + return w; + if (!ui.isMobile()) + $('working').style.top = ui.pixpos(Math.round(window.clientHeight / 2)); + $('working').style.display = w? 'block' : 'none'; + return w; +}; + +/** + * Show the online/offline status. + */ +window.onlinestatus = function() { + return navigator.onLine? (ui.isMobile()? showstatus('Online') : showstatus('Online')) : errorstatus('Offline'); + +}; /** * Handle orientation change. */ document.body.onorientationchange = function(e) { //debug('onorientationchange'); - ui.onorientationchange(e); - - // Resize menu and view header - mdiv.style.width = ui.pixpos(document.documentElement.clientWidth); - hdiv.style.width = ui.pixpos(document.documentElement.clientWidth); - return true; + return ui.onorientationchange(e); }; /** - * Initialize the document. + * Populate cache with app resources. */ -function onload() { - //debug('onload'); - ui.onload(); +var appresources = [ + ['/proxy/all-min.js'], + ['/proxy/ui-min.css'], + ['/proxy/public/config-min.js'] +]; - // Show the page - document.body.style.visibility = 'visible'; - return true; -} +/** + * Install the application cache. + */ +(function installappcache() { + if (ui.isMobile()) { + // On mobile devices, trigger usage of an application cache manifest + window.onappcachechecking = function(e) { + //debug('appcache checking', e); + workingstatus(true); + showstatus('Checking'); + }; + window.onappcacheerror = function(e) { + //debug('appcache error', e); + onlinestatus(); + workingstatus(false); + }; + window.onappcachenoupdate = function(e) { + //debug('appcache noupdate', e); + onlinestatus(); + workingstatus(false); + }; + window.onappcachedownloading = function(e) { + //debug('appcache downloading', e); + workingstatus(true); + showstatus('Updating'); + }; + window.onappcacheprogress = function(e) { + //debug('appcache progress', e); + workingstatus(true); + showstatus('Updating'); + }; + window.onappcacheupdateready = function(e) { + //debug('appcache updateready', e); + try { + applicationCache.swapCache(); + } catch(e) {} + onlinestatus(); + workingstatus(false); + //debug('appcache swapped', e); + + // Update offline resources in local storage and reload the page + map(function(res) { + showstatus('Updating'); + appcache.remove(res[0]); + appcache.get(res[0], 'remote'); + }, append(appresources, config.appresources())); + window.location.reload(); + }; + window.onappcachecached = function(e) { + //debug('appcache cached', e); + onlinestatus(); + workingstatus(false); + + // Install offline resources in local storage + map(function(res) { + showstatus('Updating'); + appcache.remove(res[0]); + appcache.get(res[0], 'remote'); + }, append(appresources, config.appresources())); + }; + + window.onloadappcache = function() { + //debug('appcache iframe loaded'); + }; + + ui.delay(function() { + $('installer').innerHTML = '<iframe src="/proxy/public/cache/" class="installer"></iframe>'; + }); + + } else { + // On non-mobile devices, check for cache-manifest changes ourselves. + workingstatus(true); + showstatus('Checking'); + var lcmf = appcache.get('/proxy/public/cache/cache-manifest.cmf', 'local'); + var rcmf = appcache.get('/proxy/public/cache/cache-manifest.cmf', 'remote'); + if (lcmf == rcmf) { + onlinestatus(); + workingstatus(false); + return true; + } -onload(); + //debug('cache-manifest changed, reloading'); + ui.delay(function() { + showstatus('Updating'); + ui.delay(function() { + map(function(res) { + appcache.remove(res[0]); + appcache.get(res[0], 'remote'); + }, append(appresources, config.appresources())); + if (!isNil(lcmf)) { + //debug('reloading'); + window.location.reload(); + } + onlinestatus(); + workingstatus(false); + }); + }); + } +})(); + +/** + * Handle network offline/online events. + */ +window.addEventListener('offline', function(e) { + //debug('going offline'); + showstatus('Offline'); +}, false); +window.addEventListener('online', function(e) { + //debug('going online'); + showstatus('Online'); +}, false); + +/** + * Initialize the document. + */ +window.onload = function() { + //debug('onload'); + return ui.onload(); +}; })(); -</script> -<div id="footdiv" class="fsection"> -</div> +} catch(e) { + debug(e.stack); + throw e; +} +</script> -</div> </body> </html> diff --git a/sca-cpp/trunk/hosting/server/htdocs/public/app.b64 b/sca-cpp/trunk/hosting/server/htdocs/public/app.b64 index 7ed235aa14..4690a5c79c 100644 --- a/sca-cpp/trunk/hosting/server/htdocs/public/app.b64 +++ b/sca-cpp/trunk/hosting/server/htdocs/public/app.b64 @@ -1 +1 @@ -iVBORw0KGgoAAAANSUhEUgAAADIAAAAyAgMAAABjUWAiAAAABGdBTUEAALGPC/xhBQAAAAxQTFRFyN+N+dR1/PCI////6HjE5gAAADJJREFUKM9j+I8EPjBQifeBAQSY6coLBYN6inhaq0Bg6SDn/f//akB466ExTS6P2ukMAKumzarJO/66AAAAAElFTkSuQmCC
\ No newline at end of file +iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAfklEQVRo3u3YoQ2EQBBA0VlauEJwODQUcw1QAQ1QDGgcjkKo4U4Q0JhNCLyvVs3kZd1E6F6l49H02y/Hgqn7pIiIeogs8+fvbiie8iMgICAgICAgICAgICAgICDSlc67Vu6709pWWeaX4+KuBQICAgICAgICAgICAgICovf1B5ehDldEK+NOAAAAAElFTkSuQmCC diff --git a/sca-cpp/trunk/hosting/server/htdocs/public/app.png b/sca-cpp/trunk/hosting/server/htdocs/public/app.png Binary files differindex 1f73274b76..7293fe7ee5 100644 --- a/sca-cpp/trunk/hosting/server/htdocs/public/app.png +++ b/sca-cpp/trunk/hosting/server/htdocs/public/app.png diff --git a/sca-cpp/trunk/hosting/server/htdocs/public/app.xcf b/sca-cpp/trunk/hosting/server/htdocs/public/app.xcf Binary files differindex 741b7ff43f..b144d46743 100644 --- a/sca-cpp/trunk/hosting/server/htdocs/public/app.xcf +++ b/sca-cpp/trunk/hosting/server/htdocs/public/app.xcf diff --git a/sca-cpp/trunk/hosting/server/htdocs/public/cache/cache-template.cmf b/sca-cpp/trunk/hosting/server/htdocs/public/cache/cache-template.cmf new file mode 100644 index 0000000000..40da327179 --- /dev/null +++ b/sca-cpp/trunk/hosting/server/htdocs/public/cache/cache-template.cmf @@ -0,0 +1,17 @@ +CACHE MANIFEST + +# Version SHA1 + +# App resources +/favicon.ico +/login/ +/public/img.png +/public/notauth/ +/public/notfound/ +/public/notyet/ +/public/oops/ +/public/touchicon.png + +NETWORK: +* + diff --git a/sca-cpp/trunk/hosting/server/htdocs/public/cache/index.html b/sca-cpp/trunk/hosting/server/htdocs/public/cache/index.html new file mode 100644 index 0000000000..c810cc16b8 --- /dev/null +++ b/sca-cpp/trunk/hosting/server/htdocs/public/cache/index.html @@ -0,0 +1,51 @@ +<!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="/public/cache/cache-manifest.cmf"> +<head> +<script type="text/javascript"> +applicationCache.addEventListener('checking', function(e) { + return window.parent.onappcachechecking(e); +}, false); +applicationCache.addEventListener('error', function(e) { + return window.parent.onappcacheerror(e); +}, false); +applicationCache.addEventListener('noupdate', function(e) { + return window.parent.onappcachenoupdate(e); +}, false); +applicationCache.addEventListener('downloading', function(e) { + return window.parent.onappcachedownloading(e); +}, false); +applicationCache.addEventListener('progress', function(e) { + return window.parent.onappcacheprogress(e); +}, false); +applicationCache.addEventListener('updateready', function(e) { + return window.parent.onappcacheupdateready(e); +}, false); +applicationCache.addEventListener('cached', function(e) { + return window.parent.onappcachecached(e); +}, false); +window.onload = function() { + window.parent.onloadappcache(); +}; +</script> +</head> +<body> +</body> +</html> diff --git a/sca-cpp/trunk/hosting/server/htdocs/public/config.js b/sca-cpp/trunk/hosting/server/htdocs/public/config.js index 54818f4810..be23c7c01e 100644 --- a/sca-cpp/trunk/hosting/server/htdocs/public/config.js +++ b/sca-cpp/trunk/hosting/server/htdocs/public/config.js @@ -35,6 +35,10 @@ config.loginprompt = function() { return '<span>Sign in with your userid and password</span>'; }; +config.signuptitle = function() { + return 'Sign up for an account'; +}; + config.viewfoot = function() { return ui.menubar(mklist(ui.menu('menuabout', 'About', '/', '_view', 'note')), mklist()); }; diff --git a/sca-cpp/trunk/hosting/server/htdocs/public/delete.b64 b/sca-cpp/trunk/hosting/server/htdocs/public/delete.b64 deleted file mode 100644 index c8137d7ab4..0000000000 --- a/sca-cpp/trunk/hosting/server/htdocs/public/delete.b64 +++ /dev/null @@ -1 +0,0 @@ -iVBORw0KGgoAAAANSUhEUgAAABkAAAAZCAYAAADE6YVjAAAAAXNSR0IArs4c6QAAAAZiS0dEANAAPwBBXloXjQAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sEFhQaKzNh4PgAAAMKSURBVEjHxZZPTBNBFMa/maVbWjcUi0YiIHIoNBADTUgsqCWgUUFjwkk5CXLUBKIc9KIXjx64oMSDoiggGC8koImCGDWYkADRIiQQgikWCq0WoXW33R0PpYjSLeWP8btN3sv85s17894QrKNeIBng8gFmJSDZgGIAqJeBjQCkH5AHioGZaHsQNUMP+ByKYB0ByVjvIAxsUkHcrRJI9pggXYBWB1pLQUqxQSlg3X4o9WWAqArpAhL04JoIYMQmxQCPD3JlGbCwBtIFaPXgWrcC+AtUEY6Ihg060NrtACyf3KgDrQ2v6e8kbzwH0URBSnvA56xAKIJ1kRzNbS2ZNhYssjodVj41VbPaxqemaqxOh9XGgkXmtpbMyKDQvqQXSKbg2iKGzfPE0v8uV7BYDIuDg95B66FhJkmM8DyxfHifK+TlGRaHhryDBwuHmSSxyBUnn6Ohh6aSQElin86U26XZWVGwWAxZD5tMAGBufmAS8vIMkssl2s+Uj6gBQuLySS/oTQpyONr9GmxHhAMvnltovJZ+73vjTiyyJSmipHw8WTrkfd33Y52385arAr1EAF00R3HqixRwu38mnT61O35/uh4AJq7Ujc0/affEUGsCDfWi9TXX3uEOeDwBABCnp/3OO42uGPuAgQLUG4urueVRlsZo1ACANiVFZ7rTkBFjMXtpqJtGV9q1q3uNJ47vlpd88kTt5VEWCLLk6gtpeyrP74qheY5wlaB6AhSqOSUUFOzIun8vh8RxZKKmZvRrw20X0WjkxCKbceexo0Z3Z+d8wDUXVIeQdgrIA6rFl5DAmVsfZ1MtT+faO5zOxrtzADB1/Ybj28tX85wgxOU8e5pN9XqqHos8QIuBGQY2GTEPD5tM8en79P7x8aWxqurx1bbPZytGRYfDrzOZBHPzA5PanCkGZki4d3GQG7DNksFdLIFkpwBQAsmugHVvJ0AB6w5PypW79EOpZ4BnOwAM8Pih1P/R6gGgDBB9kCu3Clo1GcU1kGXQgg9yxWavTgHrXp6IC///t/Iv/l2/AGa0Qa2X0eC0AAAAAElFTkSuQmCC
\ No newline at end of file diff --git a/sca-cpp/trunk/hosting/server/htdocs/public/delete.png b/sca-cpp/trunk/hosting/server/htdocs/public/delete.png Binary files differdeleted file mode 100644 index fb56bae030..0000000000 --- a/sca-cpp/trunk/hosting/server/htdocs/public/delete.png +++ /dev/null diff --git a/sca-cpp/trunk/hosting/server/htdocs/public/delete.xcf b/sca-cpp/trunk/hosting/server/htdocs/public/delete.xcf Binary files differdeleted file mode 100644 index 7691f50cc5..0000000000 --- a/sca-cpp/trunk/hosting/server/htdocs/public/delete.xcf +++ /dev/null diff --git a/sca-cpp/trunk/hosting/server/htdocs/public/grid72.b64 b/sca-cpp/trunk/hosting/server/htdocs/public/grid72.b64 deleted file mode 100644 index 34be13e5ca..0000000000 --- a/sca-cpp/trunk/hosting/server/htdocs/public/grid72.b64 +++ /dev/null @@ -1 +0,0 @@ -iVBORw0KGgoAAAANSUhEUgAAAEgAAABIAgMAAAAog1vUAAAABGdBTUEAALGPC/xhBQAAAAlQTFRFwuD84/T+////fj9v9QAAACxJREFUOMtjWLUqa9WsVctWrYQxVjAMCqFQdBDCMOrUUaeOOnXUqYPPqZgAABmg/C7pJC7lAAAAAElFTkSuQmCC
\ No newline at end of file diff --git a/sca-cpp/trunk/hosting/server/htdocs/public/grid72.png b/sca-cpp/trunk/hosting/server/htdocs/public/grid72.png Binary files differdeleted file mode 100644 index cf6008171a..0000000000 --- a/sca-cpp/trunk/hosting/server/htdocs/public/grid72.png +++ /dev/null diff --git a/sca-cpp/trunk/hosting/server/htdocs/public/iframe.html b/sca-cpp/trunk/hosting/server/htdocs/public/iframe.html deleted file mode 100644 index e2b862dbaa..0000000000 --- a/sca-cpp/trunk/hosting/server/htdocs/public/iframe.html +++ /dev/null @@ -1,28 +0,0 @@ -<!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> -<head> -</head> -<body style="margin:3px; padding: 0px; background-color: #dcdcdc;"> - -<div>frame ...</div> - -</body> -</html> diff --git a/sca-cpp/trunk/hosting/server/htdocs/public/img.b64 b/sca-cpp/trunk/hosting/server/htdocs/public/img.b64 index 97dae687a0..1025ce0d3a 100644 --- a/sca-cpp/trunk/hosting/server/htdocs/public/img.b64 +++ b/sca-cpp/trunk/hosting/server/htdocs/public/img.b64 @@ -1 +1 @@ -iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAABGdBTUEAALGPC/xhBQAAAIRQTFRFwdt/w9yEw9+MxN2GxN6NxN+Oxd2Mxd6Nxt6Lx96Lx96Nx9+NyN6MyN+MyN+N8u2I8+2I+NBq+NFr+NFt+NFu+NJz+NN0+dR1+dR3+dZw+dh4+9Fy+9Nz++5++++B+++F/NNz/PCH/PCI/PGW/PKc/fKd/vzp/vzq/v7+/v/z/9Jx////nQZfHwAAAIxJREFUOMtj0CYAGKiiQANdUAPdBAZmFMCIYQUzHwrgpKECblYwYEJ2LYoCHi0FMBCEAmF0E3hkxFGABJICXnYWFhY2aVE4EENTwCWgCARKCCCFoUAJFQw9BYycnBz8eBSA04cqPhNAQIX+CiSFhIRE8CiQ10ROMNgUqKNnHGU5FCCrhqZAg7Z5Ey8AALiBh6brcmloAAAAAElFTkSuQmCC
\ No newline at end of file +iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAX0lEQVRYw2NgGGDAyMDAwODe/vY/OZp3VgozMjAwMNhOYSBL/+EcBkamgQ6BUQeMOmDUAaMOGHXAqANGAcX1OQMDA8NFDzOy9OvvODXaHhh1wKgDRh0w6oBRB4y2BxgA0K4ON379R2QAAAAASUVORK5CYII= diff --git a/sca-cpp/trunk/hosting/server/htdocs/public/img.png b/sca-cpp/trunk/hosting/server/htdocs/public/img.png Binary files differindex 2363b25e8e..e05e74fa2d 100644 --- a/sca-cpp/trunk/hosting/server/htdocs/public/img.png +++ b/sca-cpp/trunk/hosting/server/htdocs/public/img.png diff --git a/sca-cpp/trunk/hosting/server/htdocs/public/img.xcf b/sca-cpp/trunk/hosting/server/htdocs/public/img.xcf Binary files differindex ffcc124584..c1736338ec 100644 --- a/sca-cpp/trunk/hosting/server/htdocs/public/img.xcf +++ b/sca-cpp/trunk/hosting/server/htdocs/public/img.xcf diff --git a/sca-cpp/trunk/hosting/server/htdocs/public/notauth/index.html b/sca-cpp/trunk/hosting/server/htdocs/public/notauth/index.html index 89852393bf..f453e0491c 100644 --- a/sca-cpp/trunk/hosting/server/htdocs/public/notauth/index.html +++ b/sca-cpp/trunk/hosting/server/htdocs/public/notauth/index.html @@ -19,33 +19,50 @@ --> <html> <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>Sorry</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-precomposed" href="/public/touchicon.png"/> <base href="/public/notauth/"/> <script type="text/javascript"> -(function() { +try { + +(function notauthhead() { window.appcache = {}; /** * Get and cache a resource. */ -appcache.get = function(uri) { +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(u); } catch(e) {} - if (item != null && item != '') - return item; + if (mode != 'remote') { + var item = null; + try { item = ls.getItem('ui.r.' + u); } catch(e) {} + if (item != null && item != '') + return item; + if (mode == 'local') + return null; + } // Get resource from network var http = new XMLHttpRequest(); - http.open("GET", u, false); + http.open("GET", mode == 'remote'? (u + '?t=' + new Date().getTime() + '&r=' + Math.random()) : u, false); http.setRequestHeader("Accept", "*/*"); http.send(null); if (http.status == 200) { @@ -56,7 +73,7 @@ appcache.get = function(uri) { if (window.debug) debug('http error', u, 'No-Content'); return null; } - try { ls.setItem(u, http.responseText); } catch(e) {} + try { ls.setItem('ui.r.' + u, http.responseText); } catch(e) {} return http.responseText; } if (window.debug) debug('http error', u, http.status, http.statusText); @@ -68,128 +85,287 @@ appcache.get = function(uri) { /** * Load Javascript and CSS. */ -(function() { +(function notauthboot() { 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'))); +bootjs.text = 'try {\n' + appcache.get('/all-min.js') + '\n' + appcache.get('/public/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="mainbodydiv" class="mainbodydiv"> - -<div id="headdiv" class="hsection"> -<script type="text/javascript"> -(function() { -$('headdiv').appendChild(ui.declareScript(appcache.get('/public/config-min.js'))); - -})(); -</script> +<div id="menucontainer" class="tbarmenu"> +<div id="menu"></div> </div> -<div id="menubackground" class="tbarbackground fixed"></div> -<div id="menu" class="tbarmenu fixed"></div> - -<div id="viewheadbackground" class="viewheadbackground fixed"></div> -<div id="viewhead" class="viewhead fixed"></div> +<div id="viewheadcontainer" class="viewhead"> +<div id="viewhead"></div> +</div> <div id="viewcontainer"> <div id="view"> <div id="viewcontent" class="viewcontent" style="margin-left: auto; margin-right: auto; text-align: center;"> <br/> -<div class="hd2">Sorry, you're not authorized to view this page.</div> +<div class="hd2">Sorry, you're not authorized<br/>to view this page.</div> </div> </div> </div> -<div id="viewfootbackground" class="viewfootbackground fixed"></div> -<div id="viewfoot" class="viewfoot fixed"></div> +<div id="viewfootcontainer" class="viewfoot"> +<div id="viewfoot"></div> +<div id="status"></div> +</div> + +<div id="installer" class="installer"></div> <script type="text/javascript"> -(function() { +try { + +(function notauthbody() { /** - * Init div variables. + * Setup page layout. */ -var mdiv = $('menu'); -var hdiv = $('viewhead'); -$('viewhead').innerHTML = '<span class="bcmenu">' + config.pagetitle() + '</span>'; -$('viewcontainer').className = ui.isMobile()? 'viewcontainer3d' : 'viewcontainer3dm'; -$('view').className = ui.isMobile()? 'viewloaded3d' : 'viewloaded3dm'; -var fdiv = $('viewfoot'); +(function layout() { + $('viewcontainer').className = ui.isMobile()? 'viewcontainer3dm' : 'viewcontainer3d'; + $('view').className = ui.isMobile()? 'viewloaded3dm' : 'viewloaded3d'; + document.title = config.windowtitle() + ' - Sorry'; + $('viewhead').innerHTML = '<span class="bcmenu">' + config.pagetitle() + '</span>'; + if (!ui.isMobile()) + $('viewcontent').className = 'viewcontent flatscrollbars'; + $('status').className = ui.isMobile()? 'status3dm' : 'status3d'; +})(); /** - * Set page title. + * Setup menu bar. */ -document.title = config.windowtitle() + ' - Sorry'; -$('viewhead').innerHTML = '<span class="bcmenu">' + config.pagetitle() + '</span>'; +(function showmenu() { + $('menu').innerHTML = ui.menubar( + mklist(ui.menu('menuhome', 'Home', '/', '_self', false)), mklist()); + $('viewfoot').innerHTML = config.viewfoot(); +})(); /** - * Build and show the menu bar. + * Initialize status message area. */ -function showmenu(mdiv) { - mdiv.innerHTML = ui.menubar( - mklist(ui.menu('menuhome', 'Home', '/', '_self', false)), - mklist(hasauthcookie()? ui.menufunc('menusignout', 'Sign out', 'return logout();', false) : ui.menu('menusignin', 'Sign in', '/login/', '_self', false))); - fdiv.innerHTML = config.viewfoot(); -} +(function initstatus() { + if (isNil($('status'))) + return; + $('status').style.display = 'none'; + + function divtransitionend(e) { + e.target.style.display = 'none'; + e.target.className = ui.isMobile()? 'status3dm' : 'status3d'; + e.target.error = false; + } + $('status').addEventListener('webkitTransitionEnd', divtransitionend, false); + $('status').addEventListener('transitionend', divtransitionend, false); +})(); -showmenu(mdiv); +/** + * Show a status message. + */ +window.showstatus = function(s, c) { + //debug('show status', s); + if (isNil($('status')) || $('status').error) + return s; + $('status').innerHTML = '<span class="' + (c? c : 'okstatus') + '">' + s + '</span>'; + $('status').className = ui.isMobile()? 'status3dm' : 'status3d'; + $('status').style.display = 'block'; + $('status').error = c == 'errorstatus'; + if ($('status').delay) + ui.cancelDelay($('status').delay); + $('status').delay = ui.delay(function hidestatus() { + $('status').className = ui.isMobile()? 'statusout3dm' : 'statusout3d'; + $('status').error = false; + }, 3000); + return s; +}; /** - * Log the current user out. + * Show an error message. */ -window.logout = function() { - // Clear session cookie and user-specific local storage entries - clearauthcookie(); - lstorage.removeItem('/r/Editor/accounts'); - lstorage.removeItem('/r/Editor/dashboards'); - document.location = '/login/'; - return false; -} +window.errorstatus = function(s) { + //debug('error', s); + return showstatus(s, 'errorstatus'); +}; + +/** + * Show working status. + */ +window.workingstatus = function(w, c) { + //debug('show working', w); + if (isNil($('working'))) + return w; + if (!ui.isMobile()) + $('working').style.top = ui.pixpos(Math.round(window.clientHeight / 2)); + $('working').style.display = w? 'block' : 'none'; + return w; +}; + +/** + * Show the online/offline status. + */ +window.onlinestatus = function() { + return navigator.onLine? (ui.isMobile()? showstatus('Online') : showstatus('Online')) : errorstatus('Offline'); +}; /** * Handle orientation change. */ document.body.onorientationchange = function(e) { //debug('onorientationchange'); - ui.onorientationchange(e); + return ui.onorientationchange(e); +}; - // Resize menu and view header - mdiv.style.width = ui.pixpos(document.documentElement.clientWidth); - hdiv.style.width = ui.pixpos(document.documentElement.clientWidth); +/** + * Populate cache with app resources. + */ +var appresources = [ + ['/all-min.js'], + ['/ui-min.css'], + ['/public/config-min.js'] +]; - return true; -}; +/** + * Install the application cache. + */ +(function installappcache() { + if (ui.isMobile()) { + // On mobile devices, trigger usage of an application cache manifest + window.onappcachechecking = function(e) { + //debug('appcache checking', e); + workingstatus(true); + showstatus('Checking'); + }; + window.onappcacheerror = function(e) { + //debug('appcache error', e); + onlinestatus(); + workingstatus(false); + }; + window.onappcachenoupdate = function(e) { + //debug('appcache noupdate', e); + onlinestatus(); + workingstatus(false); + }; + window.onappcachedownloading = function(e) { + //debug('appcache downloading', e); + workingstatus(true); + showstatus('Updating'); + }; + window.onappcacheprogress = function(e) { + //debug('appcache progress', e); + workingstatus(true); + showstatus('Updating'); + }; + window.onappcacheupdateready = function(e) { + //debug('appcache updateready', e); + try { + applicationCache.swapCache(); + } catch(e) {} + onlinestatus(); + workingstatus(false); + //debug('appcache swapped', e); + + // Update offline resources in local storage and reload the page + map(function(res) { + showstatus('Updating'); + appcache.remove(res[0]); + appcache.get(res[0], 'remote'); + }, append(appresources, config.appresources())); + window.location.reload(); + }; + window.onappcachecached = function(e) { + //debug('appcache cached', e); + onlinestatus(); + workingstatus(false); + + // Install offline resources in local storage + map(function(res) { + showstatus('Updating'); + appcache.remove(res[0]); + appcache.get(res[0], 'remote'); + }, append(appresources, config.appresources())); + }; + + window.onloadappcache = function() { + //debug('appcache iframe loaded'); + }; + + ui.delay(function() { + $('installer').innerHTML = '<iframe src="/public/cache/" class="installer"></iframe>'; + }); + + } else { + // On non-mobile devices, check for cache-manifest changes ourselves. + workingstatus(true); + showstatus('Checking'); + var lcmf = appcache.get('/public/cache/cache-manifest.cmf', 'local'); + var rcmf = appcache.get('/public/cache/cache-manifest.cmf', 'remote'); + if (lcmf == rcmf) { + onlinestatus(); + workingstatus(false); + return true; + } + + //debug('cache-manifest changed, reloading'); + ui.delay(function() { + showstatus('Updating'); + ui.delay(function() { + map(function(res) { + appcache.remove(res[0]); + appcache.get(res[0], 'remote'); + }, append(appresources, config.appresources())); + if (!isNil(lcmf)) { + //debug('reloading'); + window.location.reload(); + } + onlinestatus(); + workingstatus(false); + }); + }); + } +})(); + +/** + * Handle network offline/online events. + */ +window.addEventListener('offline', function(e) { + //debug('going offline'); + showstatus('Offline'); +}, false); +window.addEventListener('online', function(e) { + //debug('going online'); + showstatus('Online'); +}, false); /** * Initialize the document. */ -function onload() { +window.onload = function() { //debug('onload'); - ui.onload(); - - // Show the page - document.body.style.visibility = 'visible'; - return true; -} - -onload(); + return ui.onload(); +}; })(); -</script> -<div id="footdiv" class="fsection"> -</div> +} catch(e) { + debug(e.stack); + throw e; +} +</script> -</div> </body> </html> diff --git a/sca-cpp/trunk/hosting/server/htdocs/public/notfound/index.html b/sca-cpp/trunk/hosting/server/htdocs/public/notfound/index.html index 8f0d486854..c8475147d7 100644 --- a/sca-cpp/trunk/hosting/server/htdocs/public/notfound/index.html +++ b/sca-cpp/trunk/hosting/server/htdocs/public/notfound/index.html @@ -19,33 +19,50 @@ --> <html> <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>Page not found</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-precomposed" href="/public/touchicon.png"/> <base href="/public/notfound/"/> <script type="text/javascript"> -(function() { +try { + +(function notfoundhead() { window.appcache = {}; /** * Get and cache a resource. */ -appcache.get = function(uri) { +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(u); } catch(e) {} - if (item != null && item != '') - return item; + if (mode != 'remote') { + var item = null; + try { item = ls.getItem('ui.r.' + u); } catch(e) {} + if (item != null && item != '') + return item; + if (mode == 'local') + return null; + } // Get resource from network var http = new XMLHttpRequest(); - http.open("GET", u, false); + http.open("GET", mode == 'remote'? (u + '?t=' + new Date().getTime() + '&r=' + Math.random()) : u, false); http.setRequestHeader("Accept", "*/*"); http.send(null); if (http.status == 200) { @@ -56,7 +73,7 @@ appcache.get = function(uri) { if (window.debug) debug('http error', u, 'No-Content'); return null; } - try { ls.setItem(u, http.responseText); } catch(e) {} + try { ls.setItem('ui.r.' + u, http.responseText); } catch(e) {} return http.responseText; } if (window.debug) debug('http error', u, http.status, http.statusText); @@ -68,36 +85,32 @@ appcache.get = function(uri) { /** * Load Javascript and CSS. */ -(function() { +(function notfoundboot() { 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'))); +bootjs.text = 'try {\n' + appcache.get('/all-min.js') + '\n' + appcache.get('/public/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="mainbodydiv" class="mainbodydiv"> - -<div id="headdiv" class="hsection"> -<script type="text/javascript"> -(function() { -$('headdiv').appendChild(ui.declareScript(appcache.get('/public/config-min.js'))); - -})(); -</script> +<div id="menucontainer" class="tbarmenu"> +<div id="menu"></div> </div> -<div id="menubackground" class="tbarbackground fixed"></div> -<div id="menu" class="tbarmenu fixed"></div> - -<div id="viewheadbackground" class="viewheadbackground fixed"></div> -<div id="viewhead" class="viewhead fixed"></div> +<div id="viewheadcontainer" class="viewhead"> +<div id="viewhead"></div> +</div> <div id="viewcontainer"> <div id="view"> @@ -105,90 +118,255 @@ $('headdiv').appendChild(ui.declareScript(appcache.get('/public/config-min.js')) <br/> <div class="hd2">Sorry, that page was not found.</div> -<div>You may have clicked an expired link or mistyped the address.</div> +<div>You may have clicked an expired link<br/>or mistyped the address.</div> </div> </div> </div> -<div id="viewfootbackground" class="viewfootbackground fixed"></div> -<div id="viewfoot" class="viewfoot fixed"></div> +<div id="viewfootcontainer" class="viewfoot"> +<div id="viewfoot"></div> +<div id="status"></div> +</div> + +<div id="installer" class="installer"></div> <script type="text/javascript"> -(function() { +try { + +(function notfoundbody() { /** - * Init div variables. + * Setup page layout. */ -var mdiv = $('menu'); -var hdiv = $('viewhead'); -$('viewcontainer').className = ui.isMobile()? 'viewcontainer3d' : 'viewcontainer3dm'; -$('view').className = ui.isMobile()? 'viewloaded3d' : 'viewloaded3dm'; -var fdiv = $('viewfoot'); +(function layout() { + $('viewcontainer').className = ui.isMobile()? 'viewcontainer3dm' : 'viewcontainer3d'; + $('view').className = ui.isMobile()? 'viewloaded3dm' : 'viewloaded3d'; + document.title = config.windowtitle() + ' - Page not found'; + $('viewhead').innerHTML = '<span class="bcmenu">' + config.pagetitle() + '</span>'; + if (!ui.isMobile()) + $('viewcontent').className = 'viewcontent flatscrollbars'; + $('status').className = ui.isMobile()? 'status3dm' : 'status3d'; +})(); /** - * Set page title. + * Setup menu bar. */ -document.title = config.windowtitle() + ' - Page not found'; -$('viewhead').innerHTML = '<span class="bcmenu">' + config.pagetitle() + '</span>'; +(function showmenu() { + $('menu').innerHTML = ui.menubar( + mklist(ui.menu('menuhome', 'Home', '/', '_self', false)), mklist()); + $('viewfoot').innerHTML = config.viewfoot(); +})(); /** - * Build and show the menu bar. + * Initialize status message area. */ -function showmenu(mdiv) { - mdiv.innerHTML = ui.menubar( - mklist(ui.menu('menuhome', 'Home', '/', '_self', false)), - mklist(hasauthcookie()? ui.menufunc('menusignout', 'Sign out', 'return logout();', false) : ui.menu('menusignin', 'Sign in', '/login/', '_self', false))); - fdiv.innerHTML = config.viewfoot(); -} +(function initstatus() { + if (isNil($('status'))) + return; + $('status').style.display = 'none'; + + function divtransitionend(e) { + e.target.style.display = 'none'; + e.target.className = ui.isMobile()? 'status3dm' : 'status3d'; + e.target.error = false; + } + $('status').addEventListener('webkitTransitionEnd', divtransitionend, false); + $('status').addEventListener('transitionend', divtransitionend, false); +})(); -showmenu(mdiv); +/** + * Show a status message. + */ +window.showstatus = function(s, c) { + //debug('show status', s); + if (isNil($('status')) || $('status').error) + return s; + $('status').innerHTML = '<span class="' + (c? c : 'okstatus') + '">' + s + '</span>'; + $('status').className = ui.isMobile()? 'status3dm' : 'status3d'; + $('status').style.display = 'block'; + $('status').error = c == 'errorstatus'; + if ($('status').delay) + ui.cancelDelay($('status').delay); + $('status').delay = ui.delay(function hidestatus() { + $('status').className = ui.isMobile()? 'statusout3dm' : 'statusout3d'; + $('status').error = false; + }, 3000); + return s; +}; /** - * Log the current user out. + * Show an error message. */ -window.logout = function() { - // Clear session cookie and user-specific local storage entries - clearauthcookie(); - lstorage.removeItem('/r/Editor/accounts'); - lstorage.removeItem('/r/Editor/dashboards'); - document.location = '/login/'; - return false; -} +window.errorstatus = function(s) { + //debug('error', s); + return showstatus(s, 'errorstatus'); +}; + +/** + * Show working status. + */ +window.workingstatus = function(w, c) { + //debug('show working', w); + if (isNil($('working'))) + return w; + if (!ui.isMobile()) + $('working').style.top = ui.pixpos(Math.round(window.clientHeight / 2)); + $('working').style.display = w? 'block' : 'none'; + return w; +}; + +/** + * Show the online/offline status. + */ +window.onlinestatus = function() { + return navigator.onLine? (ui.isMobile()? showstatus('Online') : showstatus('Online')) : errorstatus('Offline'); +}; /** * Handle orientation change. */ document.body.onorientationchange = function(e) { //debug('onorientationchange'); - ui.onorientationchange(e); - - // Resize menu and view header - mdiv.style.width = ui.pixpos(document.documentElement.clientWidth); - hdiv.style.width = ui.pixpos(document.documentElement.clientWidth); - return true; + return ui.onorientationchange(e); }; /** - * Initialize the document. + * Populate cache with app resources. */ -function onload() { - //debug('onload'); - ui.onload(); +var appresources = [ + ['/all-min.js'], + ['/ui-min.css'], + ['/public/config-min.js'] +]; - // Show the page - document.body.style.visibility = 'visible'; - return true; -} +/** + * Install the application cache. + */ +(function installappcache() { + if (ui.isMobile()) { + // On mobile devices, trigger usage of an application cache manifest + window.onappcachechecking = function(e) { + //debug('appcache checking', e); + workingstatus(true); + showstatus('Checking'); + }; + window.onappcacheerror = function(e) { + //debug('appcache error', e); + onlinestatus(); + workingstatus(false); + }; + window.onappcachenoupdate = function(e) { + //debug('appcache noupdate', e); + onlinestatus(); + workingstatus(false); + }; + window.onappcachedownloading = function(e) { + //debug('appcache downloading', e); + workingstatus(true); + showstatus('Updating'); + }; + window.onappcacheprogress = function(e) { + //debug('appcache progress', e); + workingstatus(true); + showstatus('Updating'); + }; + window.onappcacheupdateready = function(e) { + //debug('appcache updateready', e); + try { + applicationCache.swapCache(); + } catch(e) {} + onlinestatus(); + workingstatus(false); + //debug('appcache swapped', e); + + // Update offline resources in local storage and reload the page + map(function(res) { + showstatus('Updating'); + appcache.remove(res[0]); + appcache.get(res[0], 'remote'); + }, append(appresources, config.appresources())); + window.location.reload(); + }; + window.onappcachecached = function(e) { + //debug('appcache cached', e); + onlinestatus(); + workingstatus(false); + + // Install offline resources in local storage + map(function(res) { + showstatus('Updating'); + appcache.remove(res[0]); + appcache.get(res[0], 'remote'); + }, append(appresources, config.appresources())); + }; + + window.onloadappcache = function() { + //debug('appcache iframe loaded'); + }; + + ui.delay(function() { + $('installer').innerHTML = '<iframe src="/public/cache/" class="installer"></iframe>'; + }); + + } else { + // On non-mobile devices, check for cache-manifest changes ourselves. + workingstatus(true); + showstatus('Checking'); + var lcmf = appcache.get('/public/cache/cache-manifest.cmf', 'local'); + var rcmf = appcache.get('/public/cache/cache-manifest.cmf', 'remote'); + if (lcmf == rcmf) { + onlinestatus(); + workingstatus(false); + return true; + } + + //debug('cache-manifest changed, reloading'); + ui.delay(function() { + showstatus('Updating'); + ui.delay(function() { + map(function(res) { + appcache.remove(res[0]); + appcache.get(res[0], 'remote'); + }, append(appresources, config.appresources())); + if (!isNil(lcmf)) { + //debug('reloading'); + window.location.reload(); + } + onlinestatus(); + workingstatus(false); + }); + }); + } +})(); -onload(); +/** + * Handle network offline/online events. + */ +window.addEventListener('offline', function(e) { + //debug('going offline'); + showstatus('Offline'); +}, false); +window.addEventListener('online', function(e) { + //debug('going online'); + showstatus('Online'); +}, false); + +/** + * Initialize the document. + */ +window.onload = function() { + //debug('onload'); + return ui.onload(); +}; })(); -</script> -<div id="footdiv" class="fsection"> -</div> +} catch(e) { + debug(e.stack); + throw e; +} +</script> -</div> </body> </html> diff --git a/sca-cpp/trunk/hosting/server/htdocs/public/notyet/index.html b/sca-cpp/trunk/hosting/server/htdocs/public/notyet/index.html index e43a992f38..4bcb3728ae 100644 --- a/sca-cpp/trunk/hosting/server/htdocs/public/notyet/index.html +++ b/sca-cpp/trunk/hosting/server/htdocs/public/notyet/index.html @@ -19,33 +19,50 @@ --> <html> <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>Page not found</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-precomposed" href="/public/touchicon.png"/> <base href="/public/notyet/"/> <script type="text/javascript"> -(function() { +try { + +(function notyethead() { window.appcache = {}; /** * Get and cache a resource. */ -appcache.get = function(uri) { +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(u); } catch(e) {} - if (item != null && item != '') - return item; + if (mode != 'remote') { + var item = null; + try { item = ls.getItem('ui.r.' + u); } catch(e) {} + if (item != null && item != '') + return item; + if (mode == 'local') + return null; + } // Get resource from network var http = new XMLHttpRequest(); - http.open("GET", u, false); + http.open("GET", mode == 'remote'? (u + '?t=' + new Date().getTime() + '&r=' + Math.random()) : u, false); http.setRequestHeader("Accept", "*/*"); http.send(null); if (http.status == 200) { @@ -56,7 +73,7 @@ appcache.get = function(uri) { if (window.debug) debug('http error', u, 'No-Content'); return null; } - try { ls.setItem(u, http.responseText); } catch(e) {} + try { ls.setItem('ui.r.' + u, http.responseText); } catch(e) {} return http.responseText; } if (window.debug) debug('http error', u, http.status, http.statusText); @@ -68,127 +85,288 @@ appcache.get = function(uri) { /** * Load Javascript and CSS. */ -(function() { +(function notyetboot() { 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'))); +bootjs.text = 'try {\n' + appcache.get('/all-min.js') + '\n' + appcache.get('/public/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="mainbodydiv" class="mainbodydiv"> - -<div id="headdiv" class="hsection"> -<script type="text/javascript"> -(function() { -$('headdiv').appendChild(ui.declareScript(appcache.get('/public/config-min.js'))); - -})(); -</script> +<div id="menucontainer" class="tbarmenu"> +<div id="menu"></div> </div> -<div id="menubackground" class="tbarbackground fixed"></div> -<div id="menu" class="tbarmenu fixed"></div> - -<div id="viewheadbackground" class="viewheadbackground fixed"></div> -<div id="viewhead" class="viewhead fixed"></div> +<div id="viewheadcontainer" class="viewhead"> +<div id="viewhead"></div> +</div> <div id="viewcontainer"> <div id="view"> <div id="viewcontent" class="viewcontent" style="margin-left: auto; margin-right: auto; text-align: center;"> <br/> -<div class="hd2">Sorry, that page is still under construction.</div> +<div class="hd2">Sorry, this page is still<br/>under construction.</div> <div>Please check back later.</div> </div> </div> </div> -<div id="viewfootbackground" class="viewfootbackground fixed"></div> -<div id="viewfoot" class="viewfoot fixed"></div> +<div id="viewfootcontainer" class="viewfoot"> +<div id="viewfoot"></div> +<div id="status"></div> +</div> + +<div id="installer" class="installer"></div> <script type="text/javascript"> -(function() { +try { + +(function notyetbody() { /** - * Init div variables. + * Setup page layout. */ -var mdiv = $('menu'); -var hdiv = $('viewhead'); -$('viewcontainer').className = ui.isMobile()? 'viewcontainer3d' : 'viewcontainer3dm'; -$('view').className = ui.isMobile()? 'viewloaded3d' : 'viewloaded3dm'; -var fdiv = $('viewfoot'); +(function layout() { + $('viewcontainer').className = ui.isMobile()? 'viewcontainer3dm' : 'viewcontainer3d'; + $('view').className = ui.isMobile()? 'viewloaded3dm' : 'viewloaded3d'; + document.title = config.windowtitle() + ' - Page not found'; + $('viewhead').innerHTML = '<span class="bcmenu">' + config.pagetitle() + '</span>'; + if (!ui.isMobile()) + $('viewcontent').className = 'viewcontent flatscrollbars'; + $('status').className = ui.isMobile()? 'status3dm' : 'status3d'; +})(); /** - * Set page title. + * Setup menu bar. */ -document.title = config.windowtitle() + ' - Page not found'; -$('viewhead').innerHTML = '<span class="bcmenu">' + config.pagetitle() + '</span>'; +(function showmenu() { + $('menu').innerHTML = ui.menubar( + mklist(ui.menu('menuhome', 'Home', '/', '_self', false)), mklist()); + $('viewfoot').innerHTML = config.viewfoot(); +})(); /** - * Build and show the menu bar. + * Initialize status message area. */ -function showmenu(mdiv) { - mdiv.innerHTML = ui.menubar( - mklist(ui.menu('menuhome', 'Home', '/', '_self', false)), - mklist(hasauthcookie()? ui.menufunc('menusignout', 'Sign out', 'return logout();', false) : ui.menu('menusignin', 'Sign in', '/login/', '_self', false))); - fdiv.innerHTML = config.viewfoot(); -} +(function initstatus() { + if (isNil($('status'))) + return; + $('status').style.display = 'none'; + + function divtransitionend(e) { + e.target.style.display = 'none'; + e.target.className = ui.isMobile()? 'status3dm' : 'status3d'; + e.target.error = false; + } + $('status').addEventListener('webkitTransitionEnd', divtransitionend, false); + $('status').addEventListener('transitionend', divtransitionend, false); +})(); -showmenu(mdiv); +/** + * Show a status message. + */ +window.showstatus = function(s, c) { + //debug('show status', s); + if (isNil($('status')) || $('status').error) + return s; + $('status').innerHTML = '<span class="' + (c? c : 'okstatus') + '">' + s + '</span>'; + $('status').className = ui.isMobile()? 'status3dm' : 'status3d'; + $('status').style.display = 'block'; + $('status').error = c == 'errorstatus'; + if ($('status').delay) + ui.cancelDelay($('status').delay); + $('status').delay = ui.delay(function hidestatus() { + $('status').className = ui.isMobile()? 'statusout3dm' : 'statusout3d'; + $('status').error = false; + }, 3000); + return s; +}; /** - * Log the current user out. + * Show an error message. */ -window.logout = function() { - // Clear session cookie and user-specific local storage entries - clearauthcookie(); - lstorage.removeItem('/r/Editor/accounts'); - lstorage.removeItem('/r/Editor/dashboards'); - document.location = '/login/'; - return false; -} +window.errorstatus = function(s) { + //debug('error', s); + return showstatus(s, 'errorstatus'); +}; + +/** + * Show working status. + */ +window.workingstatus = function(w, c) { + //debug('show working', w); + if (isNil($('working'))) + return w; + if (!ui.isMobile()) + $('working').style.top = ui.pixpos(Math.round(window.clientHeight / 2)); + $('working').style.display = w? 'block' : 'none'; + return w; +}; + +/** + * Show the online/offline status. + */ +window.onlinestatus = function() { + return navigator.onLine? (ui.isMobile()? showstatus('Online') : showstatus('Online')) : errorstatus('Offline'); +}; /** * Handle orientation change. */ document.body.onorientationchange = function(e) { //debug('onorientationchange'); - ui.onorientationchange(e); - - // Resize menu and view header - mdiv.style.width = ui.pixpos(document.documentElement.clientWidth); - hdiv.style.width = ui.pixpos(document.documentElement.clientWidth); - return true; + return ui.onorientationchange(e); }; /** - * Initialize the document. + * Populate cache with app resources. */ -function onload() { - //debug('onload'); - ui.onload(); +var appresources = [ + ['/all-min.js'], + ['/ui-min.css'], + ['/public/config-min.js'] +]; - // Show the page - document.body.style.visibility = 'visible'; - return true; -} +/** + * Install the application cache. + */ +(function installappcache() { + if (ui.isMobile()) { + // On mobile devices, trigger usage of an application cache manifest + window.onappcachechecking = function(e) { + //debug('appcache checking', e); + workingstatus(true); + showstatus('Checking'); + }; + window.onappcacheerror = function(e) { + //debug('appcache error', e); + onlinestatus(); + workingstatus(false); + }; + window.onappcachenoupdate = function(e) { + //debug('appcache noupdate', e); + onlinestatus(); + workingstatus(false); + }; + window.onappcachedownloading = function(e) { + //debug('appcache downloading', e); + workingstatus(true); + showstatus('Updating'); + }; + window.onappcacheprogress = function(e) { + //debug('appcache progress', e); + workingstatus(true); + showstatus('Updating'); + }; + window.onappcacheupdateready = function(e) { + //debug('appcache updateready', e); + try { + applicationCache.swapCache(); + } catch(e) {} + onlinestatus(); + workingstatus(false); + //debug('appcache swapped', e); + + // Update offline resources in local storage and reload the page + map(function(res) { + showstatus('Updating'); + appcache.remove(res[0]); + appcache.get(res[0], 'remote'); + }, append(appresources, config.appresources())); + window.location.reload(); + }; + window.onappcachecached = function(e) { + //debug('appcache cached', e); + onlinestatus(); + workingstatus(false); + + // Install offline resources in local storage + map(function(res) { + showstatus('Updating'); + appcache.remove(res[0]); + appcache.get(res[0], 'remote'); + }, append(appresources, config.appresources())); + }; + + window.onloadappcache = function() { + //debug('appcache iframe loaded'); + }; + + ui.delay(function() { + $('installer').innerHTML = '<iframe src="/public/cache/" class="installer"></iframe>'; + }); + + } else { + // On non-mobile devices, check for cache-manifest changes ourselves. + workingstatus(true); + showstatus('Checking'); + var lcmf = appcache.get('/public/cache/cache-manifest.cmf', 'local'); + var rcmf = appcache.get('/public/cache/cache-manifest.cmf', 'remote'); + if (lcmf == rcmf) { + onlinestatus(); + workingstatus(false); + return true; + } + + //debug('cache-manifest changed, reloading'); + ui.delay(function() { + showstatus('Updating'); + ui.delay(function() { + map(function(res) { + appcache.remove(res[0]); + appcache.get(res[0], 'remote'); + }, append(appresources, config.appresources())); + if (!isNil(lcmf)) { + //debug('reloading'); + window.location.reload(); + } + onlinestatus(); + workingstatus(false); + }); + }); + } +})(); -onload(); +/** + * Handle network offline/online events. + */ +window.addEventListener('offline', function(e) { + //debug('going offline'); + showstatus('Offline'); +}, false); +window.addEventListener('online', function(e) { + //debug('going online'); + showstatus('Online'); +}, false); + +/** + * Initialize the document. + */ +window.onload = function() { + //debug('onload'); + return ui.onload(); +}; })(); -</script> -<div id="footdiv" class="fsection"> -</div> +} catch(e) { + debug(e.stack); + throw e; +} +</script> -</div> </body> </html> diff --git a/sca-cpp/trunk/hosting/server/htdocs/public/oops/index.html b/sca-cpp/trunk/hosting/server/htdocs/public/oops/index.html index cc97c5362e..68554efdb0 100644 --- a/sca-cpp/trunk/hosting/server/htdocs/public/oops/index.html +++ b/sca-cpp/trunk/hosting/server/htdocs/public/oops/index.html @@ -19,33 +19,50 @@ --> <html> <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>Oops</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-precomposed" href="/public/touchicon.png"/> <base href="/public/oops/"/> <script type="text/javascript"> -(function() { +try { + +(function oopshead() { window.appcache = {}; /** * Get and cache a resource. */ -appcache.get = function(uri) { +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(u); } catch(e) {} - if (item != null && item != '') - return item; + if (mode != 'remote') { + var item = null; + try { item = ls.getItem('ui.r.' + u); } catch(e) {} + if (item != null && item != '') + return item; + if (mode == 'local') + return null; + } // Get resource from network var http = new XMLHttpRequest(); - http.open("GET", u, false); + http.open("GET", mode == 'remote'? (u + '?t=' + new Date().getTime() + '&r=' + Math.random()) : u, false); http.setRequestHeader("Accept", "*/*"); http.send(null); if (http.status == 200) { @@ -56,7 +73,7 @@ appcache.get = function(uri) { if (window.debug) debug('http error', u, 'No-Content'); return null; } - try { ls.setItem(u, http.responseText); } catch(e) {} + try { ls.setItem('ui.r.' + u, http.responseText); } catch(e) {} return http.responseText; } if (window.debug) debug('http error', u, http.status, http.statusText); @@ -68,36 +85,32 @@ appcache.get = function(uri) { /** * Load Javascript and CSS. */ -(function() { +(function oopsboot() { 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'))); +bootjs.text = 'try {\n' + appcache.get('/all-min.js') + '\n' + appcache.get('/public/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="mainbodydiv" class="mainbodydiv"> - -<div id="headdiv" class="hsection"> -<script type="text/javascript"> -(function() { -$('headdiv').appendChild(ui.declareScript(appcache.get('/public/config-min.js'))); - -})(); -</script> +<div id="menucontainer" class="tbarmenu"> +<div id="menu"></div> </div> -<div id="menubackground" class="tbarbackground fixed"></div> -<div id="menu" class="tbarmenu fixed"></div> - -<div id="viewheadbackground" class="viewheadbackground fixed"></div> -<div id="viewhead" class="viewhead fixed"></div> +<div id="viewheadcontainer" class="viewhead"> +<div id="viewhead"></div> +</div> <div id="viewcontainer"> <div id="view"> @@ -110,84 +123,249 @@ $('headdiv').appendChild(ui.declareScript(appcache.get('/public/config-min.js')) </div> </div> -<div id="viewfootbackground" class="viewfootbackground fixed"></div> -<div id="viewfoot" class="viewfoot fixed"></div> +<div id="viewfootcontainer" class="viewfoot"> +<div id="viewfoot"></div> +<div id="status"></div> +</div> + +<div id="installer" class="installer"></div> <script type="text/javascript"> -(function() { +try { + +(function oopsbody() { /** - * Init div variables. + * Setup page layout. */ -var mdiv = $('menu'); -var hdiv = $('viewhead'); -$('viewcontainer').className = ui.isMobile()? 'viewcontainer3d' : 'viewcontainer3dm'; -$('view').className = ui.isMobile()? 'viewloaded3d' : 'viewloaded3dm'; -var fdiv = $('viewfoot'); +(function layout() { + $('viewcontainer').className = ui.isMobile()? 'viewcontainer3dm' : 'viewcontainer3d'; + $('view').className = ui.isMobile()? 'viewloaded3dm' : 'viewloaded3d'; + document.title = config.windowtitle() + ' - Oops'; + $('viewhead').innerHTML = '<span class="bcmenu">' + config.pagetitle() + '</span>'; + if (!ui.isMobile()) + $('viewcontent').className = 'viewcontent flatscrollbars'; + $('status').className = ui.isMobile()? 'status3dm' : 'status3d'; +})(); /** - * Set page title. + * Setup menu bar. */ -document.title = config.windowtitle() + ' - Oops'; -$('viewhead').innerHTML = '<span class="bcmenu">' + config.pagetitle() + '</span>'; +(function showmenu() { + $('menu').innerHTML = ui.menubar( + mklist(ui.menu('menuhome', 'Home', '/', '_self', false)), mklist()); + $('viewfoot').innerHTML = config.viewfoot(); +})(); /** - * Build and show the menu bar. + * Initialize status message area. */ -function showmenu(mdiv) { - mdiv.innerHTML = ui.menubar( - mklist(ui.menu('menuhome', 'Home', '/', '_self', false)), - mklist(hasauthcookie()? ui.menufunc('menusignout', 'Sign out', 'return logout();', false) : ui.menu('menusignin', 'Sign in', '/login/', '_self', false))); - fdiv.innerHTML = config.viewfoot(); -} +(function initstatus() { + if (isNil($('status'))) + return; + $('status').style.display = 'none'; + + function divtransitionend(e) { + e.target.style.display = 'none'; + e.target.className = ui.isMobile()? 'status3dm' : 'status3d'; + e.target.error = false; + } + $('status').addEventListener('webkitTransitionEnd', divtransitionend, false); + $('status').addEventListener('transitionend', divtransitionend, false); +})(); -showmenu(mdiv); +/** + * Show a status message. + */ +window.showstatus = function(s, c) { + //debug('show status', s); + if (isNil($('status')) || $('status').error) + return s; + $('status').innerHTML = '<span class="' + (c? c : 'okstatus') + '">' + s + '</span>'; + $('status').className = ui.isMobile()? 'status3dm' : 'status3d'; + $('status').style.display = 'block'; + $('status').error = c == 'errorstatus'; + if ($('status').delay) + ui.cancelDelay($('status').delay); + $('status').delay = ui.delay(function hidestatus() { + $('status').className = ui.isMobile()? 'statusout3dm' : 'statusout3d'; + $('status').error = false; + }, 3000); + return s; +}; /** - * Log the current user out. + * Show an error message. */ -window.logout = function() { - // Clear session cookie and user-specific local storage entries - clearauthcookie(); - lstorage.removeItem('/r/Editor/accounts'); - lstorage.removeItem('/r/Editor/dashboards'); - document.location = '/login/'; - return false; -} +window.errorstatus = function(s) { + //debug('error', s); + return showstatus(s, 'errorstatus'); +}; + +/** + * Show working status. + */ +window.workingstatus = function(w, c) { + //debug('show working', w); + if (isNil($('working'))) + return w; + if (!ui.isMobile()) + $('working').style.top = ui.pixpos(Math.round(window.clientHeight / 2)); + $('working').style.display = w? 'block' : 'none'; + return w; +}; + +/** + * Show the online/offline status. + */ +window.onlinestatus = function() { + return navigator.onLine? (ui.isMobile()? showstatus('Online') : showstatus()) : errorstatus('Offline'); +}; /** * Handle orientation change. */ document.body.onorientationchange = function(e) { //debug('onorientationchange'); - ui.onorientationchange(e); - - // Resize menu and view header - mdiv.style.width = ui.pixpos(document.documentElement.clientWidth); - hdiv.style.width = ui.pixpos(document.documentElement.clientWidth); - return true; + return ui.onorientationchange(e); }; /** - * Initialize the document. + * Populate cache with app resources. */ -function onload() { - //debug('onload'); - ui.onload(); +var appresources = [ + ['/all-min.js'], + ['/ui-min.css'], + ['/public/config-min.js'] +]; - // Show the page - document.body.style.visibility = 'visible'; - return true; -} +/** + * Install the application cache. + */ +(function installappcache() { + if (ui.isMobile()) { + // On mobile devices, trigger usage of an application cache manifest + window.onappcachechecking = function(e) { + //debug('appcache checking', e); + workingstatus(true); + showstatus('Checking'); + }; + window.onappcacheerror = function(e) { + //debug('appcache error', e); + onlinestatus(); + workingstatus(false); + }; + window.onappcachenoupdate = function(e) { + //debug('appcache noupdate', e); + onlinestatus(); + workingstatus(false); + }; + window.onappcachedownloading = function(e) { + //debug('appcache downloading', e); + workingstatus(true); + showstatus('Updating'); + }; + window.onappcacheprogress = function(e) { + //debug('appcache progress', e); + workingstatus(true); + showstatus('Updating'); + }; + window.onappcacheupdateready = function(e) { + //debug('appcache updateready', e); + try { + applicationCache.swapCache(); + } catch(e) {} + onlinestatus(); + workingstatus(false); + //debug('appcache swapped', e); + + // Update offline resources in local storage and reload the page + map(function(res) { + showstatus('Updating'); + appcache.remove(res[0]); + appcache.get(res[0], 'remote'); + }, append(appresources, config.appresources())); + window.location.reload(); + }; + window.onappcachecached = function(e) { + //debug('appcache cached', e); + onlinestatus(); + workingstatus(false); + + // Install offline resources in local storage + map(function(res) { + showstatus('Updating'); + appcache.remove(res[0]); + appcache.get(res[0], 'remote'); + }, append(appresources, config.appresources())); + }; + + window.onloadappcache = function() { + //debug('appcache iframe loaded'); + }; + + ui.delay(function() { + $('installer').innerHTML = '<iframe src="/public/cache/" class="installer"></iframe>'; + }); + + } else { + // On non-mobile devices, check for cache-manifest changes ourselves. + workingstatus(true); + showstatus('Checking'); + var lcmf = appcache.get('/public/cache/cache-manifest.cmf', 'local'); + var rcmf = appcache.get('/public/cache/cache-manifest.cmf', 'remote'); + if (lcmf == rcmf) { + onlinestatus(); + workingstatus(false); + return true; + } + + //debug('cache-manifest changed, reloading'); + ui.delay(function() { + showstatus('Updating'); + ui.delay(function() { + map(function(res) { + appcache.remove(res[0]); + appcache.get(res[0], 'remote'); + }, append(appresources, config.appresources())); + if (!isNil(lcmf)) { + //debug('reloading'); + window.location.reload(); + } + onlinestatus(); + workingstatus(false); + }); + }); + } +})(); -onload(); +/** + * Handle network offline/online events. + */ +window.addEventListener('offline', function(e) { + //debug('going offline'); + showstatus('Offline'); +}, false); +window.addEventListener('online', function(e) { + //debug('going online'); + showstatus('Online'); +}, false); + +/** + * Initialize the document. + */ +window.onload = function() { + //debug('onload'); + return ui.onload(); +}; })(); -</script> -<div id="footdiv" class="fsection"> -</div> +} catch(e) { + debug(e.stack); + throw e; +} +</script> -</div> </body> </html> diff --git a/sca-cpp/trunk/hosting/server/htdocs/public/rate.png b/sca-cpp/trunk/hosting/server/htdocs/public/rate.png Binary files differnew file mode 100644 index 0000000000..27c744c5a6 --- /dev/null +++ b/sca-cpp/trunk/hosting/server/htdocs/public/rate.png diff --git a/sca-cpp/trunk/hosting/server/htdocs/public/rate.xcf b/sca-cpp/trunk/hosting/server/htdocs/public/rate.xcf Binary files differnew file mode 100644 index 0000000000..eb807f6005 --- /dev/null +++ b/sca-cpp/trunk/hosting/server/htdocs/public/rate.xcf diff --git a/sca-cpp/trunk/hosting/server/htdocs/public/ratings.png b/sca-cpp/trunk/hosting/server/htdocs/public/ratings.png Binary files differnew file mode 100644 index 0000000000..9c10be52dd --- /dev/null +++ b/sca-cpp/trunk/hosting/server/htdocs/public/ratings.png diff --git a/sca-cpp/trunk/hosting/server/htdocs/public/ratings.xcf b/sca-cpp/trunk/hosting/server/htdocs/public/ratings.xcf Binary files differnew file mode 100644 index 0000000000..cad8d31b2e --- /dev/null +++ b/sca-cpp/trunk/hosting/server/htdocs/public/ratings.xcf diff --git a/sca-cpp/trunk/hosting/server/htdocs/public/search.png b/sca-cpp/trunk/hosting/server/htdocs/public/search.png Binary files differnew file mode 100644 index 0000000000..d5178fea3c --- /dev/null +++ b/sca-cpp/trunk/hosting/server/htdocs/public/search.png diff --git a/sca-cpp/trunk/hosting/server/htdocs/public/search.xcf b/sca-cpp/trunk/hosting/server/htdocs/public/search.xcf Binary files differnew file mode 100644 index 0000000000..30d03df40a --- /dev/null +++ b/sca-cpp/trunk/hosting/server/htdocs/public/search.xcf diff --git a/sca-cpp/trunk/hosting/server/htdocs/public/touchicon-50.xcf b/sca-cpp/trunk/hosting/server/htdocs/public/touchicon-50.xcf Binary files differnew file mode 100644 index 0000000000..8dcc8e4f1b --- /dev/null +++ b/sca-cpp/trunk/hosting/server/htdocs/public/touchicon-50.xcf diff --git a/sca-cpp/trunk/hosting/server/htdocs/public/touchicon-53.xcf b/sca-cpp/trunk/hosting/server/htdocs/public/touchicon-53.xcf Binary files differnew file mode 100644 index 0000000000..b2dcd6f12c --- /dev/null +++ b/sca-cpp/trunk/hosting/server/htdocs/public/touchicon-53.xcf diff --git a/sca-cpp/trunk/hosting/server/htdocs/public/touchicon-57.xcf b/sca-cpp/trunk/hosting/server/htdocs/public/touchicon-57.xcf Binary files differnew file mode 100644 index 0000000000..5ab284973d --- /dev/null +++ b/sca-cpp/trunk/hosting/server/htdocs/public/touchicon-57.xcf diff --git a/sca-cpp/trunk/hosting/server/htdocs/public/touchicon.b64 b/sca-cpp/trunk/hosting/server/htdocs/public/touchicon.b64 deleted file mode 100644 index 2239f6ae0f..0000000000 --- a/sca-cpp/trunk/hosting/server/htdocs/public/touchicon.b64 +++ /dev/null @@ -1 +0,0 @@ -iVBORw0KGgoAAAANSUhEUgAAADkAAAA5CAIAAAADehTSAAAAAXNSR0IArs4c6QAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sDGxMkCJXGmL8AAAHwSURBVGje7ZpNbhNBEIXf625sCzA/QUhkg8SGiGxZcpDcgRux5hLkEjkE7BAS9gIyk+muxyZIsSeOG09bsXHX0p4pfVNdP8/loSTsiTnsj1XWyrrMutVSG+ic/ftNqe1mIMtSjsPUu9EQJ6H/UdvNLr59cgwFWaM1p8dnLx6dFGYF6RhIXzLVGIChB3VX8Fg0DWrPqqyHxTq4MUnKKEEBoNvIN4uxiqTkofUXpgZKsqtMx3Djpb45lNWAxxbfXf6wtdH9+vkKBLLGrFLz4M1HTk+K5gAIgBCVcaTI1gOK/acazqqbw2PdYzE7tdyh9AFJTL0zNDIJMInAZpKPzBzmIZuUnjoa9QQkOBHAyWbigYDaTslybg/59f7Q4+003pqwhqcbqjLH9H2OXw0Ksl6XsWB/a39lhf1rz8vOnKoHKmtlrayVtbLuuc6SFK1Z2hEZkBwAv1us4zA9PT7rDX3v9dPiOeBxT/uY0A+qd6Pbl2Sax/kXDN9LlcrXO3Rk9k/QWluVtbIe2O5toBGwFum3bLH/pEso7RarrPNHH/D8JbBIpsjJqx2Lq3Xu2Xv61yvXJzf6/b3nK2Htyu8WB9P/XltF/wfVllgFxet9azGL+bjMD5IUYbPSMktwT8hRSdalkizcufKcs77vUlkr61bsD5lbwtgOKPT2AAAAAElFTkSuQmCC
\ No newline at end of file diff --git a/sca-cpp/trunk/hosting/server/htdocs/public/touchicon.png b/sca-cpp/trunk/hosting/server/htdocs/public/touchicon.png Binary files differindex f22c33d2a0..1975eb16bf 100644 --- a/sca-cpp/trunk/hosting/server/htdocs/public/touchicon.png +++ b/sca-cpp/trunk/hosting/server/htdocs/public/touchicon.png diff --git a/sca-cpp/trunk/hosting/server/htdocs/public/touchicon.xcf b/sca-cpp/trunk/hosting/server/htdocs/public/touchicon.xcf Binary files differdeleted file mode 100644 index fc713b478b..0000000000 --- a/sca-cpp/trunk/hosting/server/htdocs/public/touchicon.xcf +++ /dev/null diff --git a/sca-cpp/trunk/hosting/server/htdocs/public/user.b64 b/sca-cpp/trunk/hosting/server/htdocs/public/user.b64 index 7ed235aa14..70e650a50b 100644 --- a/sca-cpp/trunk/hosting/server/htdocs/public/user.b64 +++ b/sca-cpp/trunk/hosting/server/htdocs/public/user.b64 @@ -1 +1 @@ -iVBORw0KGgoAAAANSUhEUgAAADIAAAAyAgMAAABjUWAiAAAABGdBTUEAALGPC/xhBQAAAAxQTFRFyN+N+dR1/PCI////6HjE5gAAADJJREFUKM9j+I8EPjBQifeBAQSY6coLBYN6inhaq0Bg6SDn/f//akB466ExTS6P2ukMAKumzarJO/66AAAAAElFTkSuQmCC
\ No newline at end of file +iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAADG0lEQVRo3u3a326iQBQG8G8EhAIRMFXHJrXEJo0XNfER+jz7PrvP04fojb0gJq2BaCOmBUuRMntls82a/hkYdDeeW+OnPweGMycC/0kRALi+vmb/MuLq6orU/pcVOUAOEEEliwhVVRWUUjiOA13XIcsysizDarVCGIYIggAvLy/7C5EkCf1+H91uF4SQd68pigLLsmBZFs7OzuD7PjzPw+vr635BDMPA5eUlNE37fM8nBCcnJ2g2m7i5uUEcx/txj5imidFo9CXEn6VpGkajEUzT3D1EVVUMh0PIMt/iyrKM4XAIVVV3CxkMBqjX64Uy6vU6BoPB7iCUUti2Xco9Zts2KKXVQwghcF231C3Udd2/djvhkE6nU/i63na/dTqdaiFFLgMRuTXem9OyLCGQRqPBtXlwQRzHEXdAIoQrv8b7q4ksnnwuiGEYQiE8+VyQsnerMvK5IIqiCIXw5HNBajWx5zGefK5vxJjYoQtPPhckyzKhEJ58LkiapkIhPMdgLshqtRIKeX5+rgby9PQkFMKTzwVZLpdCITz5XJAoipAkiRBEkiSIoqi6Nn42mwmB8OZyQ6bTKfI8LxWR5zmm02m1kDRN4ft+qRDf97m39kK9xmQyKe2ZkqYpJpPJbqYoWZZhPB4XblkYYxiPx4U6hsLd32KxgOd5hTI8z8NisSiUUcrs9/7+HgDQ7/e/Nc5hjMHzvLf37xyywcRxjIuLiy/NgJMkwe3tLcIwLOXzC0EURYFhGDAMA5qmQdM0rNdrSJIEWZa3rk6e50jTFFEUodlsQtd1xHGMOI6xXq+rgWiaBsdxYNs2Go3Gt6fvm0PTBr1tlR4fH7FcLhGG4be6h08hpmmi1Wrh+PgYuq4L7bE2wHa7/dZlPzw8YD6ff9q2bIXIsgxKKSilwicmH5Wu6+j1euj1eojjGEEQIAiCrdv0O8jR0RFOT0/RbrchSRL2qQzDwPn5OVzXxWw2w93d3btzi7wBuK6LVqvFPQ2vqiRJQrfbBaUU8/n8rRsgjLGfjLEf+w746FlECPlFmOiRSEV1+OfDAXKAfFy/AU/NFLNNzbKxAAAAAElFTkSuQmCC diff --git a/sca-cpp/trunk/hosting/server/htdocs/public/user.png b/sca-cpp/trunk/hosting/server/htdocs/public/user.png Binary files differindex 1f73274b76..e99b30815d 100644 --- a/sca-cpp/trunk/hosting/server/htdocs/public/user.png +++ b/sca-cpp/trunk/hosting/server/htdocs/public/user.png diff --git a/sca-cpp/trunk/hosting/server/htdocs/public/user.xcf b/sca-cpp/trunk/hosting/server/htdocs/public/user.xcf Binary files differnew file mode 100644 index 0000000000..2f304c45a7 --- /dev/null +++ b/sca-cpp/trunk/hosting/server/htdocs/public/user.xcf diff --git a/sca-cpp/trunk/hosting/server/htdocs/rate/index.html b/sca-cpp/trunk/hosting/server/htdocs/rate/index.html new file mode 100644 index 0000000000..22f11f631a --- /dev/null +++ b/sca-cpp/trunk/hosting/server/htdocs/rate/index.html @@ -0,0 +1,190 @@ +<!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. +--> +<div id="bodydiv" class="body"> + +<div id="viewform" class="viewform"> + +<form id="rateAppForm"> +<table style="width: 100%;"> +<tr><td class="label">Rating:</td></tr> +<tr><td class="lightlabel" id="taptorate"></td></tr> +<tr><td class="label"> +<span style="display: inline-block; width: 2px;"></span> +<span id="rateApp1" class="graystar"> </span><span style="display: inline-block; width: 20px;"></span> +<span id="rateApp2" class="graystar"> </span><span style="display: inline-block; width: 20px;"></span> +<span id="rateApp3" class="graystar"> </span><span style="display: inline-block; width: 20px;"></span> +<span id="rateApp4" class="graystar"> </span> +</td></tr> +<tr><td class="lightlabel" id="ratedescription"> </span></td></tr> +<tr><td style="padding-top: 20px;"> +<input id="rateAppDoneButton" type="button" class="graybutton" value="Done"/> +</td></tr> +</table> +</form> +<br/> + +</div> + +<script type="text/javascript"> +(function ratebody() { + +/** + * Get the app name. + */ +var appname = ui.fragmentParams(location)['app']; + +/** + * Setup page layout. + */ +(function layout() { + document.title = config.windowtitle() + ' - ' + 'Rate' + ' - ' + appname; + $('viewhead').innerHTML = '<span class="smenu">' + 'Rate' + ' ' + appname + '</span>'; + if (!ui.isMobile()) + $('viewform').className = 'viewform flatscrollbars'; + + $('viewform').appendChild(ui.declareCSS( + '.redstar { ' + + 'background: url(\'' + ui.b64png(appcache.get('/public/rate.b64')) + '\'); background-repeat: no-repeat; ' + + 'vertical-align: middle; width: 40px; height: 40px; display: inline-block; background-position: 0px 1px;' + + ' } ' + + '.graystar { ' + + 'background: url(\'' + ui.b64png(appcache.get('/public/rate.b64')) + '\'); background-repeat: no-repeat; ' + + 'vertical-align: middle; width: 40px; height: 40px; display: inline-block; background-position: -50px 1px;' + + ' }')); + + $('taptorate').innerHTML = ui.isMobile()? 'Tap a star to select a rating' : ' Click a star to select a rating'; +})(); + +/** + * Initialize service references. + */ +var editorComp = sca.component("Editor"); +var reviews = sca.reference(editorComp, "reviews"); + +/** + * Initialize the rate buttons. + */ +var rateAppButtons = [ + [$('rateApp1'), 1, function() { return onclickrating(1); }, 'Don\'t like it'], + [$('rateApp2'), 2, function() { return onclickrating(2); }, 'It\'s ok'], + [$('rateApp3'), 3, function() { return onclickrating(3); }, 'It\'s good'], + [$('rateApp4'), 4, function() { return onclickrating(4); }, 'It\'s great'] +]; +(function initRateAppButtons() { + map(function(b) { + b[0].onclick = b[2]; + }, rateAppButtons); +})(); + +/** + * Select a rating. + */ +var selectedrating = 0; +function selectrating(r) { + selectedrating = r; + map(function(b) { + b[0].className = b[1] <= r? 'redstar' : 'graystar'; + }, rateAppButtons); + $('ratedescription').innerHTML = rateAppButtons[r - 1][3]; + return true; +} + +/** + * The current app entry and corresponding saved XML content. + */ +var appentry; +var savedxml = ''; + +/** + * Get and display the requested app rating. + */ +(function getrating() { + if (isNil(appname)) + return false; + workingstatus(true); + showstatus('Loading'); + + return reviews.get(appname, function(doc) { + + // Stop now if we didn't get the rating + if (doc == null) { + onlinestatus(); + workingstatus(false); + return false; + } + + appentry = doc != null? car(elementsToValues(atom.readATOMEntry(mklist(doc)))) : mklist("'entry", mklist("'title", ''), mklist("'id", appname)); + savedxml = car(atom.writeATOMEntry(valuesToElements(mklist(appentry)))); + var content = cadr(assoc("'content", appentry)); + if (!isNil(content)) + selectrating(parseInt(cadr(content))); + + onlinestatus(); + workingstatus(false); + return true; + }); +})(); + +/** + * Save an app rating. + */ +function save(name, entryxml) { + workingstatus(true); + showstatus('Saving'); + + savedxml = entryxml; + reviews.put(name, savedxml, function(e) { + if (e) { + showstatus('Local copy'); + workingstatus(false); + return false; + } + showstatus('Saved'); + workingstatus(false); + return false; + }); + return false; +} + +/** + * Handle rating click event. + */ +function onclickrating(r) { + // Select the rating + selectrating(r); + + // Save + showstatus('Saving'); + appentry = mklist("'entry", mklist("'title", appname), mklist("'id", appname), mklist("'content", mklist("'rating", selectedrating.toString()))); + var entryxml = car(atom.writeATOMEntry(valuesToElements(mklist(appentry)))); + return save(appname, entryxml); +} + +/** + * Navigate back. + */ +$('rateAppDoneButton').onclick = function() { + history.back(); +}; + +})(); +</script> + +</div> diff --git a/sca-cpp/trunk/hosting/server/htdocs/search/index.html b/sca-cpp/trunk/hosting/server/htdocs/search/index.html new file mode 100644 index 0000000000..47d5a757f3 --- /dev/null +++ b/sca-cpp/trunk/hosting/server/htdocs/search/index.html @@ -0,0 +1,196 @@ +<!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. +--> +<div id="bodydiv" class="body"> + +<div id="viewcontent" class="viewcontent"> + +<div id="apps"></div> +<br/> + +</div> + +<script type="text/javascript"> +(function searchbody() { + +/** + * Setup page layout. + */ +(function layout() { + document.title = config.windowtitle() + ' - Apps'; + if (!ui.isMobile()) + $('viewcontent').className = 'viewcontent flatscrollbars'; + + $('viewhead').innerHTML = '<form id="searchForm">' + + '<span style="position: absolute; top: 0px; left: 5px; right: 70px; padding: 0px; background: transparent;"><input type="text" id="searchQuery" value="" class="flatentry" title="Search" autocapitalize="off" placeholder="Search for apps" style="position: absolute; left: 0px; top: 4px; width: 100%;"></span>' + + '<input type="submit" id="searchButton" title="Search" class="bluebutton search" style="position: absolute; top: 4px; right: 5px; width: 60px; background-position: center center; background-repeat: no-repeat; background-image: url(\'' + ui.b64png(appcache.get('/public/search.b64')) + '\');" value=" "/>' + + '</form>'; + + $('viewcontent').appendChild(ui.declareCSS( + '.ratings { ' + + 'background: url(\'' + ui.b64png(appcache.get('/public/ratings.b64')) + '\'); ' + + 'margin-top: 6px; width: 50px; height: 14px; display: inline-block; ' + + ' }')); +})(); + +/** + * Initialize service references. + */ +var editorComp = sca.component("Editor"); +var search = sca.reference(editorComp, "search"); +var icons = sca.reference(editorComp, "icons"); + +/** + * Edit an app. + */ +function editapp(appname) { + return ui.navigate('/#view=page&app=' + appname, '_view'); +} + +/** + * View an app. + */ +function viewapp(appname) { + return ui.navigate('/#view=info&app=' + appname, '_view'); +} + +/** + * Get and display an app icon. + */ +function geticon(appname) { + if (isNil(appname)) + return false; + + return icons.get(appname, function(doc) { + // Stop now if we didn't get an icon + if (doc == null) + return false; + + var iconentry = car(elementsToValues(atom.readATOMEntry(mklist(doc)))); + var content = assoc("'content", iconentry); + var icon = assoc("'icon", content); + var img = assoc("'image", icon); + if (!isNil(img)) { + var appimg = $('search_app_img_' + appname); + if (!isNil(appimg)) + appimg.src = cadr(img); + } + return true; + }); + return true; +} + +/** + * Get and display list of apps. + */ +function getapps(query) { + workingstatus(true); + showstatus('Searching'); + + function display(doc) { + + // Stop now if we didn't get the apps + if (doc == null) { + errorstatus('Not available'); + workingstatus(false); + return false; + } + + var feed = car(elementsToValues(atom.readATOMFeed(mklist(doc)))); + var aentries = assoc("'entry", feed); + var entries = isNil(aentries)? mklist() : isList(car(cadr(aentries)))? cadr(aentries) : mklist(cdr(aentries)); + + var defappimg = ui.b64png(appcache.get('/public/app.b64')); + + var apps = '<div>'; + var icons = mklist(); + + (function displayentries(entries) { + if (isNil(entries)) + return apps; + var entry = car(entries); + var title = cadr(assoc("'title", entry)) + var name = cadr(assoc("'id", entry)); + var author = cadr(assoc("'author", entry)); + var updated = xmldatetime(cadr(assoc("'updated", entry))).toLocaleDateString(); + + var aratings = assoc("'info", assoc("'content", entry)); + var ar = assoc("'rating", aratings); + var ar1 = assoc("'rating1", aratings); + var ar2 = assoc("'rating2", aratings); + var ar3 = assoc("'rating3", aratings); + var ar4 = assoc("'rating4", aratings); + var rating = isNil(ar)? 0 : Number(cadr(ar)); + var reviews = (isNil(ar1)? 0 : Number(cadr(ar1))) + (isNil(ar2)? 0 : Number(cadr(ar2))) + (isNil(ar3)? 0 : Number(cadr(ar3))) + (isNil(ar4)? 0 : Number(cadr(ar4))); + + apps += '<div class="box">' + apps += '<div class="appicon">' + apps += ui.href('appicon_' + name, '/#view=info&app=' + name, '_view', '<img id="search_app_img_' + name + '" src="' + defappimg + '" width="50" height="50"></img>'); + //apps += '<br/><input type="button" class="lightbutton" value="Run" onclick="ui.navigate(\'/' + name + '/\', \'_blank\');"/>'; + apps += '</div>' + apps += '<div class="appdetails">'; + apps += '<span class="apptitle">' + ui.href('search_app_title_' + name, '/#view=info&app=' + name, '_view', name) + '</span>'; + apps += '<br/><span>' + 'by ' + author.split('@')[0] + '</span>'; + var ratingy = -20 * (4 - Math.floor(rating)); + apps += '<br/><span class="ratings" style="background-position: 0px ' + ratingy + 'px;"> </span>'; + apps += '<br/><span style="font-size: 10px;">' + reviews + (reviews > 1? ' ratings' : ' rating') + '</span>'; + /*apps += '<br/><span>' + updated + '</span>';*/ + apps += '</div>'; + apps += '</div>'; + + icons = cons(name, icons); + + return displayentries(cdr(entries)); + })(entries); + + apps += '</div>'; + $('apps').innerHTML = apps; + + ui.unmemo$('search_app_'); + + (function displayicons(icons) { + if (isNil(icons)) + return true; + geticon(car(icons)); + return displayicons(cdr(icons)); + })(reverse(icons)); + + onlinestatus(); + workingstatus(false); + } + + return search.get('?q=' + query, display); +} + +/** + * Handle search form submit. + */ +$('searchForm').onsubmit = function() { + if ($('searchQuery').value.trim() == '') + return false; + if (ui.isMobile()) + $('searchQuery').blur(); + getapps($('searchQuery').value.trim()); + return false; +}; + +})(); +</script> + +</div> diff --git a/sca-cpp/trunk/hosting/server/htdocs/stats/index.html b/sca-cpp/trunk/hosting/server/htdocs/stats/index.html deleted file mode 100644 index 7c3d9a6434..0000000000 --- a/sca-cpp/trunk/hosting/server/htdocs/stats/index.html +++ /dev/null @@ -1,179 +0,0 @@ -<!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. ---> -<div id="bodydiv" class="body"> - -<div class="viewform"> - -<form id="appForm"> -<table style="width: 100%;"> -<tr><tr><td><b>Icon:</b></td></tr> -<tr><td><img id="appimg" style="width: 50px; height: 50px; vertical-align: top;"></td></tr> -<tr><tr><td style="padding-top: 6px;"><b>Title:</b></td></tr> -<tr><td><input type="text" class="flatentry" id="appTitle" size="30" readonly="readonly" placeholder="Enter the title of your app" style="width: 300px;"/></td></tr> -<tr><tr><td style="padding-top: 6px;"><b>Author:</b></td></tr> -<tr><td><span id="appAuthor"></span></td></tr> -<tr><tr><td style="padding-top: 6px;"><b>Updated:</b></td></tr> -<tr><td><span id="appUpdated"></span></td></tr> -<tr><tr><td style="padding-top: 6px;"><b>Description:</b></td></tr> -<tr><td><textarea id="appDescription" class="flatentry" cols="40" rows="3" readonly="readonly" placeholder="Enter a short description of your app" style="width: 300px;"></textarea></td></tr> -</table> -</form> - -</div> - -<script type="text/javascript"> -(function() { - -/** - * Get the app name. - */ -var appname = ui.fragmentParams(location)['app']; - -/** - * Set page titles. - */ -document.title = config.windowtitle() + ' - Stats - ' + appname; -$('viewhead').innerHTML = '<span id="appname" class="cmenu">' + appname + '</span>' + -'<input type="button" class="graybutton redbutton plusminus" style="position: absolute; top: 4px; left: 5px;" id="deleteApp" value="-" title="Delete the app" disabled="true"/>' + -'<input type="button" class="graybutton bluebutton" style="position: absolute; top: 4px; right: 5px;" id="cloneApp" value="'+ config.clone() +'" title="' + config.clone() + ' this app"/>'; - -/** - * Set images. - */ -$('appimg').src = ui.b64img(appcache.get('/public/app.b64')); - -/** - * Init service references. - */ -var editorComp = sca.component("Editor"); -var apps = sca.reference(editorComp, "apps"); - -/** - * The current app entry, author and saved XML content. - */ -var savedappentryxml = ''; -var author; -var appentry; - -/** - * Get and display an app. - */ -function getapp(name) { - if (isNil(name)) - return false; - showStatus('Loading'); - - return apps.get(name, function(doc) { - - // Stop now if we didn't get the app - if (doc == null) { - showError('App not available'); - return false; - } - - appentry = car(elementsToValues(atom.readATOMEntry(mklist(doc)))); - $('appTitle').value = cadr(assoc("'title", cdr(appentry))); - author = cadr(assoc("'author", cdr(appentry))); - $('appAuthor').innerHTML = author; - $('appUpdated').innerHTML = cadr(assoc("'updated", cdr(appentry))); - var content = cadr(assoc("'content", cdr(appentry))); - var description = assoc("'description", content); - $('appDescription').value = isNil(description) || isNil(cadr(description))? '' : cadr(description); - savedappentryxml = car(atom.writeATOMEntry(valuesToElements(mklist(appentry)))); - - // Enable author to edit and delete the app - if (username == author) { - $('appTitle').readOnly = false; - $('appDescription').readOnly = false; - $('deleteApp').disabled = false; - $('deleteApp').onclick = function() { - return ui.navigate('/#view=delete&app=' + appname, '_view'); - } - showOnlineStatus(); - } else { - $('appTitle').placeholder = ''; - $('appDescription').placeholder = ''; - showStatus('Read only'); - } - return true; - }); -} - -/** - * Save the current app. - */ -function save(entryxml) { - showStatus('Saving'); - savedappentryxml = entryxml; - apps.put(appname, savedappentryxml, function(e) { - if (e) { - showStatus('Local copy'); - return false; - } - - showStatus('Saved'); - return false; - }); - return true; -} - -/** - * Handle a change event - */ -function onappchange() { - if (username != author) - return false; - var title = $('appTitle').value; - var description = $('appDescription').value; - appentry = mklist("'entry", mklist("'title", title != ''? title : appname), mklist("'id", appname), mklist("'content", mklist("'stats", mklist("'description", description)))); - var entryxml = car(atom.writeATOMEntry(valuesToElements(mklist(appentry)))); - if (savedappentryxml == entryxml) - return false; - showStatus('Modified'); - return save(entryxml); -} - -$('appTitle').onchange = onappchange; -$('appDescription').onchange = onappchange; - -/** - * Handle a form submit event. - */ -$('appForm').onsubmit = function() { - onappchange(); - return false; -}; - -/** - * Handle Clone button event. - */ -$('cloneApp').onclick = function() { - return ui.navigate('/#view=clone&app=' + appname, '_view'); -} - -/** - * Get the current app. - */ -getapp(appname); - -})(); -</script> - -</div> diff --git a/sca-cpp/trunk/hosting/server/htdocs/store/index.html b/sca-cpp/trunk/hosting/server/htdocs/store/index.html index 1264007fe3..15e7aeed0c 100644 --- a/sca-cpp/trunk/hosting/server/htdocs/store/index.html +++ b/sca-cpp/trunk/hosting/server/htdocs/store/index.html @@ -19,24 +19,39 @@ --> <div id="bodydiv" class="body"> -<div id="apps" class="viewcontent"></div> +<div id="viewcontent" class="viewcontent"> + +<div id="apps"></div> +<br/> + +</div> <script type="text/javascript"> -(function() { +(function storebody() { /** - * Set page titles. + * Setup page layout. */ -document.title = config.windowtitle() + ' - Store'; +(function layout() { + document.title = config.windowtitle() + ' - Apps'; + if (!ui.isMobile()) + $('viewcontent').className = 'viewcontent flatscrollbars'; + + $('viewcontent').appendChild(ui.declareCSS( + '.ratings { ' + + 'background: url(\'' + ui.b64png(appcache.get('/public/ratings.b64')) + '\'); ' + + 'margin-top: 6px; width: 50px; height: 14px; display: inline-block; ' + + ' }')); +})(); /** * The store categories */ var categories = [ - //['Featured', 'featured', 1], + ['Featured', 'featured', 1], ['Top', 'top', 2], - ['New', 'new', 3], - ['Search', 'all', 4], + //['New', 'new', 3], + //['Search', 'all', 4], ['My Apps', 'myapps', 5] ]; @@ -45,22 +60,22 @@ var categories = [ */ function findcategory(name) { if (isNil(name)) - return findcategory('top'); + return findcategory('featured'); var f = filter(function(c) { return cadr(c) == name }, categories); if (isNil(f)) - return findcategory('top'); + return findcategory('featured'); return car(f); } /** - * Get the current store category. + * Get the requested store category. */ var catname = cadr(findcategory(ui.fragmentParams(location)['category'])); /** * Build the store menu bar */ -function catmenu() { +$('viewhead').innerHTML = (function catmenu() { function catmenuitem(name, cat, idx) { var c = cat == catname? 'smenu' : 'amenu'; return '<span>' + ui.href('storecat_' + cat, '/#view=store&category=' + cat + '&idx=' + idx, '_view', '<span class="' + c + '">' + name + '</span>') + '</span>'; @@ -68,34 +83,31 @@ function catmenu() { var m = ''; map(function(c) { m += catmenuitem(car(c), cadr(c), caddr(c)); }, categories); - m += '<span class="rmenu"><input type="button" class="graybutton bluebutton" id="createApp" title="Create a new app" Value="Create"/></span>'; + m += '<span class="rmenu"><input type="button" class="bluebutton" id="createApp" title="Create a new app" Value="Create"/></span>'; return m; -} +})(); -/** - * Build the store menu bar. - */ -$('viewhead').innerHTML = catmenu(); /** - * Init service references. + * Initialize service references. */ var editorComp = sca.component("Editor"); var store = sca.reference(editorComp, "store"); var dashboards = sca.reference(editorComp, "dashboards"); +var icons = sca.reference(editorComp, "icons"); /** * Edit an app. */ -function editApp(appname) { +function editapp(appname) { return ui.navigate('/#view=page&app=' + appname, '_view'); } /** * View an app. */ -function viewApp(appname) { - return ui.navigate('/#view=stats&app=' + appname, '_view'); +function viewapp(appname) { + return ui.navigate('/#view=info&app=' + appname, '_view'); } /** @@ -103,66 +115,118 @@ function viewApp(appname) { */ $('createApp').onclick = function() { return ui.navigate('/#view=create', '_view'); +}; + +/** + * Get and display an app icon. + */ +function geticon(appname) { + if (isNil(appname)) + return false; + + return icons.get(appname, function(doc) { + // Stop now if we didn't get an icon + if (doc == null) + return false; + + var iconentry = car(elementsToValues(atom.readATOMEntry(mklist(doc)))); + var content = assoc("'content", iconentry); + var icon = assoc("'icon", content); + var img = assoc("'image", icon); + if (!isNil(img)) { + var appimg = $('store_app_img_' + appname); + if (!isNil(appimg)) + appimg.src = cadr(img); + } + return true; + }); + return true; } /** * Get and display list of apps. */ -function getapps(catname) { - //debug('catname', catname); - showStatus('Loading'); +(function getapps() { + workingstatus(true); + showstatus('Loading'); function display(doc) { // Stop now if we didn't get the apps if (doc == null) { - showError('App not available'); + errorstatus('Couldn\'t get the list of apps'); + workingstatus(false); return false; } - showOnlineStatus(); - var apps = '<div>'; var feed = car(elementsToValues(atom.readATOMFeed(mklist(doc)))); - var aentries = assoc("'entry", cdr(feed)); + var aentries = assoc("'entry", feed); var entries = isNil(aentries)? mklist() : isList(car(cadr(aentries)))? cadr(aentries) : mklist(cdr(aentries)); - var appimg = ui.b64img(appcache.get('/public/app.b64')); + var defappimg = ui.b64png(appcache.get('/public/app.b64')); - function displayentries(entries) { + var apps = '<div>'; + var icons = mklist(); + + (function displayentries(entries) { if (isNil(entries)) return apps; var entry = car(entries); var title = cadr(assoc("'title", entry)) var name = cadr(assoc("'id", entry)); var author = cadr(assoc("'author", entry)); - var updated = cadr(assoc("'updated", entry)); + var updated = xmldatetime(cadr(assoc("'updated", entry))).toLocaleDateString(); + + var aratings = assoc("'info", assoc("'content", entry)); + var ar = assoc("'rating", aratings); + var ar1 = assoc("'rating1", aratings); + var ar2 = assoc("'rating2", aratings); + var ar3 = assoc("'rating3", aratings); + var ar4 = assoc("'rating4", aratings); + var rating = isNil(ar)? 0 : Number(cadr(ar)); + var reviews = (isNil(ar1)? 0 : Number(cadr(ar1))) + (isNil(ar2)? 0 : Number(cadr(ar2))) + (isNil(ar3)? 0 : Number(cadr(ar3))) + (isNil(ar4)? 0 : Number(cadr(ar4))); apps += '<div class="box">' - apps += '<span class="appicon">' + ui.href('appicon_' + name, '/#view=stats&app=' + name, '_view', '<img src="' + appimg + '" width="50" height="50"></img>') + '</span>'; - apps += '<span>' - apps += '<span class="apptitle">' + ui.href('apptitle_' + name, '/#view=stats&app=' + name, '_view', name) + '</span>'; + apps += '<div class="appicon">' + apps += ui.href('appicon_' + name, '/#view=info&app=' + name, '_view', '<img id="store_app_img_' + name + '" src="' + defappimg + '" width="50" height="50"></img>'); + //apps += '<br/><input type="button" class="lightbutton" value="Run" onclick="ui.navigate(\'/' + name + '/\', \'_blank\');"/>'; + apps += '</div>' + apps += '<div class="appdetails">'; + apps += '<span class="apptitle">' + ui.href('store_app_title_' + name, '/#view=info&app=' + name, '_view', name) + '</span>'; if (catname != 'myapps') apps += '<br/><span>' + 'by ' + author.split('@')[0] + '</span>'; - apps += '</span>'; + var ratingy = -20 * (4 - Math.floor(rating)); + apps += '<br/><span class="ratings" style="background-position: 0px ' + ratingy + 'px;"> </span>'; + apps += '<br/><span style="font-size: 10px;">' + reviews + (reviews > 1? ' ratings' : ' rating') + '</span>'; + /*apps += '<br/><span>' + updated + '</span>';*/ + apps += '</div>'; apps += '</div>'; - return displayentries(cdr(entries)); - } - displayentries(entries); + icons = cons(name, icons); + + return displayentries(cdr(entries)); + })(entries); apps += '</div>'; $('apps').innerHTML = apps; + + ui.unmemo$('store_app_'); + + (function displayicons(icons) { + if (isNil(icons)) + return true; + geticon(car(icons)); + return displayicons(cdr(icons)); + })(reverse(icons)); + + onlinestatus(); + workingstatus(false); } if (catname == 'myapps') return dashboards.get('', display); return store.get(catname, display); -} - -/** - * Get and display the list of apps. - */ -getapps(catname); +})(); })(); </script> |