summaryrefslogtreecommitdiffstats
path: root/sca-cpp/trunk/modules
diff options
context:
space:
mode:
Diffstat (limited to 'sca-cpp/trunk/modules')
-rw-r--r--sca-cpp/trunk/modules/atom/atom-test.cpp36
-rw-r--r--sca-cpp/trunk/modules/atom/atom.hpp56
-rw-r--r--sca-cpp/trunk/modules/http/conf/mime.types4
-rwxr-xr-xsca-cpp/trunk/modules/http/form-auth-conf2
-rwxr-xr-xsca-cpp/trunk/modules/http/httpd-conf36
-rwxr-xr-xsca-cpp/trunk/modules/http/httpd-ssl-conf27
-rwxr-xr-xsca-cpp/trunk/modules/http/proxy-base-conf5
-rwxr-xr-xsca-cpp/trunk/modules/http/proxy-conf6
-rwxr-xr-xsca-cpp/trunk/modules/http/proxy-ssl-conf6
-rw-r--r--sca-cpp/trunk/modules/js/htdocs/atomutil.js32
-rw-r--r--sca-cpp/trunk/modules/js/htdocs/component.js18
-rw-r--r--sca-cpp/trunk/modules/js/htdocs/ui.css520
-rw-r--r--sca-cpp/trunk/modules/js/htdocs/ui.js169
-rw-r--r--sca-cpp/trunk/modules/js/htdocs/util.js55
14 files changed, 611 insertions, 361 deletions
diff --git a/sca-cpp/trunk/modules/atom/atom-test.cpp b/sca-cpp/trunk/modules/atom/atom-test.cpp
index 3030777b87..e00c75a62f 100644
--- a/sca-cpp/trunk/modules/atom/atom-test.cpp
+++ b/sca-cpp/trunk/modules/atom/atom-test.cpp
@@ -41,6 +41,10 @@ const string itemEntry(
"<entry xmlns=\"http://www.w3.org/2005/Atom\">\n"
" <title type=\"text\">item</title>\n"
" <id>cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b</id>\n"
+ " <author>\n"
+ " <email>jane@example.com</email>\n"
+ " </author>\n"
+ " <updated>Fri Jan 01 08:11:36 PDT 2012</updated>\n"
" <content type=\"application/xml\">\n"
" <item>\n"
" <name>Apple</name>\n"
@@ -54,6 +58,10 @@ const string itemTextEntry("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<entry xmlns=\"http://www.w3.org/2005/Atom\">\n"
" <title type=\"text\">item</title>\n"
" <id>cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b</id>\n"
+ " <author>\n"
+ " <email>jane@example.com</email>\n"
+ " </author>\n"
+ " <updated>Fri Jan 01 08:11:36 PDT 2012</updated>\n"
" <content type=\"text\">Apple</content>\n"
" <link href=\"cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b\"/>\n"
"</entry>\n");
@@ -62,6 +70,10 @@ const string itemNoContentEntry("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<entry xmlns=\"http://www.w3.org/2005/Atom\">\n"
" <title type=\"text\">item</title>\n"
" <id>cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b</id>\n"
+ " <author>\n"
+ " <name>jane</name>\n"
+ " </author>\n"
+ " <updated>Fri Jan 01 08:11:36 PDT 2012</updated>\n"
" <link href=\"cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b\"/>\n"
"</entry>\n");
@@ -96,6 +108,8 @@ bool testEntry() {
const list<value> a = list<value>() + (list<value>() + element + value("entry")
+ value(list<value>() + element + value("title") + value(string("item")))
+ value(list<value>() + element + value("id") + value(string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b")))
+ + value(list<value>() + element + value("author") + value(string("jane@example.com")))
+ + value(list<value>() + element + value("updated") + value(string("Fri Jan 01 08:11:36 PDT 2012")))
+ value(list<value>() + element + value("content") + value(i)));
ostringstream os;
writeATOMEntry<ostream*>(writer, &os, a);
@@ -105,6 +119,8 @@ bool testEntry() {
const list<value> a = list<value>() + (list<value>() + element + value("entry")
+ value(list<value>() + element + value("title") + value(string("item")))
+ value(list<value>() + element + value("id") + value(string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b")))
+ + value(list<value>() + element + value("author") + value(string("jane@example.com")))
+ + value(list<value>() + element + value("updated") + value(string("Fri Jan 01 08:11:36 PDT 2012")))
+ value(list<value>() + element + value("content") + value(string("Apple"))));
ostringstream os;
writeATOMEntry<ostream*>(writer, &os, a);
@@ -113,7 +129,9 @@ bool testEntry() {
{
const list<value> a = list<value>() + (list<value>() + element + value("entry")
+ value(list<value>() + element + value("title") + value(string("item")))
- + value(list<value>() + element + value("id") + value(string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b"))));
+ + value(list<value>() + element + value("id") + value(string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b")))
+ + value(list<value>() + element + value("author") + value(string("jane")))
+ + value(list<value>() + element + value("updated") + value(string("Fri Jan 01 08:11:36 PDT 2012"))));
ostringstream os;
writeATOMEntry<ostream*>(writer, &os, a);
assert(str(os) == itemNoContentEntry);
@@ -158,6 +176,10 @@ const string itemFeed("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
" <entry xmlns=\"http://www.w3.org/2005/Atom\">\n"
" <title type=\"text\">item</title>\n"
" <id>cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b</id>\n"
+ " <author>\n"
+ " <email>jane@example.com</email>\n"
+ " </author>\n"
+ " <updated>Fri Jan 01 08:11:36 PDT 2012</updated>\n"
" <content type=\"application/xml\">\n"
" <item>\n"
" <name>Apple</name>\n"
@@ -169,6 +191,10 @@ const string itemFeed("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
" <entry xmlns=\"http://www.w3.org/2005/Atom\">\n"
" <title type=\"text\">item</title>\n"
" <id>cart-53d67a61-aa5e-4e5e-8401-39edeba8b83c</id>\n"
+ " <author>\n"
+ " <email>jane@example.com</email>\n"
+ " </author>\n"
+ " <updated>Fri Jan 01 08:11:36 PDT 2012</updated>\n"
" <content type=\"application/xml\">\n"
" <item>\n"
" <name>Orange</name>\n"
@@ -183,7 +209,9 @@ bool testFeed() {
{
const list<value> a = list<value>() + (list<value>() + element + value("feed")
+ value(list<value>() + element + value("title") + value(string("Feed")))
- + value(list<value>() + element + value("id") + value(string("1234"))));
+ + value(list<value>() + element + value("id") + value(string("1234")))
+ + value(list<value>() + element + value("author") + value(string("jane@example.com")))
+ + value(list<value>() + element + value("updated") + value(string("Fri Jan 01 08:11:36 PDT 2012"))));
ostringstream os;
writeATOMFeed<ostream*>(writer, &os, a);
assert(str(os) == emptyFeed);
@@ -207,10 +235,14 @@ bool testFeed() {
+ value(list<value>() + element + value("entry")
+ value(list<value>() + element + value("title") + value(string("item")))
+ value(list<value>() + element + value("id") + value(string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83b")))
+ + value(list<value>() + element + value("author") + value(string("jane@example.com")))
+ + value(list<value>() + element + value("updated") + value(string("Fri Jan 01 08:11:36 PDT 2012")))
+ value(list<value>() + element + value("content") + value(i1)))
+ value(list<value>() + element + value("entry")
+ value(list<value>() + element + value("title") + value(string("item")))
+ value(list<value>() + element + value("id") + value(string("cart-53d67a61-aa5e-4e5e-8401-39edeba8b83c")))
+ + value(list<value>() + element + value("author") + value(string("jane@example.com")))
+ + value(list<value>() + element + value("updated") + value(string("Fri Jan 01 08:11:36 PDT 2012")))
+ value(list<value>() + element + value("content") + value(i2)));
const list<value> a = list<value>() + (append<value>(list<value>() + element + value("feed")
diff --git a/sca-cpp/trunk/modules/atom/atom.hpp b/sca-cpp/trunk/modules/atom/atom.hpp
index 1d4a12a867..5de3894214 100644
--- a/sca-cpp/trunk/modules/atom/atom.hpp
+++ b/sca-cpp/trunk/modules/atom/atom.hpp
@@ -46,14 +46,24 @@ const value entry("entry");
*/
const list<value> entryElementValues(const list<value>& e) {
const list<value> lt = filter<value>(selector(mklist<value>(element, "title")), e);
- const value t = isNil(lt)? value(emptyString) : elementValue(car(lt));
+ const list<value> t = list<value>() + element + value("title") + (isNil(lt)? value(emptyString) : elementValue(car(lt)));
+
const list<value> li = filter<value>(selector(mklist<value>(element, "id")), e);
- const value i = isNil(li)? value(emptyString) : elementValue(car(li));
+ const list<value> i = list<value>() + element + value("id") + (isNil(li)? value(emptyString) : elementValue(car(li)));
+
+ const list<value> la = filter<value>(selector(mklist<value>(element, "author")), e);
+ const list<value> lan = isNil(la)? list<value>() : filter<value>(selector(mklist<value>(element, "name")), car(la));
+ const list<value> lae = isNil(la)? list<value>() : filter<value>(selector(mklist<value>(element, "email")), car(la));
+ const list<value> laa = isNil(lan)? lae : lan;
+ const list<value> a = isNil(laa)? list<value>() : mklist<value>(list<value>() + element + value("author") + elementValue(car(laa)));
+
+ const list<value> lu = filter<value>(selector(mklist<value>(element, "updated")), e);
+ const list<value> u = isNil(lu)? list<value>() : mklist<value>(list<value>() + element + value("updated") + elementValue(car(lu)));
+
const list<value> lc = filter<value>(selector(mklist<value>(element, "content")), e);
- return append<value>(list<value>() + element + entry
- + value(list<value>() + element + value("title") + t)
- + value(list<value>() + element + value("id") + i),
- isNil(lc)? list<value>() : mklist<value>(value(list<value>() + element + value("content") + elementValue(car(lc)))));
+ const list<value> c = isNil(lc)? list<value>() : mklist<value>(list<value>() + element + value("content") + elementValue(car(lc)));
+
+ return append<value>(append<value>(append<value>(list<value>() + element + entry + value(t) + value(i), a), u), c);
}
/**
@@ -110,22 +120,44 @@ const failable<list<value> > readATOMFeed(const list<string>& ilist) {
}
/**
+ * Returns children of an ATOM content element.
+ */
+struct filterContentElementChildren {
+ const value type;
+ filterContentElementChildren() : type("type") {
+ }
+ const bool operator()(const value& v) const {
+ return !(isAttribute(v) && attributeName((list<value>)v) == type);
+ }
+};
+
+const list<value> contentElementChildren(const value& content) {
+ return filter<value>(filterContentElementChildren(), elementChildren(content));
+}
+
+/**
* Convert a list of element values representing an ATOM entry to a list of elements.
*/
const list<value> entryElement(const list<value>& l) {
- const value title = elementValue(elementChild("title", l));
- const value id = elementValue(elementChild("id", l));
+ const value title = elementChild("title", l);
+ const value id = elementChild("id", l);
+ const value author = elementChild("author", l);
+ const bool email = isNil(author)? false : contains(elementValue(author), "@");
+ const value updated = elementChild("updated", l);
const value content = elementChild("content", l);
const bool text = isNil(content)? false : elementHasValue(content);
return list<value>()
+ element + entry + (list<value>() + attribute + "xmlns" + "http://www.w3.org/2005/Atom")
- + (list<value>() + element + "title" + (list<value>() + attribute + "type" + "text") + title)
- + (list<value>() + element + "id" + id)
+ + (list<value>() + element + "title" + (list<value>() + attribute + "type" + "text") + elementValue(title))
+ + (list<value>() + element + "id" + elementValue(id))
+ + (isNil(author)? list<value>() : (list<value>() + element + "author" +
+ (email? (list<value>() + element + "email" + elementValue(author)) : (list<value>() + element + "name" + elementValue(author)))))
+ + (isNil(updated)? list<value>() : (list<value>() + element + "updated" + elementValue(updated)))
+ (isNil(content)?
list<value>() :
append<value>(list<value>() + element + "content" + (list<value>() + attribute + "type" + (text? "text" : "application/xml")),
- text? mklist<value>(elementValue(content)) : elementChildren(content)))
- + (list<value>() + element + "link" + (list<value>() + attribute + "href" + id));
+ text? mklist<value>(elementValue(content)) : contentElementChildren(content)))
+ + (list<value>() + element + "link" + (list<value>() + attribute + "href" + elementValue(id)));
}
/**
diff --git a/sca-cpp/trunk/modules/http/conf/mime.types b/sca-cpp/trunk/modules/http/conf/mime.types
index 430aa95f0f..3f083f9a32 100644
--- a/sca-cpp/trunk/modules/http/conf/mime.types
+++ b/sca-cpp/trunk/modules/http/conf/mime.types
@@ -471,7 +471,7 @@ image/gif gif
image/ief ief
image/jpeg jpeg jpg jpe
image/naplps
-image/png png
+image/png png b64
image/prs.btif
image/prs.pti
image/svg+xml svg
@@ -546,7 +546,7 @@ text/directory
text/enriched
text/html html htm
text/parityfec
-text/plain asc txt b64
+text/plain asc txt
text/prs.lines.tag
text/rfc822-headers
text/richtext rtx
diff --git a/sca-cpp/trunk/modules/http/form-auth-conf b/sca-cpp/trunk/modules/http/form-auth-conf
index 2898d9b7ed..08b97b9df8 100755
--- a/sca-cpp/trunk/modules/http/form-auth-conf
+++ b/sca-cpp/trunk/modules/http/form-auth-conf
@@ -57,7 +57,7 @@ AuthFormProvider file
AuthFormLoginRequiredLocation /login
AuthFormLogoutLocation /
Session On
-SessionCookieName TuscanyFormAuth path=/;secure=TRUE
+SessionCookieName TuscanyFormAuth domain=.$host; path=/
SessionCryptoPassphrase $pw
Require valid-user
</Location>
diff --git a/sca-cpp/trunk/modules/http/httpd-conf b/sca-cpp/trunk/modules/http/httpd-conf
index 74b3944cc1..5b034c7928 100755
--- a/sca-cpp/trunk/modules/http/httpd-conf
+++ b/sca-cpp/trunk/modules/http/httpd-conf
@@ -35,8 +35,6 @@ else
pportsuffix=":$pport"
fi
-dothost=`echo $host | grep "\."`
-
mkdir -p $4
htdocs=`echo "import os; print os.path.realpath('$4')" | python`
@@ -83,12 +81,9 @@ HostNameLookups Off
# [timestamp] [access] remote-host remote-ident remote-user "request-line"
# status response-size "referrer" "user-agent" "user-track" local-IP
# virtual-host response-time bytes-received bytes-sent
-LogFormat "[%{%a %b %d %H:%M:%S %Y}t] [access] %h %l %u \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\" \"%{cookie}n\" %A %V %D %I %O" combined
+LogFormat "[%{%a %b %d %H:%M:%S %Y}t] [access] %h %l %u \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\" \"%{cookie}n\" %A %V %D %I %O %{mod_security-message}i" combined
Include conf/log.conf
-# Configure tracking
-Include conf/tracking.conf
-
# Configure Mime types and default charsets
TypesConfig $here/conf/mime.types
AddDefaultCharset utf-8
@@ -116,7 +111,8 @@ Require all denied
# Configure output filters to enable compression and rate limiting
<Location />
-SetOutputFilter RATE_LIMIT;DEFLATE
+#SetOutputFilter RATE_LIMIT;DEFLATE
+SetOutputFilter DEFLATE
BrowserMatch ^Mozilla/4 gzip-only-text/html
BrowserMatch ^Mozilla/4\.0[678] no-gzip
@@ -125,7 +121,7 @@ BrowserMatch ^check_http/ check_http
SetEnvIfNoCase Request_URI \.(?:gif|jpe?g|png)$ no-gzip dont-vary
Header append Vary User-Agent env=!dont-vary
-SetEnv rate-limit 400
+#SetEnv rate-limit 400
</Location>
# Listen on HTTP port
@@ -165,26 +161,6 @@ Include conf/adminauth.conf
EOF
-# Generate tracking configuration
-cat >$root/conf/tracking.conf <<EOF
-# Generated by: httpd-conf $*
-# Configure tracking
-CookieTracking on
-CookieName TuscanyVisitorId
-CookieStyle Cookie
-CookieExpires 31556926
-
-EOF
-
-if [ "$dothost" != "" ]; then
- cat >>$root/conf/tracking.conf <<EOF
-# Generated by: httpd-conf $*
-CookieDomain .$dothost
-
-EOF
-
-fi
-
# Configure logging
cat >$root/conf/log.conf <<EOF
# Generated by: httpd-conf $*
@@ -303,6 +279,10 @@ Require all granted
AuthType None
Require all granted
</Location>
+<Location /proxy/public>
+AuthType None
+Require all granted
+</Location>
<Location /favicon.ico>
AuthType None
Require all granted
diff --git a/sca-cpp/trunk/modules/http/httpd-ssl-conf b/sca-cpp/trunk/modules/http/httpd-ssl-conf
index 420d08ff87..b5f82d9690 100755
--- a/sca-cpp/trunk/modules/http/httpd-ssl-conf
+++ b/sca-cpp/trunk/modules/http/httpd-ssl-conf
@@ -37,6 +37,8 @@ else
sslpportsuffix=":$sslpport"
fi
+dothost=`echo $host | grep "\."`
+
htdocs=`echo $conf | awk '{ print $8 }'`
mkdir -p $htdocs
htdocs=`echo "import os; print os.path.realpath('$htdocs')" | python`
@@ -80,6 +82,9 @@ Include conf/locauth-ssl.conf
Include conf/pubauth-ssl.conf
Include conf/adminauth-ssl.conf
+# Configure tracking
+Include conf/tracking-ssl.conf
+
</VirtualHost>
EOF
@@ -163,7 +168,7 @@ SSLRequire %{SSL_CIPHER_USEKEYSIZE} >= 128
# SSL-cipher "request-line" status response-size "referrer" "user-agent"
# "SSL-client-I-DN" "SSL-client-S-DN" "user-track" local-IP virtual-host
# response-time bytes-received bytes-sent
-LogFormat "[%{%a %b %d %H:%M:%S %Y}t] [sslaccess] %h %l %u %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\" \"%{SSL_CLIENT_I_DN}x\" \"%{SSL_CLIENT_S_DN}x\" \"%{cookie}n\" %A %V %D %I %O" sslcombined
+LogFormat "[%{%a %b %d %H:%M:%S %Y}t] [sslaccess] %h %l %u %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\" \"%{SSL_CLIENT_I_DN}x\" \"%{SSL_CLIENT_S_DN}x\" \"%{cookie}n\" %A %V %D %I %O %{mod_security-message}i" sslcombined
Include conf/log-ssl.conf
# Enable HTTPS reverse proxy
@@ -180,6 +185,26 @@ SSLProxyCheckPeerCN Off
EOF
+# Generate tracking configuration
+cat >$root/conf/tracking-ssl.conf <<EOF
+# Generated by: httpd-ssl-conf $*
+# Configure tracking
+CookieTracking on
+CookieName TuscanyVisitorId
+CookieStyle Cookie
+CookieExpires 31556926
+
+EOF
+
+if [ "$dothost" != "" ]; then
+ cat >>$root/conf/tracking-ssl.conf <<EOF
+# Generated by: httpd-ssl-conf $*
+CookieDomain .$dothost
+
+EOF
+
+fi
+
# Configure logging
cat >$root/conf/log-ssl.conf <<EOF
# Generated by: httpd-ssl-conf $*
diff --git a/sca-cpp/trunk/modules/http/proxy-base-conf b/sca-cpp/trunk/modules/http/proxy-base-conf
index c61c0e20d8..cbd62bcc14 100755
--- a/sca-cpp/trunk/modules/http/proxy-base-conf
+++ b/sca-cpp/trunk/modules/http/proxy-base-conf
@@ -24,10 +24,11 @@ root=`echo "import os; print os.path.realpath('$1')" | python`
cat >>$root/conf/vhost.conf <<EOF
# Generated by: proxy-base-conf $*
-# Enable load balancing
+# Do not proxy admin pages
ProxyPass /balancer-manager !
ProxyPass /server-status !
ProxyPass /server-info !
+ProxyPass /proxy !
# Enable balancer manager
<Location /balancer-manager>
@@ -38,7 +39,7 @@ HostnameLookups on
EOF
cat >>$root/conf/adminauth.conf <<EOF
-# Generated by: proxy-conf $*
+# Generated by: proxy-base-conf $*
# Allow the server admin to manage the load balancer
<Location /balancer-manager>
Require user admin
diff --git a/sca-cpp/trunk/modules/http/proxy-conf b/sca-cpp/trunk/modules/http/proxy-conf
index b2156e6f74..dd51a34b5b 100755
--- a/sca-cpp/trunk/modules/http/proxy-conf
+++ b/sca-cpp/trunk/modules/http/proxy-conf
@@ -24,12 +24,14 @@ root=`echo "import os; print os.path.realpath('$1')" | python`
cat >>$root/conf/vhost.conf <<EOF
# Generated by: proxy-conf $*
-# Enable load balancing
+# Do not proxy admin pages
ProxyPass /balancer-manager !
ProxyPass /server-status !
ProxyPass /server-info !
-ProxyPass / balancer://cluster/
+ProxyPass /proxy !
+# Enable load balancing
+ProxyPass / balancer://cluster/
<Proxy balancer://cluster>
Require all granted
ProxySet lbmethod=byrequests
diff --git a/sca-cpp/trunk/modules/http/proxy-ssl-conf b/sca-cpp/trunk/modules/http/proxy-ssl-conf
index 94318d7db5..150cf88b60 100755
--- a/sca-cpp/trunk/modules/http/proxy-ssl-conf
+++ b/sca-cpp/trunk/modules/http/proxy-ssl-conf
@@ -24,12 +24,14 @@ root=`echo "import os; print os.path.realpath('$1')" | python`
cat >>$root/conf/vhost-ssl.conf <<EOF
# Generated by: proxy-ssl-conf $*
-# Enable load balancing
+# Do not proxy admin pages
ProxyPass /balancer-manager !
ProxyPass /server-status !
ProxyPass /server-info !
-ProxyPass / balancer://sslcluster/
+ProxyPass /proxy !
+# Enable load balancing
+ProxyPass / balancer://sslcluster/
<Proxy balancer://sslcluster>
Require all granted
ProxySet lbmethod=byrequests
diff --git a/sca-cpp/trunk/modules/js/htdocs/atomutil.js b/sca-cpp/trunk/modules/js/htdocs/atomutil.js
index 62f390d37e..068b5de2fd 100644
--- a/sca-cpp/trunk/modules/js/htdocs/atomutil.js
+++ b/sca-cpp/trunk/modules/js/htdocs/atomutil.js
@@ -27,12 +27,24 @@ var atom = {};
*/
atom.entryElementValues = function(e) {
var lt = filter(selector(mklist(element, "'title")), e);
- var t = isNil(lt)? '' : elementValue(car(lt));
+ var t = mklist(element, "'title", isNil(lt)? '' : elementValue(car(lt)));
+
var li = filter(selector(mklist(element, "'id")), e);
- var i = isNil(li)? '' : elementValue(car(li));
+ var i = mklist(element, "'id", isNil(li)? '' : elementValue(car(li)));
+
+ var la = filter(selector(mklist(element, "'author")), e);
+ var lan = isNil(la)? mklist() : filter(selector(mklist(element, "'name")), car(la));
+ var lae = isNil(la)? mklist() : filter(selector(mklist(element, "'email")), car(la));
+ var laa = isNil(lan)? lae : lan;
+ var a = isNil(laa)? mklist() : mklist(mklist(element, "'author", elementValue(car(laa))));
+
+ var lu = filter(selector(mklist(element, "'updated")), e);
+ var u = isNil(lu)? mklist() : mklist(mklist(element, "'updated", elementValue(car(lu))));
+
var lc = filter(selector(mklist(element, "'content")), e);
- return append(mklist(element, "'entry", mklist(element, "'title", t), mklist(element, "'id", i)),
- isNil(lc)? mklist() : mklist(mklist(element, "'content", elementValue(car(lc)))))
+ var c = isNil(lc)? mklist() : mklist(mklist(element, "'content", elementValue(car(lc))));
+
+ return append(append(append(mklist(element, "'entry", t, i), a), u), c);
};
/**
@@ -107,14 +119,20 @@ atom.readATOMFeed = function(l) {
atom.entryElement = function(l) {
var title = elementValue(namedElementChild("'title", l));
var id = elementValue(namedElementChild("'id", l));
+ var author = namedElementChild("'author", l);
+ var email = isNil(author)? false : (elementValue(author).indexOf('@') != -1);
+ var updated = namedElementChild("'updated", l);
var content = namedElementChild("'content", l);
var text = isNil(content)? false : elementHasValue(content);
- return append(append(
+ return append(append(append(append(
mklist(element, "'entry", mklist(attribute, "'xmlns", "http://www.w3.org/2005/Atom"),
mklist(element, "'title", mklist(attribute, "'type", "text"), title), mklist(element, "'id", id)),
+ isNil(author)? mklist() : mklist(element, "'author",
+ (email? mklist(element, "'email", elementValue(author)) : mklist(element, "'name", elementValue(author))))),
+ isNil(updated)? mklist() : mklist(element, "'updated", elementValue(updated))),
isNil(content)? mklist() :
- mklist(append(mklist(element, "'content", mklist(attribute, "'type", text? "text" : "application/xml")),
- text? mklist(elementValue(content)) : elementChildren(content)))),
+ mklist(append(mklist(element, "'content", mklist(attribute, "'type", text? "text" : "application/xml")),
+ text? mklist(elementValue(content)) : elementChildren(content)))),
mklist(mklist(element, "'link", mklist(attribute, "'href", id))));
};
diff --git a/sca-cpp/trunk/modules/js/htdocs/component.js b/sca-cpp/trunk/modules/js/htdocs/component.js
index 10b4535470..c3799ef708 100644
--- a/sca-cpp/trunk/modules/js/htdocs/component.js
+++ b/sca-cpp/trunk/modules/js/htdocs/component.js
@@ -191,6 +191,7 @@ HTTPBindingClient.prototype.jsonApply = function(req) {
var http = HTTPBindingClient.getHTTPRequest();
var hascb = req.cb? true : false;
http.open("POST", this.uri, hascb);
+ http.setRequestHeader("Accept", "*/*");
http.setRequestHeader("Content-Type", "application/json-rpc");
// Construct call back if we have one
@@ -238,7 +239,9 @@ HTTPBindingClient.prototype.get = function(id, cb) {
var hascb = cb? true : false;
// Get from local storage first
- var item = localStorage.getItem(u);
+ var ls = window.lstorage || localStorage;
+ var item = null;
+ try { item = ls.getItem(u); } catch(e) {}
//log('localStorage.getItem', u, item);
if (item != null && item != '') {
if (!hascb)
@@ -253,6 +256,7 @@ HTTPBindingClient.prototype.get = function(id, cb) {
// Connect to the service
var http = HTTPBindingClient.getHTTPRequest();
http.open("GET", u, hascb);
+ http.setRequestHeader("Accept", "*/*");
// Construct call back if we have one
if (hascb) {
@@ -282,7 +286,7 @@ HTTPBindingClient.prototype.get = function(id, cb) {
// Store retrieved entry in local storage
if (http.responseText != null) {
//log('localStorage.setItem', u, http.responseText);
- localStorage.setItem(u, http.responseText);
+ try { ls.setItem(u, http.responseText); } catch(e) {}
}
try {
return cb(http.responseText);
@@ -337,6 +341,7 @@ HTTPBindingClient.prototype.getnocache = function(id, cb) {
// Connect to the service
var http = HTTPBindingClient.getHTTPRequest();
http.open("GET", u, hascb);
+ http.setRequestHeader("Accept", "*/*");
// Construct call back if we have one
if (hascb) {
@@ -407,6 +412,7 @@ HTTPBindingClient.prototype.post = function (entry, cb) {
var http = HTTPBindingClient.getHTTPRequest();
var hascb = cb? true : false;
http.open("POST", this.uri, hascb);
+ http.setRequestHeader("Accept", "*/*");
http.setRequestHeader("Content-Type", "application/atom+xml");
// Construct call back if we have one
@@ -445,13 +451,15 @@ HTTPBindingClient.prototype.put = function (id, entry, cb) {
var u = this.uri + '/' + id;
// Update local storage
- localStorage.setItem(u, entry);
+ var ls = window.lstorage || localStorage;
+ try { ls.setItem(u, entry); } catch(e) {}
//log('localStorage.setItem', u, entry);
// Connect to the service
var http = HTTPBindingClient.getHTTPRequest();
var hascb = cb? true : false;
http.open("PUT", u, hascb);
+ http.setRequestHeader("Accept", "*/*");
http.setRequestHeader("Content-Type", "application/atom+xml");
// Construct call back if we have one
@@ -489,13 +497,15 @@ HTTPBindingClient.prototype.del = function (id, cb) {
var u = this.uri + '/' + id;
// Update local storage
- localStorage.removeItem(u);
+ var ls = window.lstorage || localStorage;
+ try { ls.removeItem(u); } catch(e) {}
//log('localStorage.removeItem', u);
// Connect to the service
var http = HTTPBindingClient.getHTTPRequest();
var hascb = cb? true : false;
http.open("DELETE", u, hascb);
+ http.setRequestHeader("Accept", "*/*");
// Construct call back if we have one
if (cb) {
diff --git a/sca-cpp/trunk/modules/js/htdocs/ui.css b/sca-cpp/trunk/modules/js/htdocs/ui.css
index 364e47774a..3dde10a2c0 100644
--- a/sca-cpp/trunk/modules/js/htdocs/ui.css
+++ b/sca-cpp/trunk/modules/js/htdocs/ui.css
@@ -19,146 +19,181 @@
body {
margin-top: 0px; margin-bottom: 2px; margin-left: 2px; margin-right: 2px;
-font-family: "Helvetica Neue", Helvetica; font-style: normal; font-variant: normal; font-size: 13px;
+font-family: Arial; font-style: normal; font-variant: normal; font-size: 14px;
+background-color: #ffffff; opacity: 1;
-webkit-text-size-adjust: none;
-webkit-touch-callout: none;
-webkit-tap-highlight-color: rgba(0,0,0,0);
--webkit-user-select: none;
+-webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none;
+cursor: default;
+-webkit-backface-visibility: hidden;
}
.delayed {
visibility: hidden;
}
-.devicewidth {
-position: absolute; top: 0px; left: 0px; width: 100%; height: 5000px; overflow: hidden;
+.fixed {
+position: absolute;
}
-.mainbodydiv {
+.devicewidth {
position: absolute; top: 0px; left: 0px; width: 100%; height: 5000px; overflow: hidden;
}
-.bodydiv {
-position: absolute; top: 0px; left: 0px; width: 100%; height: 5000px; overflow: hidden;
+.mainbody {
+position: absolute; top: 0px; left: 0px; width: 100%; height: 5000px; overflow: visible;
+-webkit-backface-visibility: hidden;
}
.viewcontainer3dm {
--webkit-perspective: 1000;
+position: absolute; left: 0px; top: 35px; width: 100%;
+-webkit-backface-visibility: hidden;
}
.viewcontainer3d {
+position: absolute; left: 0px; top: 35px; width: 100%;
+-webkit-backface-visibility: hidden;
}
.leftviewloading3dm {
-position: absolute; top: 0px; left: 0px; width: 100%; height: 5000px; overflow: visible;
--webkit-transform: translate3d(100%, 0px, 0) rotateY(0deg);
--webkit-backface-visibility: hidden; background-color: #ffffff;
+position: absolute; top: 0px; left: 0px; width: 100%; height: 5000px; overflow: hidden;
+z-index: -10; background-color: #ffffff;
+-webkit-transform: translate(100%, 0px);
-moz-transform: translate(100%, 0px);
-ms-transform: translate(100%, 0px);
+-o-transform: translate(100%, 0px);
transform: translate(100%, 0px);
+-webkit-backface-visibility: hidden;
}
.rightviewloading3dm {
-position: absolute; top: 0px; left: 0px; width: 100%; height: 5000px; overflow: visible;
--webkit-transform: translate3d(-100%, 0px, 0) rotateY(0deg);
--webkit-backface-visibility: hidden; background-color: #ffffff;
+position: absolute; top: 0px; left: 0px; width: 100%; height: 5000px; overflow: hidden;
+z-index: -10; background-color: #ffffff;
+-webkit-transform: translate(-100%, 0px);
-moz-transform: translate(-100%, 0px);
-ms-transform: translate(-100%, 0px);
+-o-transform: translate(-100%, 0px);
transform: translate(-100%, 0px);
-}
-
-.flipviewloading3dm {
-position: absolute; top: 0px; left: 0px; width: 100%; height: 5000px; overflow: visible;
--webkit-transform: translate3d(0px, 0px, 0) rotateY(180deg);
--webkit-backface-visibility: hidden; background-color: #ffffff;
--moz-transform: translate(100%, 0px);
--ms-transform: translate(100%, 0px);
-transform: translate(100%, 0px);
+-webkit-backface-visibility: hidden;
}
.viewloading3d {
-position: absolute; top: 0px; left: 0px; width: 100%; height: 5000px; overflow: visible;
-visibility: hidden;
--webkit-transform: translate3d(100%, 0px, 0) rotateY(0deg);
--webkit-backface-visibility: hidden; background-color: #ffffff;
+position: absolute; top: 0px; left: 0px; width: 100%; height: 5000px; overflow: hidden;
+visibility: hidden; z-index: -10; background-color: #ffffff;
+-webkit-transform: translate(100%, 0px);
-moz-transform: translate(100%, 0px);
-ms-transform: translate(100%, 0px);
+-o-transform: translate(100%, 0px);
transform: translate(100%, 0px);
+-webkit-backface-visibility: hidden;
}
.viewloaded3dm {
position: absolute; top: 0px; left: 0px; width: 100%; height: 5000px; overflow: visible;
--webkit-transition: -webkit-transform 0.5s ease-in-out;
--moz-transition: -moz-transform 0.5s ease-in-out;
--ms-transition: -ms-transform 0.5s ease-in-out;
-transition: transform 0.5s ease-in-out;
--webkit-transform: translate3d(0px, 0px, 0) rotateY(0deg);
--webkit-backface-visibility: hidden; background-color: #ffffff;
+z-index: 0; background-color: #ffffff;
+-webkit-transition: -webkit-transform 0.4s ease-in-out;
+-moz-transition: -moz-transform 0.4s ease-in-out;
+-ms-transition: -ms-transform 0.4s ease-in-out;
+-o-transition: -o-transform 0.4s ease-in-out;
+transition: transform 0.4s ease-in-out;
+-webkit-transform: translate(0px, 0px);
-moz-transform: translate(0px, 0px);
-ms-transform: translate(0px, 0px);
+-o-transform: translate(0px, 0px);
transform: translate(0px, 0px);
+-webkit-backface-visibility: hidden;
}
.viewloaded3d {
position: absolute; top: 0px; left: 0px; width: 100%; height: 5000px; overflow: visible;
--webkit-transform: translate3d(0px, 0px, 0) rotateY(0deg);
--webkit-backface-visibility: hidden; background-color: #ffffff;
+z-index: 0; background-color: #ffffff;
+-webkit-transform: translate(0px, 0px);
-moz-transform: translate(0px, 0px);
-ms-transform: translate(0px, 0px);
+-o-transform: translate(0px, 0px);
transform: translate(0px, 0px);
+-webkit-backface-visibility: hidden;
}
.viewunloading3dm {
-position: absolute; top: 0px; left: 0px; width: 100%; height: 5000px; overflow: visible;
--webkit-transform: translate3d(0px, 0px, 0) rotateY(0deg);
--webkit-backface-visibility: hidden; background-color: #ffffff;
+position: absolute; top: 0px; left: 0px; width: 100%; height: 5000px; overflow: hidden;
+z-index: 0; background-color: #ffffff;
+-webkit-transform: translate(0px, 0px);
-moz-transform: translate(0px, 0px);
-ms-transform: translate(0px, 0px);
+-o-transform: translate(0px, 0px);
transform: translate(0px, 0px);
+-webkit-backface-visibility: hidden;
}
.leftviewunloaded3dm {
-position: absolute; top: 0px; left: 0px; width: 100%; height: 5000px; overflow: visible;
--webkit-transition: -webkit-transform 0.5s ease-in-out;
--moz-transition: -moz-transform 0.5s ease-in-out;
--ms-transition: -ms-transform 0.5s ease-in-out;
-transition: transform 0.5s ease-in-out;
--webkit-transform: translate3d(-100%, 0px, 0px) rotateY(0deg);
--webkit-backface-visibility: hidden; background-color: #ffffff;
+position: absolute; top: 0px; left: 0px; width: 100%; height: 5000px; overflow: hidden;
+z-index: -10; background-color: #ffffff;
+-webkit-transition: -webkit-transform 0.4s ease-in-out;
+-moz-transition: -moz-transform 0.4s ease-in-out;
+-ms-transition: -ms-transform 0.4s ease-in-out;
+-o-transition: -o-transform 0.4s ease-in-out;
+transition: transform 0.4s ease-in-out;
+-webkit-transform: translate(-100%, 0px);
-moz-transform: translate(-100%, 0px);
-ms-transform: translate(-100%, 0px);
+-o-transform: translate(-100%, 0px);
transform: translate(-100%, 0px);
+-webkit-backface-visibility: hidden;
}
.rightviewunloaded3dm {
-position: absolute; top: 0px; left: 0px; width: 100%; height: 5000px; overflow: visible;
--webkit-transition: -webkit-transform 0.5s ease-in-out;
--moz-transition: -moz-transform 0.5s ease-in-out;
--ms-transition: -ms-transform 0.5s ease-in-out;
-transition: transform 0.5s ease-in-out;
--webkit-transform: translate3d(100%, 0px, 0) rotateY(0deg);
--webkit-backface-visibility: hidden; background-color: #ffffff;
+position: absolute; top: 0px; left: 0px; width: 100%; height: 5000px; overflow: hidden;
+z-index: -10; background-color: #ffffff;
+-webkit-transition: -webkit-transform 0.4s ease-in-out;
+-moz-transition: -moz-transform 0.4s ease-in-out;
+-ms-transition: -ms-transform 0.4s ease-in-out;
+-o-transition: -o-transform 0.4s ease-in-out;
+transition: transform 0.4s ease-in-out;
+-webkit-transform: translate(100%, 0px);
-moz-transform: translate(100%, 0px);
-ms-transform: translate(100%, 0px);
+-o-transform: translate(100%, 0px);
transform: translate(100%, 0px);
+-webkit-backface-visibility: hidden;
}
-.flipviewunloaded3dm {
-position: absolute; top: 0px; left: 0px; width: 100%; height: 5000px; overflow: visible;
--webkit-transition: -webkit-transform 0.5s ease-in-out;
--moz-transition: -moz-transform 0.5s ease-in-out;
--ms-transition: -ms-transform 0.5s ease-in-out;
-transition: transform 0.5s ease-in-out;
--webkit-transform: translate3d(0px, 0px, 0) rotateY(-180deg);
--webkit-backface-visibility: hidden; background-color: #ffffff;
--moz-transform: translate(0px, 0px);
--ms-transform: translate(0px, 0px);
-transform: translate(0px, 0px);
+.body {
+width: 100%; height: 5000px; overflow: visible;
+-webkit-backface-visibility: hidden;
+}
+
+.viewhead {
+position: absolute; left: 0px; top: 35px; height: 35px; line-height: 35px; width: 100%; z-index: 8;
+font-size: 110%; font-weight: bold; background-color: #f1f1f1; color: #000000;
+border-top: 1px; border-bottom: 1px; border-left: 0px; border-right: 0px;
+border-style: solid; border-top-color: #e5e5e5; border-bottom-color: #e5e5e5;
+overflow: hidden;
+-webkit-backface-visibility: hidden;
+}
+
+.viewheadbackground {
+position: absolute; left: 0px; top: 35px; height: 35px; line-height: 35px; width: 2500px; z-index: 7;
+font-size: 110%; font-weight: bold; background-color: #f1f1f1; color: #000000;
+border-top: 1px; border-bottom: 1px; border-left: 0px; border-right: 0px;
+border-style: solid; border-top-color: #e5e5e5; border-bottom-color: #e5e5e5;
+overflow: hidden;
+-webkit-backface-visibility: hidden;
+}
+
+.viewcontent {
+position: absolute; left: 0px; top: 38px; width: 100%;
+-webkit-backface-visibility: hidden;
+}
+
+.viewform {
+position: absolute; left: 0px; top: 40px; width: 100%;
}
table {
border: 0px; border-collapse: collapse; border-color: #a2bae7; border-style: solid;
-font-family: "Helvetica Neue", Helvetica; font-style: normal; font-variant: normal; font-size: 13px;
+font-family: Arial; font-style: normal; font-variant: normal; font-size: 14px;
overflow: visible;
}
@@ -167,22 +202,23 @@ border-bottom: 1px; border-bottom-style: solid; border-color: #dcdcdc;
}
th {
-font-weight: bold; background-color: #d4e6fc; color: #000000; height: 18px;
+font-size: 110%; font-weight: bold; background-color: #f1f1f1; color: #000000;
text-align: left; padding-left: 2px; padding-right: 8px; padding-top: 0px; padding-bottom: 0px; vertical-align: middle; white-space: nowrap;
-border-top: 1px; border-bottom: 1px; border-left: 1px; border-right: 1px; border-style: solid; border-top-color: #a2bae7; border-bottom-color: #d1d3d4; border-left-color: #a2bae7; border-right-color: #a2bae7;
+border-top: 1px; border-bottom: 1px; border-left: 1px; border-right: 1px; border-style: solid; border-top-color: #e5e5e5; border-bottom-color: #e5e5e5; border-left-color: #e5e5e5; border-right-color: #e5e5e5;
overflow: hidden;
}
.section {
-font-weight: bold; background-color: #d4e6fc; color: #000000; height: 24px; padding-top: 1px; padding-bottom: 0px; padding-left: 2px; padding-right: 2px;
-border-top: 1px; border-bottom: 1px; border-left: 0px; border-right: 0px; border-style: solid; border-top-color: #a2bae7; border-bottom-color: #d1d3d4; border-left-color: #a2bae7; border-right-color: #a2bae7;
+font-size: 110%; font-weight: bold; background-color: #f1f1f1; color: #000000; height: 30px; line-height: 30px;
+text-align: left; padding-top: 0px; padding-bottom: 0px; padding-left: 2px; padding-right: 2px; white-space: nowrap;
+border-top: 1px; border-bottom: 1px; border-left: 0px; border-right: 0px; border-style: solid; border-top-color: #e5e5e5; border-bottom-color: #e5e5e5; border-left-color: #e5e5e5; border-right-color: #e5e5e5;
overflow: hidden;
}
.hsection {
width: 100%; height: 0px; visibility: hidden;
border-top: 0px; border-bottom: 0px; border-left: 0px; border-right: 0px; border-style: solid; border-bottom-color: #000000; background-color: #ffffff;
-padding: 0px; margin-bottom: 0px; margin-left: auto; margin-right: auto; text-align: center;
+padding-left: 2px; padding-right: 2px; padding-top: 0px; padding-bottom: 0px; margin-bottom: 0px; margin-left: auto; margin-right: auto; text-align: center;
}
.fsection{
@@ -191,10 +227,39 @@ border-top: 0px; border-bottom: 0px; border-left: 0px; border-right: 0px; border
padding: 0px; margin-top: 0px; margin-left: auto; margin-right: auto; text-align: center;
}
+.bluetext {
+color: #4787ed;
+}
+
+.redtext {
+color: #d14836;
+}
+
+.mirror {
+display: inline-block;
+-webkit-transform: scaleX(-1);
+-moz-transform: scaleX(-1);
+-ms-transform: scaleX(-1);
+-o-transform: scaleX(-1);
+transform: scaleX(-1);
+}
+
+.greentext {
+color: #009900;
+}
+
.text {
padding-top: 3px; padding-bottom: 4px; vertical-align: middle; white-space: nowrap;
}
+.link {
+padding-top: 3px; padding-bottom: 4px; vertical-align: middle; white-space: nowrap;
+}
+
+.checkbox {
+padding-top: 3px; padding-bottom: 4px; vertical-align: middle; white-space: nowrap;
+}
+
.thl {
border-left: 0px;
}
@@ -264,39 +329,122 @@ padding: 3px; background-color: #dcdcdc; color: #000000;
input {
vertical-align: middle;
-font-family: "Helvetica Neue", Helvetica; font-style: normal; font-variant: normal; font-size: 13px;
+font-family: Arial; font-style: normal; font-variant: normal; font-size: 15px;
+outline: none;
+-webkit-text-size-adjust: 100%;
+}
+
+button {
+vertical-align: middle;
+font-family: Arial; font-style: normal; font-variant: normal; font-size: 15px;
+outline: none;
-webkit-text-size-adjust: 100%;
}
textarea {
-font-family: "Helvetica Neue", Helvetica; font-style: normal; font-variant: normal; font-size: 13px;
+font-family: Arial; font-style: normal; font-variant: normal; font-size: 15px;
+outline: none;
overflow: auto; resize: none;
}
-.editable {
+.flatentry {
+font-family: Arial; font-style: normal; font-variant: normal; font-size: 15px;
+-webkit-appearance: none; appearance: none;
+border: 1px solid #d9d9d9!important; border-top: 1px solid silver!important;
+box-sizing: border-box; -moz-box-sizing: border-box; -webkit-box-sizing: border-box;
+border-radius: 1px; -webkit-border-radius: 1px; -moz-border-radius: 1px;
+margin: 1px!important; padding: 3px 1px 3px 3px;
+}
+
+.graphentry {
+font-family: Arial; font-style: normal; font-variant: normal; font-size: 13px;
+-webkit-appearance: none; appearance: none;
+border: 1px solid #d9d9d9!important; border-top: 1px solid silver!important;
+box-sizing: border-box; -moz-box-sizing: border-box; -webkit-box-sizing: border-box;
+border-radius: 1px; -webkit-border-radius: 1px; -moz-border-radius: 1px;
+margin: 0px; padding: 0px;
+}
+
+.flatcheckbox {
+}
+
+.editablewidget {
+-webkit-user-select: text; -moz-user-select: text; -ms-user-select: text; user-select: text;
+outline: none; -moz-outline-style: none;
+}
+
+.noneditablewidget {
+outline: none; -moz-outline-style: none;
+}
+
+.editablesvg {
background-color: transparent;
font-family: inherit; font-style: inherit; font-variant: inherit; font-size: inherit; font-weight: inherit;
padding: 0px; margin: 0px;
overflow: auto; resize: none;
-outline: none; -webkit-appearance: none; -moz-outline-style: none;
--webkit-text-size-adjust: 100%;
+outline: none; -moz-outline-style: none;
+-webkit-appearance: none; -webkit-text-size-adjust: 100%;
border: 0px;
}
a:link {
-color: #598edd; text-decoration: none; white-space: nowrap;
+color: #357ae8; text-decoration: none; white-space: nowrap; cursor: pointer;
}
a:visited {
-color: #598edd; text-decoration: none; white-space: nowrap;
+color: #357ae8; text-decoration: none; white-space: nowrap; cursor: pointer;
+}
+
+.tbarmenu {
+position: absolute; top: 0px; left: 0px; z-index: 10; width: 100%; margin: 0px; padding: 0px; border-collapse: separate;
+height: 35px; line-height: 35px; background-color: #2c2c2c;
+border-top: 1px; border-bottom: 1px; border-left: 0px; border-right: 0px; border-style: solid; border-top-color: #2c2c2c; border-bottom-color: #2c2c2c;
+-webkit-backface-visibility: hidden;
+}
+
+.tbarbackground {
+position: absolute; top: 0px; left: 0px; z-index: 9; width: 2500px; margin: 0px; padding: 0px; border-collapse: separate;
+height: 35px; line-height: 35px; background-color: #2c2c2c;
+border-top: 1px; border-bottom: 1px; border-left: 0px; border-right: 0px; border-style: solid; border-top-color: #2c2c2c; border-bottom-color: #2c2c2c;
+overflow: hidden;
+-webkit-backface-visibility: hidden;
+}
+
+.tbarleft {
+padding-left: 2px; padding-right: 6px; white-space: nowrap; float: left;
+}
+
+.tbarright {
+padding-left: 6px; padding-right: 2px; white-space: nowrap; float: right;
+}
+
+.tbaramenu {
+font-size: 110%; color: #cccccc; text-decoration: none; white-space: nowrap;
+}
+
+.tbarsmenu {
+font-size: 110%; font-weight: bold; color: #ffffff; text-decoration: none; white-space: nowrap;
}
.amenu {
-color: #598edd; text-decoration: none; white-space: nowrap;
+padding-left: 2px; padding-right: 6px; white-space: nowrap; color: #808080; text-decoration: none; float: left;
}
.smenu {
-font-weight: bold; color: #000000; text-decoration: none; white-space: nowrap;
+padding-left: 2px; padding-right: 6px; white-space: nowrap; color: #000000; text-decoration: none; float: left;
+}
+
+.cmenu {
+font-size: 18px; padding-left: 6px; padding-right: 6px; white-space: nowrap; color: #000000; text-decoration: none;
+width: 100%; margin-left: auto; margin-right: auto; text-align: center; float: right;
+}
+
+.bcmenu {
+font-size: 22px; padding-left: 2px; padding-right: 6px; white-space: nowrap; color: #000000; text-decoration: none;
+}
+
+.rmenu {
+padding-left: 2px; padding-right: 2px; white-space: nowrap; white-space: nowrap; float: right;
}
h1 {
@@ -319,141 +467,161 @@ img {
border: 0px;
}
+.plusminus {
+font-size: 18px; font-family: "Courier New";
+}
+
.imgbutton {
width: 142px; height: 64px; margin-left: 20px; margin-right: 20px; padding: 0px; border: 1px; cursor: pointer;
}
-.toolbutton {
-font-weight: bold; font-size: 16px;
-display: inline-block; width: 24px; height: 20px; padding: 0px;
-vertical-align: middle; text-align: center; margin-left: 0px; margin-right: 0px;
-padding-left: 0px; padding-right: 0px; padding-top: 0px; padding-bottom: 0px;
+.graybutton {
+display: inline-block; text-align: center; color: #444; font-weight: bold;
+padding-top: 0px; padding-bottom: 0px; padding-left: 4px; padding-right: 4px;
+height: 28px; line-height: 28px; min-width: 30px;
+-webkit-border-radius: 2px; -moz-border-radius: 2px; border-radius: 2px;
+border: 1px solid gainsboro; background-color: whiteSmoke;
+background-image: -webkit-gradient(linear,left top,left bottom,from(whiteSmoke),to(#f1f1f1));
+background-image: -webkit-linear-gradient(top,whiteSmoke,#f1f1f1);
+background-image: -moz-linear-gradient(top,whiteSmoke,#f1f1f1);
+background-image: -ms-linear-gradient(top,whiteSmoke,#f1f1f1);
+background-image: -o-linear-gradient(top,whiteSmoke,#f1f1f1);
+background-image: linear-gradient(top,whiteSmoke,#f1f1f1);
+cursor: default;
+}
+
+.graybutton:hover {
+border: 1px solid #c6c6c6; color: #333; text-shadow: 0 1px rgba(0, 0, 0, 0.3); background-color: #f8f8f8;
+background-image: -webkit-gradient(linear,left top,left bottom,from(#f8f8f8),to(#f1f1f1));
+background-image: -webkit-linear-gradient(top,#f8f8f8,#f1f1f1);
+background-image: -moz-linear-gradient(top,#f8f8f8,#f1f1f1);
+background-image: -ms-linear-gradient(top,#f8f8f8,#f1f1f1);
+background-image: -o-linear-gradient(top,#f8f8f8,#f1f1f1);
+background-image: linear-gradient(top,#f8f8f8,#f1f1f1);
}
-.greenbutton {
--webkit-border-radius: 4px;
-border-radius: 4px;
-background: #96d333;
-background: -moz-linear-gradient(top, #f8f8f8 0%, #96d333 80%);
-background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#f8f8f8), color-stop(80%,#96d333));
-filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#f8f8f8', endColorstr='#96d333',GradientType=0 );
-background: -o-linear-gradient(top, #f8f8f8 0%,#96d333 80%);
-border: 1px outset #dcdcdc;
-padding-left: 4px; padding-right: 4px; padding-top: 2px; padding-bottom: 2px; margin: 2px;
-cursor: pointer;
+.graybutton:active {
+background-color: #f6f6f6;
+background-image: -webkit-gradient(linear,left top,left bottom,from(#f6f6f6),to(#f1f1f1));
+background-image: -webkit-linear-gradient(top,#f6f6f6,#f1f1f1);
+background-image: -moz-linear-gradient(top,#f6f6f6,#f1f1f1);
+background-image: -ms-linear-gradient(top,#f6f6f6,#f1f1f1);
+background-image: -o-linear-gradient(top,#f6f6f6,#f1f1f1);
+background-image: linear-gradient(top,#f6f6f6,#f1f1f1);
+-webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
}
-.tgreenbutton {
--webkit-border-radius: 4px;
-border-radius: 4px;
-background: #96d333;
-background: -moz-linear-gradient(top, #f8f8f8 0%, #96d333 80%);
-background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#f8f8f8), color-stop(80%,#96d333));
-filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#f8f8f8', endColorstr='#96d333',GradientType=0 );
-background: -o-linear-gradient(top, #f8f8f8 0%,#96d333 80%);
-border: 1px outset #dcdcdc;
-padding-left: 4px; padding-right: 4px; padding-top: 2px; padding-bottom: 2px; margin: 2px;
-cursor: pointer;
+.graybutton:disabled {
+color: #c0c0c0;
}
.bluebutton {
--webkit-border-radius: 4px;
-border-radius: 4px;
-background: #598edd;
-background: -moz-linear-gradient(top, #f8f8f8 0%, #598edd 80%);
-background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#f8f8f8), color-stop(80%,#598edd));
-filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#f8f8f8', endColorstr='#598edd',GradientType=0 );
-background: -o-linear-gradient(top, #f8f8f8 0%,#598edd 80%);
-border: 1px outset #dcdcdc;
-padding-left: 4px; padding-right: 4px; padding-top: 2px; padding-bottom: 2px; margin: 2px;
-cursor: pointer;
+border: 1px solid #3079ed; color: white; text-shadow: 0 1px rgba(0, 0, 0, 0.1); background-color: #4d90fe;
+background-image: -webkit-gradient(linear,left top,left bottom,from(#4d90fe),to(#4787ed));
+background-image: -webkit-linear-gradient(top,#4d90fe,#4787ed);
+background-image: -moz-linear-gradient(top,#4d90fe,#4787ed);
+background-image: -ms-linear-gradient(top,#4d90fe,#4787ed);
+background-image: -o-linear-gradient(top,#4d90fe,#4787ed);
+background-image: linear-gradient(top,#4d90fe,#4787ed);
+}
+
+.bluebutton:disabled {
+color: #c0c0c0;
+}
+
+.bluebutton:hover {
+border: 1px solid #2f5bb7; color: white; text-shadow: 0 1px rgba(0, 0, 0, 0.3); background-color: #357ae8;
+background-image: -webkit-gradient(linear,left top,left bottom,from(#4d90fe),to(#357ae8));
+background-image: -webkit-linear-gradient(top,#4d90fe,#357ae8);
+background-image: -moz-linear-gradient(top,#4d90fe,#357ae8);
+background-image: -ms-linear-gradient(top,#4d90fe,#357ae8);
+background-image: -o-linear-gradient(top,#4d90fe,#357ae8);
+background-image: linear-gradient(top,#4d90fe,#357ae8);
+}
+
+.bluebutton:hover:disabled {
+color: #c0c0c0;
}
.redbutton {
--webkit-border-radius: 4px;
-border-radius: 4px;
-background: #d03f41;
-background: -moz-linear-gradient(top, #f8f8f8 0%, #d03f41 80%);
-background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#f8f8f8), color-stop(80%,#d03f41));
-filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#f8f8f8', endColorstr='#d03f41',GradientType=0 );
-background: -o-linear-gradient(top, #f8f8f8 0%,#d03f41 80%);
-border: 1px outset #dcdcdc;
-padding-left: 4px; padding-right: 4px; padding-top: 2px; padding-bottom: 2px; margin: 2px;
-cursor: pointer;
-}
-
-.orangebutton {
--webkit-border-radius: 4px;
-border-radius: 4px;
-background: #ffbb00;
-background: -moz-linear-gradient(top, #f8f8f8 0%, #ffbb00 80%);
-background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#f8f8f8), color-stop(80%,#ffbb00));
-filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#f8f8f8', endColorstr='#ffbb00',GradientType=0 );
-background: -o-linear-gradient(top, #f8f8f8 0%,#ffbb00 80%);
-border: 1px outset #dcdcdc;
-padding-left: 4px; padding-right: 4px; padding-top: 2px; padding-bottom: 2px; margin: 2px;
-cursor: pointer;
+border: 1px solid transparent; color: white; text-shadow: 0 1px rgba(0, 0, 0, 0.1); background-color: #d14836;
+background-image: -webkit-gradient(linear,left top,left bottom,from(#dd4b39),to(#d14836));
+background-image: -webkit-linear-gradient(top,#dd4b39,#d14836);
+background-image: -moz-linear-gradient(top,#dd4b39,#d14836);
+background-image: -ms-linear-gradient(top,#dd4b39,#d14836);
+background-image: -o-linear-gradient(top,#dd4b39,#d14836);
+background-image: linear-gradient(top,#dd4b39,#d14836);
+-webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.3); -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.3); -ms-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.3);
+-o-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.3); box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.3);
}
-.graybutton {
--webkit-border-radius: 4px;
-border-radius: 4px;
-background: #dcdcdc;
-background: -moz-linear-gradient(top, #f8f8f8 0%, #dcdcdc 80%);
-background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#f8f8f8), color-stop(80%,#dcdcdc));
-filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#f8f8f8', endColorstr='#dcdcdc',GradientType=0 );
-background: -o-linear-gradient(top, #f8f8f8 0%,#dcdcdc 80%);
-border: 1px outset #dcdcdc;
-padding-left: 4px; padding-right: 4px; padding-top: 2px; padding-bottom: 2px; margin: 2px;
-margin: 2px;
-cursor: pointer;
+.redbutton:disabled {
+color: #c0c0c0;
}
-.tbar {
-margin: 0px; width: 100%; padding-top: 0px; padding-left: 0px; padding-right: 0px; padding-bottom: 0px; border-collapse: separate;
-background-color: #2c2c2c;
+.redbutton:hover {
+border: 1px solid #b0281a; border-bottom-color: #af301f; color: white; background-color: #c53727;
+background-image: -webkit-linear-gradient(top,#dd4b39,#c53727);
+background-image: -moz-linear-gradient(top,#dd4b39,#c53727);
+background-image: -ms-linear-gradient(top,#dd4b39,#c53727);
+background-image: -o-linear-gradient(top,#dd4b39,#c53727);
+background-image: linear-gradient(top,#dd4b39,#c53727);
+-webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2); -moz-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2); -ms-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);
+-o-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2); box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);
}
-.ltbar {
-padding-left: 2px; padding-right: 6px; padding-top: 3px; padding-bottom: 4px; white-space: nowrap; vertical-align: middle;
+.redbutton:hover:disabled {
+color: #c0c0c0;
}
-.dtbar {
-padding-left: 0px; padding-right: 0px; padding-top: 3px; padding-bottom: 4px; white-space: nowrap; vertical-align: middle; text-align: right;
+.box {
+width: 150px; display: inline-block;
+border: 1px; border-style: solid; border-color: #dcdcdc; border-collapse: collapse;
+white-space: nowrap; margin: 2px; padding: 2px; vertical-align: top;
}
-.rtbar {
-padding-left: 6px; padding-right: 2px; padding-top: 3px; padding-bottom: 4px; white-space: nowrap; vertical-align: middle; text-align: right;
+.appicon {
+float: left;
+height: 50px; width: 50px; vertical-align: top; margin: 0px; padding: 0px;
}
-.tbaramenu {
-color: #cccccc; text-decoration: none; white-space: nowrap; vertical-align: middle;
+.apptitle {
+font-weight: bold;
}
-.tbarsmenu {
-font-weight: bold; color: #ffffff; text-decoration: none; white-space: nowrap; vertical-align: middle;
+.note {
+font-size: 12px; color: #808080;
}
-.suggest {
-background-color: #d4e6fc; color: #598edd;
-border-top: 1px; border-bottom: 1px; border-left: 1px; border-right: 1px; border-style: solid; border-top-color: #a2bae7; border-bottom-color: #d1d3d4; border-left-color: #d1d3d4; border-right-color: #d1d3d4;
-position: absolute; overflow: auto; overflow-x: hidden; padding: 0px; margin: 0px;
-cursor: default;
+.pagediv {
+position: absolute; display: block; overflow: visible;
+-webkit-backface-visibility: hidden;
}
-.suggestTable {
-border: 0px; border-collapse: separate; padding-left: 5px; padding-right: 5px; padding-top: 2px; padding-bottom: 2px; margin: 0px;
+.graphdiv {
+position: absolute; display: block; overflow: visible;
+-webkit-backface-visibility: hidden;
}
-.suggestItem {
-padding-left: 2px; padding-top: 0px; padding-bottom: 0px; padding-right: 2px; vertical-align: middle; background-color: #d4e6fc; color: #598edd;
+.g {
+position: absolute; display: block; overflow: visible;
+-webkit-backface-visibility: hidden;
}
-.suggestHilighted {
-padding-left: 2px; padding-top: 0px; padding-bottom: 0px; padding-right: 2px; vertical-align: middle; background-color: #598edd; color: #d4e6fc;
+.path {
+position: absolute; background: transparent; display: block; overflow: visible;
+visibility: visible;
+-webkit-backface-visibility: hidden;
}
-.svgtitle {
-margin: 0px; padding: 0px; font-family: "Helvetica Neue", Helvetica; font-style: normal; font-variant: normal; font-size: 10px; cursor: default;
+.gtitle {
+position: absolute;
+margin: 4px; padding: 0px; line-height: 15px; vertical-align: middle; white-space: nowrap;
+font-family: Arial; font-style: normal; font-variant: normal; font-size: 13px; cursor: default;
+background: transparent; display: block; overflow: visible;
+-webkit-text-size-adjust: none;
+-webkit-touch-callout: none;
+-webkit-tap-highlight-color: rgba(0,0,0,0);
+-webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none;
}
diff --git a/sca-cpp/trunk/modules/js/htdocs/ui.js b/sca-cpp/trunk/modules/js/htdocs/ui.js
index dcc1462084..f200321ccd 100644
--- a/sca-cpp/trunk/modules/js/htdocs/ui.js
+++ b/sca-cpp/trunk/modules/js/htdocs/ui.js
@@ -50,6 +50,13 @@ function $(id) {
};
/**
+ * Return a list of elements with the given class name.
+ */
+ui.elementsByClassName = function(node, c) {
+ return nodeList(node.getElementsByClassName(c));
+};
+
+/**
* Return the query string of a URL.
*/
ui.query = function(url) {
@@ -151,7 +158,7 @@ ui.evalScript = function(s) {
* Include a script.
*/
ui.includeScript = function(s) {
- log('include', s);
+ //log('include', s);
return eval(s);
};
@@ -207,18 +214,54 @@ ui.pixpos = function(p) {
};
/**
- * Reload the current document when orientation changes.
+ * Default orientation change behavior.
*/
-ui.onorientationchange = function() {
- window.location.reload();
+ui.onorientationchange = function(e) {
+
+ // Scroll to the top and hide the address bar
+ window.scrollTo(0, 0);
+
+ // Change fixed position elements to absolute then back to fixed
+ // to make sure they're correctly layed out after the orientation
+ // change
+ map(function(e) {
+ e.style.position = 'absolute';
+ return e;
+ }, ui.elementsByClassName(document, 'fixed'));
+
+ setTimeout(function() {
+ map(function(e) {
+ e.style.position = 'fixed';
+ return e;
+ }, ui.elementsByClassName(document, 'fixed'));
+ }, 0);
return true;
-}
+};
+
+/**
+ * Default page load behavior.
+ */
+ui.onload = function() {
+
+ // Scroll to the top and hide the address bar
+ window.scrollTo(0, 0);
+
+ // Initialize fixed position elements only after the page is loaded,
+ // to workaround layout issues with fixed position on mobile devices
+ setTimeout(function() {
+ map(function(e) {
+ e.style.position = 'fixed';
+ return e;
+ }, ui.elementsByClassName(document, 'fixed'));
+ }, 0);
+ return true;
+};
/**
* Navigate to a new document.
*/
ui.navigate = function(url, win) {
- log('navigate', url, win);
+ //log('navigate', url, win);
// Open a new window
if (win == '_blank')
@@ -283,17 +326,11 @@ ui.menufunc = function(name, fun, hilight) {
};
ui.menubar = function(left, right) {
- var bar = '<table cellpadding="0" cellspacing="0" width="100%" class="tbar"><tr>' +
- '<td class="dtbar"><table border="0" cellspacing="0" cellpadding="0"><tr>';
+ var bar = '';
for (i in left)
- bar = bar + '<td class="ltbar">' + left[i].content() + '</td>'
-
- bar = bar + '</tr></table></td>' +
- '<td class="dtbar"><table border="0" cellpadding="0" cellspacing="0" align="right"><tr>';
+ bar = bar + '<span class="tbarleft">' + left[i].content() + '</span>';
for (i in right)
- bar = bar + '<td class="' + (i == 0? 'dtbar' : 'rtbar') + '">' + right[i].content() + '</td>'
-
- bar = bar + '</tr></table></td></tr></table>';
+ bar = bar + '<span class="tbarright">' + right[i].content() + '</span>';
return bar;
};
@@ -379,105 +416,3 @@ ui.datalist = function(l) {
return '<table class="datatable ' + (window.name == 'dataFrame'? ' databg' : '') + '" style="width: 100%;">' + rows(l, 0) + '</table>';
}
-/**
- * Autocomplete / suggest support for input fields
- * To use it declare a 'suggest' function as follows:
- * function suggestItems() {
- * return new Array('abc', 'def', 'ghi');
- * }
- * then hook it to an input field as follows:
- * suggest(document.yourForm.yourInputField, suggestItems);
- */
-ui.selectSuggestion = function(node, value) {
- for (;;) {
- node = node.parentNode;
- if (node.tagName.toLowerCase() == 'div')
- break;
- }
- node.selectSuggestion(value);
-};
-
-ui.hilightSuggestion = function(node, over) {
- if (over)
- node.className = 'suggestHilighted';
- node.className = 'suggestItem';
-};
-
-ui.suggest = function(input, suggestFunction) {
- input.suggest = suggestFunction;
-
- input.selectSuggestion = function(value) {
- this.hideSuggestDiv();
- this.value = value;
- }
-
- input.hideSuggestDiv = function() {
- if (this.suggestDiv != null) {
- this.suggestDiv.style.visibility = 'hidden';
- }
- }
-
- input.showSuggestDiv = function() {
- if (this.suggestDiv == null) {
- this.suggestDiv = document.createElement('div');
- this.suggestDiv.input = this;
- this.suggestDiv.className = 'suggest';
- input.parentNode.insertBefore(this.suggestDiv, input);
- this.suggestDiv.style.visibility = 'hidden';
- this.suggestDiv.style.zIndex = '99';
-
- this.suggestDiv.selectSuggestion = function(value) {
- this.input.selectSuggestion(value);
- }
- }
-
- var values = this.suggest();
- var items = '';
- for (var i = 0; i < values.length; i++) {
- if (values[i].indexOf(this.value) == -1)
- continue;
- if (items.length == 0)
- items += '<table class="suggestTable">';
- items += '<tr><td class="suggestItem" ' +
- 'onmouseover="ui.hilightSuggestion(this, true)" onmouseout="ui.hilightSuggestion(this, false)" ' +
- 'onmousedown="ui.selectSuggestion(this, \'' + values[i] + '\')">' + values[i] + '</td></tr>';
- }
- if (items.length != 0)
- items += '</table>';
- this.suggestDiv.innerHTML = items;
-
- if (items.length != 0) {
- var node = input;
- var left = 0;
- var top = 0;
- for (;;) {
- left += node.offsetLeft;
- top += node.offsetTop;
- node = node.offsetParent;
- if (node.tagName.toLowerCase() == 'body')
- break;
- }
- this.suggestDiv.style.left = left;
- this.suggestDiv.style.top = top + input.offsetHeight;
- this.suggestDiv.style.visibility = 'visible';
- } else
- this.suggestDiv.style.visibility = 'hidden';
- }
-
- input.onkeydown = function(event) {
- this.showSuggestDiv();
- };
-
- input.onkeyup = function(event) {
- this.showSuggestDiv();
- };
-
- input.onmousedown = function(event) {
- this.showSuggestDiv();
- };
-
- input.onblur = function(event) {
- setTimeout(function() { input.hideSuggestDiv(); }, 50);
- };
-};
-
diff --git a/sca-cpp/trunk/modules/js/htdocs/util.js b/sca-cpp/trunk/modules/js/htdocs/util.js
index 677132d2a8..0f7de94289 100644
--- a/sca-cpp/trunk/modules/js/htdocs/util.js
+++ b/sca-cpp/trunk/modules/js/htdocs/util.js
@@ -170,11 +170,11 @@ function tokens(path) {
}
/**
- * Log a value.
+ * Debug log a value.
*/
var rconsole;
-function log(v) {
+function debug(v) {
try {
var s = '';
for (i = 0; i < arguments.length; i++) {
@@ -196,13 +196,13 @@ function log(v) {
}
/**
- * Dump an object to the debug console.
+ * Dump an object to the console.
*/
-function debug(o) {
+function dump(o) {
try {
for (f in o) {
try {
- log('debug ' + f + '=' + o[f]);
+ debug('dump ' + f + '=' + o[f]);
} catch (e) {}
}
} catch (e) {}
@@ -302,6 +302,51 @@ function unmemo(obj) {
}
/**
+ * Local storage.
+ */
+var lstorage = {};
+lstorage.enabled = true;
+
+/**
+ * Get an item.
+ */
+lstorage.getItem = function(k) {
+ if (!lstorage.enabled)
+ return null;
+ try {
+ return localStorage.getItem(k);
+ } catch(e) {
+ return null;
+ }
+}
+
+/**
+ * Set an item.
+ */
+lstorage.setItem = function(k, v) {
+ if (!lstorage.enabled)
+ return null;
+ try {
+ return localStorage.setItem(k, v);
+ } catch(e) {
+ return null;
+ }
+}
+
+/**
+ * Remove an item.
+ */
+lstorage.removeItem = function(k) {
+ if (!lstorage.enabled)
+ return null;
+ try {
+ return localStorage.removeItem(k);
+ } catch(e) {
+ return null;
+ }
+}
+
+/**
* Returns a list of the properties of an object.
*/
function properties(o) {