summaryrefslogtreecommitdiffstats
path: root/sca-cpp/trunk/hosting/server/htdocs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--sca-cpp/trunk/hosting/server/htdocs/account/index.html335
-rw-r--r--sca-cpp/trunk/hosting/server/htdocs/app/cache/cache-template.cmf (renamed from sca-cpp/trunk/hosting/server/htdocs/app/cache-template.cmf)2
-rw-r--r--sca-cpp/trunk/hosting/server/htdocs/app/index.html102
-rw-r--r--sca-cpp/trunk/hosting/server/htdocs/cache/cache-template.cmf (renamed from sca-cpp/trunk/hosting/server/htdocs/cache-template.cmf)2
-rw-r--r--sca-cpp/trunk/hosting/server/htdocs/cache/index.html51
-rw-r--r--sca-cpp/trunk/hosting/server/htdocs/clone/index.html135
-rw-r--r--sca-cpp/trunk/hosting/server/htdocs/config.js2
-rw-r--r--sca-cpp/trunk/hosting/server/htdocs/create/index.html97
-rw-r--r--sca-cpp/trunk/hosting/server/htdocs/delete/index.html91
-rw-r--r--sca-cpp/trunk/hosting/server/htdocs/favicon-16.xcfbin0 -> 1134 bytes
-rw-r--r--sca-cpp/trunk/hosting/server/htdocs/favicon-32.xcfbin0 -> 1456 bytes
-rw-r--r--sca-cpp/trunk/hosting/server/htdocs/favicon.icobin2238 -> 153 bytes
-rw-r--r--sca-cpp/trunk/hosting/server/htdocs/graph/index.html195
-rw-r--r--sca-cpp/trunk/hosting/server/htdocs/home/home.b641
-rw-r--r--sca-cpp/trunk/hosting/server/htdocs/home/home.pngbin9595 -> 0 bytes
-rw-r--r--sca-cpp/trunk/hosting/server/htdocs/home/index.html47
-rw-r--r--sca-cpp/trunk/hosting/server/htdocs/index.html503
-rw-r--r--sca-cpp/trunk/hosting/server/htdocs/info/index.html494
-rw-r--r--sca-cpp/trunk/hosting/server/htdocs/login/index.html409
-rw-r--r--sca-cpp/trunk/hosting/server/htdocs/page/index.html1581
-rw-r--r--sca-cpp/trunk/hosting/server/htdocs/proxy/public/cache/cache-template.cmf11
-rw-r--r--sca-cpp/trunk/hosting/server/htdocs/proxy/public/cache/index.html51
-rw-r--r--sca-cpp/trunk/hosting/server/htdocs/proxy/public/oops/index.html327
-rw-r--r--sca-cpp/trunk/hosting/server/htdocs/public/app.b642
-rw-r--r--sca-cpp/trunk/hosting/server/htdocs/public/app.pngbin147 -> 222 bytes
-rw-r--r--sca-cpp/trunk/hosting/server/htdocs/public/app.xcfbin1294 -> 1906 bytes
-rw-r--r--sca-cpp/trunk/hosting/server/htdocs/public/cache/cache-template.cmf17
-rw-r--r--sca-cpp/trunk/hosting/server/htdocs/public/cache/index.html51
-rw-r--r--sca-cpp/trunk/hosting/server/htdocs/public/config.js4
-rw-r--r--sca-cpp/trunk/hosting/server/htdocs/public/delete.b641
-rw-r--r--sca-cpp/trunk/hosting/server/htdocs/public/delete.pngbin906 -> 0 bytes
-rw-r--r--sca-cpp/trunk/hosting/server/htdocs/public/delete.xcfbin2008 -> 0 bytes
-rw-r--r--sca-cpp/trunk/hosting/server/htdocs/public/grid72.b641
-rw-r--r--sca-cpp/trunk/hosting/server/htdocs/public/grid72.pngbin138 -> 0 bytes
-rw-r--r--sca-cpp/trunk/hosting/server/htdocs/public/iframe.html28
-rw-r--r--sca-cpp/trunk/hosting/server/htdocs/public/img.b642
-rw-r--r--sca-cpp/trunk/hosting/server/htdocs/public/img.pngbin357 -> 191 bytes
-rw-r--r--sca-cpp/trunk/hosting/server/htdocs/public/img.xcfbin1639 -> 1456 bytes
-rw-r--r--sca-cpp/trunk/hosting/server/htdocs/public/notauth/index.html328
-rw-r--r--sca-cpp/trunk/hosting/server/htdocs/public/notfound/index.html328
-rw-r--r--sca-cpp/trunk/hosting/server/htdocs/public/notyet/index.html328
-rw-r--r--sca-cpp/trunk/hosting/server/htdocs/public/oops/index.html326
-rw-r--r--sca-cpp/trunk/hosting/server/htdocs/public/rate.pngbin0 -> 1690 bytes
-rw-r--r--sca-cpp/trunk/hosting/server/htdocs/public/rate.xcfbin0 -> 3754 bytes
-rw-r--r--sca-cpp/trunk/hosting/server/htdocs/public/ratings.pngbin0 -> 726 bytes
-rw-r--r--sca-cpp/trunk/hosting/server/htdocs/public/ratings.xcfbin0 -> 6344 bytes
-rw-r--r--sca-cpp/trunk/hosting/server/htdocs/public/search.pngbin0 -> 351 bytes
-rw-r--r--sca-cpp/trunk/hosting/server/htdocs/public/search.xcfbin0 -> 1263 bytes
-rw-r--r--sca-cpp/trunk/hosting/server/htdocs/public/touchicon-50.xcfbin0 -> 1742 bytes
-rw-r--r--sca-cpp/trunk/hosting/server/htdocs/public/touchicon-53.xcfbin0 -> 1748 bytes
-rw-r--r--sca-cpp/trunk/hosting/server/htdocs/public/touchicon-57.xcfbin0 -> 1988 bytes
-rw-r--r--sca-cpp/trunk/hosting/server/htdocs/public/touchicon.b641
-rw-r--r--sca-cpp/trunk/hosting/server/htdocs/public/touchicon.pngbin606 -> 243 bytes
-rw-r--r--sca-cpp/trunk/hosting/server/htdocs/public/touchicon.xcfbin3400 -> 0 bytes
-rw-r--r--sca-cpp/trunk/hosting/server/htdocs/public/user.b642
-rw-r--r--sca-cpp/trunk/hosting/server/htdocs/public/user.pngbin147 -> 891 bytes
-rw-r--r--sca-cpp/trunk/hosting/server/htdocs/public/user.xcfbin0 -> 2706 bytes
-rw-r--r--sca-cpp/trunk/hosting/server/htdocs/rate/index.html190
-rw-r--r--sca-cpp/trunk/hosting/server/htdocs/search/index.html196
-rw-r--r--sca-cpp/trunk/hosting/server/htdocs/stats/index.html179
-rw-r--r--sca-cpp/trunk/hosting/server/htdocs/store/index.html152
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
new file mode 100644
index 0000000000..e43dcba033
--- /dev/null
+++ b/sca-cpp/trunk/hosting/server/htdocs/favicon-16.xcf
Binary files differ
diff --git a/sca-cpp/trunk/hosting/server/htdocs/favicon-32.xcf b/sca-cpp/trunk/hosting/server/htdocs/favicon-32.xcf
new file mode 100644
index 0000000000..c1736338ec
--- /dev/null
+++ b/sca-cpp/trunk/hosting/server/htdocs/favicon-32.xcf
Binary files differ
diff --git a/sca-cpp/trunk/hosting/server/htdocs/favicon.ico b/sca-cpp/trunk/hosting/server/htdocs/favicon.ico
index a7b502b9e1..bd60462963 100644
--- a/sca-cpp/trunk/hosting/server/htdocs/favicon.ico
+++ b/sca-cpp/trunk/hosting/server/htdocs/favicon.ico
Binary files differ
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="&gt;"/>' +
-'<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
deleted file mode 100644
index 8f5a0b0d86..0000000000
--- a/sca-cpp/trunk/hosting/server/htdocs/home/home.png
+++ /dev/null
Binary files differ
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">&nbsp;</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="&gt;"/>' +
+ '<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="&gt;"/>' +
-'<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
index 1f73274b76..7293fe7ee5 100644
--- a/sca-cpp/trunk/hosting/server/htdocs/public/app.png
+++ b/sca-cpp/trunk/hosting/server/htdocs/public/app.png
Binary files differ
diff --git a/sca-cpp/trunk/hosting/server/htdocs/public/app.xcf b/sca-cpp/trunk/hosting/server/htdocs/public/app.xcf
index 741b7ff43f..b144d46743 100644
--- a/sca-cpp/trunk/hosting/server/htdocs/public/app.xcf
+++ b/sca-cpp/trunk/hosting/server/htdocs/public/app.xcf
Binary files differ
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
deleted file mode 100644
index fb56bae030..0000000000
--- a/sca-cpp/trunk/hosting/server/htdocs/public/delete.png
+++ /dev/null
Binary files differ
diff --git a/sca-cpp/trunk/hosting/server/htdocs/public/delete.xcf b/sca-cpp/trunk/hosting/server/htdocs/public/delete.xcf
deleted file mode 100644
index 7691f50cc5..0000000000
--- a/sca-cpp/trunk/hosting/server/htdocs/public/delete.xcf
+++ /dev/null
Binary files differ
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
deleted file mode 100644
index cf6008171a..0000000000
--- a/sca-cpp/trunk/hosting/server/htdocs/public/grid72.png
+++ /dev/null
Binary files differ
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
index 2363b25e8e..e05e74fa2d 100644
--- a/sca-cpp/trunk/hosting/server/htdocs/public/img.png
+++ b/sca-cpp/trunk/hosting/server/htdocs/public/img.png
Binary files differ
diff --git a/sca-cpp/trunk/hosting/server/htdocs/public/img.xcf b/sca-cpp/trunk/hosting/server/htdocs/public/img.xcf
index ffcc124584..c1736338ec 100644
--- a/sca-cpp/trunk/hosting/server/htdocs/public/img.xcf
+++ b/sca-cpp/trunk/hosting/server/htdocs/public/img.xcf
Binary files differ
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
new file mode 100644
index 0000000000..27c744c5a6
--- /dev/null
+++ b/sca-cpp/trunk/hosting/server/htdocs/public/rate.png
Binary files differ
diff --git a/sca-cpp/trunk/hosting/server/htdocs/public/rate.xcf b/sca-cpp/trunk/hosting/server/htdocs/public/rate.xcf
new file mode 100644
index 0000000000..eb807f6005
--- /dev/null
+++ b/sca-cpp/trunk/hosting/server/htdocs/public/rate.xcf
Binary files differ
diff --git a/sca-cpp/trunk/hosting/server/htdocs/public/ratings.png b/sca-cpp/trunk/hosting/server/htdocs/public/ratings.png
new file mode 100644
index 0000000000..9c10be52dd
--- /dev/null
+++ b/sca-cpp/trunk/hosting/server/htdocs/public/ratings.png
Binary files differ
diff --git a/sca-cpp/trunk/hosting/server/htdocs/public/ratings.xcf b/sca-cpp/trunk/hosting/server/htdocs/public/ratings.xcf
new file mode 100644
index 0000000000..cad8d31b2e
--- /dev/null
+++ b/sca-cpp/trunk/hosting/server/htdocs/public/ratings.xcf
Binary files differ
diff --git a/sca-cpp/trunk/hosting/server/htdocs/public/search.png b/sca-cpp/trunk/hosting/server/htdocs/public/search.png
new file mode 100644
index 0000000000..d5178fea3c
--- /dev/null
+++ b/sca-cpp/trunk/hosting/server/htdocs/public/search.png
Binary files differ
diff --git a/sca-cpp/trunk/hosting/server/htdocs/public/search.xcf b/sca-cpp/trunk/hosting/server/htdocs/public/search.xcf
new file mode 100644
index 0000000000..30d03df40a
--- /dev/null
+++ b/sca-cpp/trunk/hosting/server/htdocs/public/search.xcf
Binary files differ
diff --git a/sca-cpp/trunk/hosting/server/htdocs/public/touchicon-50.xcf b/sca-cpp/trunk/hosting/server/htdocs/public/touchicon-50.xcf
new file mode 100644
index 0000000000..8dcc8e4f1b
--- /dev/null
+++ b/sca-cpp/trunk/hosting/server/htdocs/public/touchicon-50.xcf
Binary files differ
diff --git a/sca-cpp/trunk/hosting/server/htdocs/public/touchicon-53.xcf b/sca-cpp/trunk/hosting/server/htdocs/public/touchicon-53.xcf
new file mode 100644
index 0000000000..b2dcd6f12c
--- /dev/null
+++ b/sca-cpp/trunk/hosting/server/htdocs/public/touchicon-53.xcf
Binary files differ
diff --git a/sca-cpp/trunk/hosting/server/htdocs/public/touchicon-57.xcf b/sca-cpp/trunk/hosting/server/htdocs/public/touchicon-57.xcf
new file mode 100644
index 0000000000..5ab284973d
--- /dev/null
+++ b/sca-cpp/trunk/hosting/server/htdocs/public/touchicon-57.xcf
Binary files differ
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
index f22c33d2a0..1975eb16bf 100644
--- a/sca-cpp/trunk/hosting/server/htdocs/public/touchicon.png
+++ b/sca-cpp/trunk/hosting/server/htdocs/public/touchicon.png
Binary files differ
diff --git a/sca-cpp/trunk/hosting/server/htdocs/public/touchicon.xcf b/sca-cpp/trunk/hosting/server/htdocs/public/touchicon.xcf
deleted file mode 100644
index fc713b478b..0000000000
--- a/sca-cpp/trunk/hosting/server/htdocs/public/touchicon.xcf
+++ /dev/null
Binary files differ
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
index 1f73274b76..e99b30815d 100644
--- a/sca-cpp/trunk/hosting/server/htdocs/public/user.png
+++ b/sca-cpp/trunk/hosting/server/htdocs/public/user.png
Binary files differ
diff --git a/sca-cpp/trunk/hosting/server/htdocs/public/user.xcf b/sca-cpp/trunk/hosting/server/htdocs/public/user.xcf
new file mode 100644
index 0000000000..2f304c45a7
--- /dev/null
+++ b/sca-cpp/trunk/hosting/server/htdocs/public/user.xcf
Binary files differ
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">&nbsp;</span><span style="display: inline-block; width: 20px;"></span>
+<span id="rateApp2" class="graystar">&nbsp;</span><span style="display: inline-block; width: 20px;"></span>
+<span id="rateApp3" class="graystar">&nbsp;</span><span style="display: inline-block; width: 20px;"></span>
+<span id="rateApp4" class="graystar">&nbsp;</span>
+</td></tr>
+<tr><td class="lightlabel" id="ratedescription">&nbsp;</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&nbsp;' + author.split('@')[0] + '</span>';
+ var ratingy = -20 * (4 - Math.floor(rating));
+ apps += '<br/><span class="ratings" style="background-position: 0px ' + ratingy + 'px;">&nbsp;</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&nbsp;' + author.split('@')[0] + '</span>';
- apps += '</span>';
+ var ratingy = -20 * (4 - Math.floor(rating));
+ apps += '<br/><span class="ratings" style="background-position: 0px ' + ratingy + 'px;">&nbsp;</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>