diff options
Diffstat (limited to '')
30 files changed, 1775 insertions, 1007 deletions
diff --git a/sca-cpp/trunk/modules/edit/htdocs/account/index.html b/sca-cpp/trunk/modules/edit/htdocs/account/index.html index d83ca4562b..ef1deb0527 100644 --- a/sca-cpp/trunk/modules/edit/htdocs/account/index.html +++ b/sca-cpp/trunk/modules/edit/htdocs/account/index.html @@ -17,7 +17,7 @@ * specific language governing permissions and limitations * under the License. --> -<html> +<html manifest="/cache-manifest.cmf"> <head> <title>Account</title> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0"/> @@ -28,8 +28,8 @@ <script type="text/javascript" src="/all-min.js"></script> <script type="text/javascript" src="/menu.js"></script> </head> -<body class="delayed" onload="ui.onload();"> -<div id="bodydiv" class="devicewidth"> +<body class="delayed" onload="ui.onload();" onbeforeunload="ui.onbeforeunload();"> +<div id="bodydiv" class="bodydiv"> <div id="headdiv" class="hsection"> <script type="text/javascript" src="/headconfig.js"></script> @@ -97,13 +97,18 @@ </form> <script type="text/javascript"> +ui.initbody(); + // Init service references var editWidget = sca.component("EditWidget"); var user= sca.defun(sca.reference(editWidget, "user"), "id"); var accounts = sca.reference(editWidget, "accounts"); // Get the user name -var username = user.id() +var username = ''; +try { + username = user.id() +} catch(e) {} // Set page titles document.title = windowtitle(window.location.hostname) + ' - Account - ' + username; @@ -123,6 +128,11 @@ var savedaccountentryxml = ''; */ function getaccount(name) { return accounts.get(name, function(doc) { + + // Stop now if we didn't get an account + if (doc == null) + return false; + accountentry = doc != null? car(elementsToValues(atom.readATOMEntry(mklist(doc)))) : mklist("'entry", mklist("'title", ''), mklist("'id", name)); var title = cadr(assoc("'title", cdr(accountentry))); $('userTitle').value = title; @@ -162,8 +172,10 @@ function getaccount(name) { function save(entryxml) { $('saveStatus').innerHTML = 'Saving'; savedaccountentryxml = entryxml; - accounts.put(username, savedaccountentryxml); - $('saveStatus').innerHTML = 'Saved'; + accounts.put(username, savedaccountentryxml, function(e) { + if (!e) + $('saveStatus').innerHTML = 'Saved'; + }); return true; } diff --git a/sca-cpp/trunk/modules/edit/htdocs/app/cache-manifest.cmf.off b/sca-cpp/trunk/modules/edit/htdocs/app/cache-manifest.cmf index 58371aa6b5..1d9464bea6 100644 --- a/sca-cpp/trunk/modules/edit/htdocs/app/cache-manifest.cmf.off +++ b/sca-cpp/trunk/modules/edit/htdocs/app/cache-manifest.cmf @@ -6,7 +6,6 @@ CACHE MANIFEST # App resources / -/app.html /data/index.html /favicon.ico /footconfig.js diff --git a/sca-cpp/trunk/modules/edit/htdocs/app/frame.html b/sca-cpp/trunk/modules/edit/htdocs/app/frame.html index 7e313d2138..3509e1e190 100644 --- a/sca-cpp/trunk/modules/edit/htdocs/app/frame.html +++ b/sca-cpp/trunk/modules/edit/htdocs/app/frame.html @@ -17,7 +17,7 @@ * specific language governing permissions and limitations * under the License. --> -<html> +<html manifest="/cache-manifest.cmf"> <head> <title></title> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0"/> diff --git a/sca-cpp/trunk/modules/edit/htdocs/app/index.html b/sca-cpp/trunk/modules/edit/htdocs/app/index.html index 8d0a3f7153..f62cc5d0eb 100644 --- a/sca-cpp/trunk/modules/edit/htdocs/app/index.html +++ b/sca-cpp/trunk/modules/edit/htdocs/app/index.html @@ -17,7 +17,7 @@ * specific language governing permissions and limitations * under the License. --> -<html> +<html manifest="/cache-manifest.cmf"> <head> <title></title> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0"/> @@ -30,8 +30,8 @@ document.title = window.location.hostname.split('.')[0]; <link rel="stylesheet" type="text/css" href="/ui-min.css"/> <script type="text/javascript" src="/all-min.js"></script> </head> -<body class="delayed" onload="ui.onload();"> -<div id="bodydiv" class="devicewidth"> +<body class="delayed" onload="ui.onload();" onbeforeunload="ui.onbeforeunload();"> +<div id="bodydiv" class="bodydiv"> <div id="headdiv" class="hsection"> <script type="text/javascript" src="/headconfig.js"></script> @@ -45,6 +45,8 @@ document.title = window.location.hostname.split('.')[0]; </div> <script type="text/javascript"> +ui.initbody(); + /** * The main app div. */ @@ -120,49 +122,123 @@ function inputvalue(e) { */ function setwidgetvalue(e, dv) { var htattrs = namedElementChild("'htattrs", dv); - var attrs = append(isNil(htattrs)? mklist() : - map(function(ce) { return mklist(elementName(ce).substring(1), elementHasValue(ce)? elementValue(ce) : elementChildren(ce)); }, elementChildren(htattrs)), - elementHasValue(dv)? mklist(mklist('value', isNil(elementValue(dv))? '' : elementValue(dv))) : mklist()); + + function attr(ce) { + return mklist(elementName(ce) == "'htstyle"? 'style' : elementName(ce).substring(1), elementHasValue(ce)? elementValue(ce) : elementChildren(ce)); + } + + function vattr(dv) { + return (elementHasValue(dv) && !isNil(elementValue(dv)))? mklist(mklist('value', isNil(elementValue(dv))? '' : elementValue(dv))) : mklist(); + } + + function sattr(dv) { + var s = namedElementChild("'htstyle", dv); + return isNil(s)? mklist() : mklist(mklist('style', elementHasValue(s)? elementValue(s) : elementChildren(s))) + } + + var attrs = append(append(isNil(htattrs)? mklist() : map(attr, elementChildren(htattrs)), vattr(dv)), sattr(dv)); + + // Set the attributes of the widget + function setattrs(vsetter, attrs, ce) { + return map(function(a) { + if (car(a) == 'value') + return vsetter(a, ce); + + if (car(a) == 'style') { + // Split a style property between a style attribute + // and a stylesheet definition in the document's head + + function prop(s) { + if (s == ';') + return ''; + var i = s.indexOf('<style>'); + if (i == -1) + return s; + var j = s.indexOf('</style>'); + return s.substring(0, i) + prop(s.substring(j + 8)); + } + + function sheet(s) { + var i = s.indexOf('<style>'); + if (i == -1) + return ''; + var j = s.indexOf('</style>'); + return s.substring(i + 7, j) + sheet(s.substring(j + 8)); + } + + var st = cadr(a).replace(new RegExp('{id}', 'g'), e.id); + var p = prop(st); + var s = sheet(st); + + // Define the stylesheet + if (s != '') { + var esheet = appframe.contentDocument.getElementById('style_' + e.id); + if (isNil(esheet)) { + var nesheet = document.createElement('style'); + nesheet.id = 'style_' + e.id; + nesheet.type = 'text/css'; + appframe.contentDocument.getElementsByTagName('head')[0].appendChild(nesheet); + nesheet.innerHTML = s; + } else { + esheet.innerHTML = s; + } + } + + var aname = ce.style.webkitAnimationName; + + // Set the style attribute + ce.setAttribute('style', p); + + // Restart current animation if necessary + if (!isNil(aname) && ce.style.webkitAnimationName == aname) { + ce.style.webkitAnimationName = ''; + setTimeout(function() { + ce.style.webkitAnimationName = aname; + }, 0); + } + return a; + } + + ce.setAttribute(car(a), cadr(a)); + return a; + }, attrs); + } if (e.className == 'h1' || e.className == 'h2' || e.className == 'text' || e.className == 'section') { var ce = car(childElements(e)); - return map(function(a) { car(a) == 'value'? ce.innerHTML = cadr(a) : ce.setAttribute(car(a), cadr(a)); }, attrs); + return setattrs(function(a, ce) { ce.innerHTML = cadr(a); }, attrs, ce); } - if (e.className == 'entry' || e.className == 'password') { var ce = car(childElements(e)); - return map(function(a) { car(a) == 'value'? ce.defaultValue = cadr(a) : ce.setAttribute(car(a), cadr(a)); }, attrs); + return setattrs(function(a, ce) { ce.defaultValue = cadr(a); }, attrs, ce); } - if (e.className == 'button') { var ce = car(childElements(e)); - return map(function(a) { car(a) == 'value'? ce.value = cadr(a) : ce.setAttribute(car(a), cadr(a)); }, attrs); + return setattrs(function(a, ce) { ce.value = cadr(a); }, attrs, ce); } - if (e.className == 'checkbox') { var ce = car(childElements(e)); - function setcheckvalue(ce, v) { + function setcheckvalue(a, ce) { + var v = cadr(a); ce.value = v; map(function(n) { if (n.nodeName == "SPAN") n.innerHTML = v; return n; }, nodeList(e.childNodes)); return true; } - var r = map(function(a) { car(a) == 'value'? setcheckvalue(ce, cadr(a)) : ce.setAttribute(car(a), cadr(a)); }, attrs); - return r; + return setattrs(setcheckvalue, attrs, ce); } - if (e.className == 'select') { var ce = car(childElements(car(childElements(e)))); - function setselectvalue(ce, v) { + function setselectvalue(a, ce) { + var v = cadr(a); ce.value = v; ce.innerHTML = v; return true; } - var r = map(function(a) { car(a) == 'value'? setselectvalue(ce, cadr(a)) : ce.setAttribute(car(a), cadr(a)); }, attrs); - return r; + return setattrs(setselectvalue, attrs, ce); } if (e.className == 'list') { var dl = ui.datalist(isNil(dv)? mklist() : mklist(dv)); @@ -177,7 +253,8 @@ function setwidgetvalue(e, dv) { if (e.className == 'link') { var ce = car(childElements(e)); - function setlinkvalue(ce, v) { + function setlinkvalue(a, ce) { + var v = cadr(a); if (isList(v)) { ce.href = car(v); ce.innerHTML = cadr(v); @@ -188,15 +265,15 @@ function setwidgetvalue(e, dv) { return true; } - return map(function(a) { car(a) == 'value'? setlinkvalue(ce, cadr(a)) : ce.setAttribute(car(a), cadr(a)); }, attrs); + return setattrs(setlinkvalue, attrs, ce); } if (e.className == 'img') { var ce = car(childElements(e)); - return map(function(a) { car(a) == 'value'? ce.setAttribute('src', cadr(a)) : ce.setAttribute(car(a), cadr(a)); }, attrs); + return setattrs(function(a, ce) { ce.setAttribute('src', cadr(a)); }, attrs, ce); } if (e.className == 'iframe') { var ce = car(childElements(e)); - return map(function(a) { car(a) == 'value'? ce.setAttribute('src', cadr(a)) : ce.setAttribute(car(a), cadr(a)); }, attrs); + return setattrs(function(a, ce) { ce.setAttribute('src', cadr(a)); }, attrs, ce); } return ''; }; @@ -250,6 +327,19 @@ function bindwidgethandler(e) { b.onclick = function() { return buttonClickHandler(b.value); }; return e; } + if (e.className == 'link') { + var l = car(childElements(e)); + var hr = l.href; + if (hr.substring(0, 5) == 'link:' && hr.indexOf('://') == -1) { + var f = function(e) { + e.preventDefault(); + return buttonClickHandler(hr.substring(5)); + }; + l.ontouchstart = l.onclick = f; + l.href = 'javascript:void()'; + } + return e; + } if (e.className == 'entry' || e.className == 'password' || e.className == 'checkbox') { car(childElements(e)).name = e.id; return e; @@ -266,13 +356,40 @@ function bindwidgethandler(e) { * Initial fixup of a widget. */ function fixupwidget(e) { - if (e.className == 'iframe') { - var f = car(childElements(e)); - e.innerHTML = '<iframe src="' + f.href + '" frameborder="no" scrolling="no"></iframe>'; + if (e.className == 'h1' || e.className == 'h2' || e.className == 'text' || e.className == 'section') { + if (e.className == 'section') + e.style.width = '100%'; + var ce = car(childElements(e)); + if (ce.innerHTML == '=' + e.id) + ce.innerHTML = ''; return e; } - if (e.className == 'section') { - e.style.width = '100%'; + if (e.className == 'entry' || e.className == 'password') { + var ce = car(childElements(e)); + if (ce.defaultValue == '=' + e.id) + ce.defaultValue = ''; + return e; + } + if (e.className == 'button') { + var ce = car(childElements(e)); + if (ce.value == '=' + e.id) + ce.value = ''; + return e; + } + if (e.className == 'checkbox') { + var ce = car(childElements(e)); + if (ce.value == '=' + e.id) { + ce.value = ''; + map(function(n) { if (n.nodeName == "SPAN") n.innerHTML = ''; return n; }, nodeList(e.childNodes)); + } + return e; + } + if (e.className == 'select') { + var ce = car(childElements(car(childElements(e)))); + if (ce.value == '=' + e.id) { + ce.value = ''; + ce.innerHTML = ''; + } return e; } if (e.className == 'list') { @@ -287,6 +404,21 @@ function fixupwidget(e) { car(childElements(e)).style.width = '100%'; return e; } + if (e.className == 'link') { + var ce = car(childElements(e)); + if (ce.innerHTML == '=' + e.id) + ce.innerHTML = ''; + return e; + } + if (e.className == 'img') { + var ce = car(childElements(e)); + return e; + } + if (e.className == 'iframe') { + var ce = car(childElements(e)); + e.innerHTML = '<iframe src="' + ce.href + '" frameborder="no" scrolling="no"></iframe>'; + return e; + } return e; } @@ -304,7 +436,7 @@ function initwidget(e) { */ function getdoc(comp, name, uri) { try { - return comp.get(uri); + return comp.getnocache(uri); } catch(e) { log('exception on get(' + name + ', ' + uri + ')', e); return null; diff --git a/sca-cpp/trunk/modules/edit/htdocs/clone/index.html b/sca-cpp/trunk/modules/edit/htdocs/clone/index.html index 5e3922a28e..29ebe1ce06 100644 --- a/sca-cpp/trunk/modules/edit/htdocs/clone/index.html +++ b/sca-cpp/trunk/modules/edit/htdocs/clone/index.html @@ -17,7 +17,7 @@ * specific language governing permissions and limitations * under the License. --> -<html> +<html manifest="/cache-manifest.cmf"> <head> <title></title> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0"/> @@ -28,8 +28,8 @@ <script type="text/javascript" src="/all-min.js"></script> <script type="text/javascript" src="/menu.js"></script> </head> -<body class="delayed" onload="ui.onload();"> -<div id="bodydiv" class="devicewidth"> +<body class="delayed" onload="ui.onload();" onbeforeunload="ui.onbeforeunload();"> +<div id="bodydiv" class="bodydiv"> <div id="headdiv" class="hsection"> <script type="text/javascript" src="/headconfig.js"></script> @@ -62,15 +62,17 @@ <tr><tr><td style="padding-top: 6px;"><b>Description:</b></td></tr> <tr><td><textarea id="appDescription" 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="greenbutton" style="font-weight: bold;" value="Clone" title="Clone the app"/> -<input id="cloneAppCancelButton" type="button" class="redbutton" value="Cancel"/> +<input id="cloneAppOKButton" type="submit" class="graybutton" style="font-weight: bold;" value="Clone" title="Clone the app"/> +<input id="cloneAppCancelButton" type="button" class="graybutton" value="Cancel"/> </td></tr> </table> </form> <script type="text/javascript"> +ui.initbody(); + // Get the app name -var appname = ui.queryParams()['app']; +var appname = ui.fragmentParams()['app']; if (isNil(appname)) window.open('/', '_self'); @@ -90,8 +92,7 @@ function applink(appname) { // Set page titles var tclone = isNil(config.clone)? 'Clone' : config.clone; document.title = windowtitle(window.location.hostname) + ' - ' + tclone + ' - ' + appname; -//$('h1').innerHTML = hometitle(window.location.hostname); -$('appNameHeader').innerHTML = '<a href=\"' + applink(appname) + '\" target=\"' + '_blank' + '\">' + appname + '.' + window.location.hostname + '</a>'; +$('appNameHeader').innerHTML = '<a href=\"' + applink(appname) + '\" target=\"' + '_blank' + '\">' + appname + '</a>'; $('th').innerHTML = tclone + ' this App'; $('cloneAppOKButton').value = tclone; $('cloneAppOKButton').title = tclone + ' this app'; @@ -120,6 +121,11 @@ function getapp(name) { if (isNil(name)) return false; return apps.get(name, function(doc) { + + // Stop now if we didn't get the app + if (doc == null) + return false; + appentry = doc != null? car(elementsToValues(atom.readATOMEntry(mklist(doc)))) : mklist("'entry", mklist("'title", ''), mklist("'id", name)); var title = cadr(assoc("'title", cdr(appentry))); $('appTitle').value = title; @@ -141,10 +147,14 @@ $('cloneAppForm').onsubmit = function() { var title = $('appTitle').value; var app = mklist(mklist("'entry", mklist("'title", title != ''? title : name), mklist("'id", appname))); var entry = atom.writeATOMEntry(valuesToElements(app)); - dashboards.put(name, car(entry)); + dashboards.put(name, car(entry), function(e) { + if (e) + return false; - // Open it in the page editor - window.open('/page/?app=' + name, '_self'); + // Open it in the page editor + ui.navigate('/page/#app=' + name, '_self'); + return false; + }); return false; }; @@ -152,7 +162,7 @@ $('cloneAppForm').onsubmit = function() { * Cancel cloning an app. */ $('cloneAppCancelButton').onclick = function() { - window.open('/stats/?app=' + appname, '_self'); + ui.navigate('/stats/#app=' + appname, '_self'); }; // Get the current app diff --git a/sca-cpp/trunk/modules/edit/htdocs/create/index.html b/sca-cpp/trunk/modules/edit/htdocs/create/index.html index bf8f71f7e9..575016aeb8 100644 --- a/sca-cpp/trunk/modules/edit/htdocs/create/index.html +++ b/sca-cpp/trunk/modules/edit/htdocs/create/index.html @@ -17,7 +17,7 @@ * specific language governing permissions and limitations * under the License. --> -<html> +<html manifest="/cache-manifest.cmf"> <head> <title>Create App</title> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0"/> @@ -28,8 +28,8 @@ <script type="text/javascript" src="/all-min.js"></script> <script type="text/javascript" src="/menu.js"></script> </head> -<body class="delayed" onload="ui.onload();"> -<div id="bodydiv" class="devicewidth"> +<body class="delayed" onload="ui.onload();" onbeforeunload="ui.onbeforeunload();"> +<div id="bodydiv" class="bodydiv"> <div id="headdiv" class="hsection"> <script type="text/javascript" src="/headconfig.js"></script> @@ -60,13 +60,15 @@ <tr><tr><td style="padding-top: 6px;"><b>Description:</b></td></tr> <tr><td><textarea id="appDescription" 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="greenbutton" style="font-weight: bold;" value="Create" title="Create the app"/> -<input id="createAppCancelButton" type="button" class="redbutton" value="Cancel"/> +<input id="createAppOKButton" type="submit" class="graybutton" style="font-weight: bold;" value="Create" title="Create the app"/> +<input id="createAppCancelButton" type="button" class="graybutton" value="Cancel"/> </td></tr> </table> </form> <script type="text/javascript"> +ui.initbody(); + // Set page titles document.title = windowtitle(window.location.hostname) + ' - Create App'; $('h1').innerHTML = hometitle(window.location.hostname); @@ -94,10 +96,14 @@ $('createAppForm').onsubmit = function() { var title = $('appTitle').value; var app = mklist(mklist("'entry", mklist("'title", title != ''? title : name), mklist("'id", 'new'))); var entry = atom.writeATOMEntry(valuesToElements(app)); - dashboards.put(name, car(entry)); + dashboards.put(name, car(entry), function(e) { + if (e) + return false; - // Open it in the page editor - window.open('/page/?app=' + name, '_self'); + // Open it in the page editor + ui.navigate('/page/#app=' + name, '_self'); + return false; + }); return false; }; @@ -105,7 +111,7 @@ $('createAppForm').onsubmit = function() { * Cancel creating an app. */ $('createAppCancelButton').onclick = function() { - return window.open('/store/', '_self'); + return ui.navigate('/store/', '_self'); }; </script> diff --git a/sca-cpp/trunk/modules/edit/htdocs/data/index.html b/sca-cpp/trunk/modules/edit/htdocs/data/index.html index 1f583adc3b..23b8668ce4 100644 --- a/sca-cpp/trunk/modules/edit/htdocs/data/index.html +++ b/sca-cpp/trunk/modules/edit/htdocs/data/index.html @@ -17,7 +17,7 @@ * specific language governing permissions and limitations * under the License. --> -<html> +<html manifest="/cache-manifest.cmf"> <head> <title>View</title> <script type="text/javascript"> @@ -31,7 +31,7 @@ document.title = 'View - ' + window.location.hostname.split('.')[0] + '/' + cn; <link rel="stylesheet" type="text/css" href="/ui-min.css"> <script type="text/javascript" src="/all-min.js"></script> </head> -<body class="delayed" onload="ui.onload();"> +<body class="delayed" onload="ui.onload();" onbeforeunload="ui.onbeforeunload();"> <div id="bodydiv" style="position: absolute; top: 0px; left: 0px; right: 0px;"> <div id="compLinkHeader" style="margin-top: 4px; margin-bottom: 4px;"></div> @@ -39,8 +39,10 @@ document.title = 'View - ' + window.location.hostname.split('.')[0] + '/' + cn; </div> <script type="text/javascript"> +ui.initbody(); + // Get the component name -var cname = ui.queryParams()['component']; +var cname = ui.fragmentParams()['component']; /** * The current component. @@ -74,7 +76,12 @@ function mkdoctable(doc) { * Get and display the contents of the current component. */ function getdata() { - return comp.get('', function(doc) { + return comp.getnocache('', function(doc) { + + // Stop now if we didn't the doc + if (doc == null) + return false; + if (json.isJSON(mklist(doc))) return display(datatable(json.readJSON(mklist(doc)))); diff --git a/sca-cpp/trunk/modules/edit/htdocs/graph/graph.js b/sca-cpp/trunk/modules/edit/htdocs/graph/graph.js index 2ef53fa54a..d459a4b021 100644 --- a/sca-cpp/trunk/modules/edit/htdocs/graph/graph.js +++ b/sca-cpp/trunk/modules/edit/htdocs/graph/graph.js @@ -18,7 +18,7 @@ */ /** - * SVG and VML composite rendering functions. + * SVG composite rendering functions. */ var graph = {}; @@ -40,18 +40,39 @@ graph.colors.purple = '#800080'; graph.colors.red = '#ff0000'; graph.colors.white = '#ffffff'; graph.colors.yellow = '#ffff00'; - graph.colors.link = '#598edd'; -graph.colors.orange1 = '#ffbb00'; -graph.colors.green1 = '#96d333'; -//graph.colors.blue1 = '#00c3c9'; -graph.colors.blue1 = '#0d7cc1'; +graph.colors.orange1 = '#ffd666'; +graph.colors.green1 = '#bbe082'; +graph.colors.blue1 = '#66dbdf'; +graph.colors.yellow1 = '#fdf57a'; +graph.colors.cyan1 = '#e6eafb'; +graph.colors.lightgray1 = '#eaeaea' +graph.colors.pink1 = '#ffd9e0'; graph.colors.red1 = '#d03f41'; -graph.colors.yellow1 = '#fcee21'; -graph.colors.magenta1 = '#c0688a'; -graph.colors.cyan1 = '#d5dcf9'; -graph.colors.lightgray1 = '#dcdcdc' +graph.colors.white1 = '#ffffff'; + +graph.colors.orange2 = '#ffbb00'; +graph.colors.green2 = '#96d333'; +//graph.colors.blue2 = '#0d7cc1'; +graph.colors.blue2 = '#00c3c9'; +graph.colors.red2 = '#d03f41'; +graph.colors.yellow2 = '#fcee21'; +graph.colors.magenta2 = '#c0688a'; +graph.colors.cyan2 = '#d5dcf9'; +graph.colors.lightgray2 = '#dcdcdc' +graph.colors.pink2 = '#ffc0cb'; +graph.colors.white2 = '#ffffff'; + +graph.colors.orange3 = '#ffc700'; +graph.colors.green3 = '#92e120'; +graph.colors.blue3 = '#008fd1'; +graph.colors.yellow3 = '#fdf400'; +graph.colors.cyan3 = '#b4d3fd'; +graph.colors.lightgray3 = '#e3e3e3' +graph.colors.pink3 = '#da749b'; +graph.colors.red3 = '#ed3f48'; +graph.colors.white3 = '#ffffff'; /** * Default positions and sizes. @@ -59,50 +80,14 @@ graph.colors.lightgray1 = '#dcdcdc' var palcx = 2500; var proxcx = 20; var proxcy = 20; -var buttoncx = 65; -var buttoncy = 30; -var curvsz = 6; +var buttoncx = 55; +var buttoncy = 23; +var curvsz = 4; var tabsz = 2; -var fontsz = '11px'; - -/** - * Base path class. - */ -graph.BasePath = function() { - this.path = ''; - this.x = 0; - this.y = 0; - - this.pos = function(x, y) { - this.x = x; - this.y = y; - return this; - }; - - this.xpos = function() { - return this.x; - }; - - this.ypos = function() { - return this.y; - }; - - this.rmove = function(x, y) { - return this.move(this.x + x, this.y + y); - }; - - this.rline = function(x, y) { - return this.line(this.x + x, this.y + y); - }; - - this.rcurve = function(x1, y1, x, y) { - return this.curve(this.x + x1, this.y + y1, this.x + x1 + x, this.y + y1 + y); - }; - - this.str = function() { - return this.path; - }; -}; +var titlex = 4; +var titley = 11; +var titlesp = 3; +var titlew = ui.isMobile()? -2 : 0; /** * SVG rendering functions. @@ -113,7 +98,7 @@ graph.svgns='http://www.w3.org/2000/svg'; /** * Make an SVG graph. */ -graph.mkgraph = function(cdiv, pos, cvalue, cadd, cdelete) { +graph.mkgraph = function(cdiv, pos, cvalue, cadd, ccopy, cdelete) { // Create a div element to host the graph var div = document.createElement('div'); @@ -121,7 +106,7 @@ graph.mkgraph = function(cdiv, pos, cvalue, cadd, cdelete) { div.style.position = 'absolute'; div.style.left = ui.pixpos(pos.xpos() + cdiv.offsetLeft); div.style.top = ui.pixpos(pos.ypos() + cdiv.offsetTop); - div.style.overflow = 'hidden'; + //div.style.overflow = 'hidden'; cdiv.appendChild(div); // Create SVG element @@ -132,8 +117,11 @@ graph.mkgraph = function(cdiv, pos, cvalue, cadd, cdelete) { // Track element dragging and selection graph.dragging = null; + graph.dragged = false; + graph.moverenderer = null; graph.selected = null; cvalue.disabled = true; + ccopy.disabled = true; cdelete.disabled = true; /** @@ -148,50 +136,87 @@ graph.mkgraph = function(cdiv, pos, cvalue, cadd, cdelete) { } /** - * Handle a mouse down event. + * Handle a mouse down or touch start event. */ - div.onmousedown = function(e) { + function onmousedown(e) { + + // Remember mouse or touch position + var pos = typeof e.touches != "undefined" ? e.touches[0] : e; + graph.downX = pos.screenX; + graph.downY = pos.screenY; + graph.moveX = pos.screenX; + graph.moveY = pos.screenY; - // On mouse controlled devices, engage the click component selection - // logic right away + // Engage the click component selection right away + // on mouse controlled devices if (typeof e.touches == 'undefined') - div.onclick(e); + onclick(e); - // Find draggable component + // Find and remember draggable component var dragging = draggable(e.target); if (dragging == null || dragging != graph.selected) return true; graph.dragging = dragging; + graph.dragged = false; - // Remember current mouse position - var pos = typeof e.touches != "undefined" ? e.touches[0] : e; + // Remember current drag position graph.dragX = pos.screenX; graph.dragY = pos.screenY; - if (e.preventDefault) - e.preventDefault(); - else - e.returnValue = false; + e.preventDefault(); return true; }; - // Support touch devices - div.ontouchstart = div.onmousedown; + if (!ui.isMobile()) { + div.onmousedown = function(e) { + //log('onmousedown'); + var suspend = svg.suspendRedraw(10); + var r = onmousedown(e); + svg.unsuspendRedraw(suspend); + return r; + } + } else { + div.ontouchstart = function(e) { + //log('ontouchstart'); + + // Clear current move renderer if it's running + if (!isNil(graph.moverenderer)) { + clearInterval(graph.moverenderer); + graph.moverenderer = null; + } + + var suspend = svg.suspendRedraw(10); + var r = onmousedown(e); + svg.unsuspendRedraw(suspend); + return r; + } + } /** - * Handle a mouse up event. + * Handle a mouse up or touch end event. */ - div.onmouseup = function(e) { + function onmouseup(e) { + + // Engage the click component selection now on touch devices + if (ui.isMobile()) { + if (!graph.dragged && graph.moveX == graph.downX && graph.moveY == graph.downY) + return onclick(e); + } + + // Stop here if the component was not dragged if (graph.dragging == null) return true; + if (!graph.dragged) { + graph.dragging = null; + return true; + } if (graph.dragging.parentNode == svg && graph.dragging.id.substring(0, 8) != 'palette:') { - var gpos = graph.relpos(graph.dragging); // Add new dragged component to the composite if (isNil(graph.dragging.compos)) { var compos = scdl.composite(svg.compos); - setElement(compos, graph.sortcompos(graph.addcomp(graph.dragging.comp, compos))); + setElement(compos, graph.sortcompos(graph.addcomps(mklist(graph.dragging.comp), compos))); graph.dragging.compos = svg.compos; } @@ -207,34 +232,62 @@ graph.mkgraph = function(cdiv, pos, cvalue, cadd, cdelete) { // Snap top level component position to grid if (graph.dragging.parentNode == svg) { var gpos = graph.relpos(graph.dragging); - graph.move(graph.dragging, graph.mkpath().move(graph.gridsnap(gpos.xpos()), graph.gridsnap(gpos.ypos()))); - setElement(graph.dragging.comp, graph.movecomp(graph.dragging.comp, graph.abspos(graph.dragging, svg))); + setElement(graph.dragging.comp, graph.movecomp(graph.dragging.comp, graph.mkpath().pos(graph.gridsnap(gpos.xpos()), graph.gridsnap(gpos.ypos())))); } } // Forget current dragged component graph.dragging = null; + graph.dragged = false; // Refresh the composite + //log('onmouseup refresh'); var nodes = graph.refresh(svg); // Reselected the previously selected component - graph.selected = graph.findcompnode(scdl.name(graph.selected.comp), nodes); - graph.compselect(graph.selected, true, cvalue, cdelete); + if (!isNil(graph.selected)) { + graph.selected = graph.findcompnode(scdl.name(graph.selected.comp), nodes); + graph.compselect(graph.selected, true, cvalue, ccopy, cdelete); - // Trigger component select event - svg.oncompselect(graph.selected); + // Trigger component select event + svg.oncompselect(graph.selected); + } // Trigger composite change event svg.oncomposchange(false); return true; }; - // Support touch devices - div.ontouchend = div.onmouseup; + if (!ui.isMobile()) { + div.onmouseup = function(e) { + //log('onmouseup'); + var suspend = svg.suspendRedraw(10); + var r = onmouseup(e); + svg.unsuspendRedraw(suspend); + return r; + } + } else { + div.ontouchend = function(e) { + //log('ontouchend'); + + // Clear current move renderer if it's running + if (!isNil(graph.moverenderer)) { + clearInterval(graph.moverenderer); + graph.moverenderer = null; + } - // Handle a mouse click event. - div.onclick = svg.onclick = function(e) { + var suspend = svg.suspendRedraw(10); + var r = onmouseup(e); + svg.unsuspendRedraw(suspend); + return r; + } + } + + /** + * Handle a mouse or touch click event. + */ + function onclick(e) { + //log('onclick logic'); // Find selected component var selected = draggable(e.target); @@ -242,7 +295,7 @@ graph.mkgraph = function(cdiv, pos, cvalue, cadd, cdelete) { if (graph.selected != null) { // Reset current selection - graph.compselect(graph.selected, false, cvalue, cdelete); + graph.compselect(graph.selected, false, cvalue, ccopy, cdelete); graph.selected = null; // Trigger component select event @@ -263,29 +316,24 @@ graph.mkgraph = function(cdiv, pos, cvalue, cadd, cdelete) { return true; // Deselect previously selected component - graph.compselect(graph.selected, false, cvalue, cdelete); + graph.compselect(graph.selected, false, cvalue, ccopy, cdelete); // Clone component from the palette if (selected.id.substring(0, 8) == 'palette:') { var compos = scdl.composite(svg.compos); - graph.selected = graph.clonepalette(selected, compos, svg); - setElement(compos, graph.sortcompos(graph.addcomp(graph.selected.comp, compos))); - graph.selected.compos = svg.compos; + var comp = graph.clonepalette(selected, compos, svg); + setElement(compos, graph.sortcompos(graph.addcomps(mklist(comp), compos))); // Move into the editing area and hide the palette - var gpos = graph.relpos(graph.selected); - graph.move(graph.selected, graph.mkpath().move(gpos.xpos() + palcx, gpos.ypos())); div.style.left = ui.pixpos(palcx * -1); - // Update component position - setElement(graph.selected.comp, graph.movecomp(graph.selected.comp, graph.abspos(graph.selected, svg))); - // Refresh the composite + //log('onclick refresh'); var nodes = graph.refresh(svg); // Reselect the previously selected component - graph.selected = graph.findcompnode(scdl.name(graph.selected.comp), nodes); - graph.compselect(graph.selected, true, cvalue, cdelete); + graph.selected = graph.findcompnode(scdl.name(comp), nodes); + graph.compselect(graph.selected, true, cvalue, ccopy, cdelete); // Trigger component select event svg.oncompselect(graph.selected); @@ -297,12 +345,14 @@ graph.mkgraph = function(cdiv, pos, cvalue, cadd, cdelete) { graph.selected = selected; // Select the component - graph.compselect(graph.selected, true, cvalue, cdelete); + graph.compselect(graph.selected, true, cvalue, ccopy, cdelete); // Trigger component select event svg.oncompselect(graph.selected); } + //log('comp selected'); + if (e.preventDefault) e.preventDefault(); else @@ -310,18 +360,37 @@ graph.mkgraph = function(cdiv, pos, cvalue, cadd, cdelete) { return true; } + if (!ui.isMobile()) { + div.onclick = function(e) { + //log('div onclick'); + var suspend = svg.suspendRedraw(10); + var r = onclick(e); + svg.unsuspendRedraw(suspend); + return r; + } + svg.onclick = function(e) { + //log('svg onclick'); + var suspend = svg.suspendRedraw(10); + var r = onclick(e); + svg.unsuspendRedraw(suspend); + return r; + } + } + /** - * Handle a mouse move event. + * Handle a mouse or touch move event. */ - window.onmousemove = function(e) { + function onmousemove(e) { if (graph.dragging == null) return true; - // Get the mouse position - var pos = typeof e.touches != "undefined" ? e.touches[0] : e; - if (pos.screenX == graph.dragX && pos.screenY == graph.dragY) + // 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 != svg) { var compos = scdl.composite(svg.compos); @@ -333,30 +402,68 @@ graph.mkgraph = function(cdiv, pos, cvalue, cadd, cdelete) { // Calculate new position of dragged element var gpos = graph.relpos(graph.dragging); - var newX = gpos.xpos() + (pos.screenX - graph.dragX); - var newY = gpos.ypos() + (pos.screenY - graph.dragY); + var newX = gpos.xpos() + (graph.moveX - graph.dragX); + var newY = gpos.ypos() + (graph.moveY - graph.dragY); if (newX >= palcx) - graph.dragX = pos.screenX; + graph.dragX = graph.moveX else newX = palcx; if (newY >= 0) - graph.dragY = pos.screenY; + graph.dragY = graph.moveY; else newY = 0; + // Detach child elements to speedup rendering + graph.compoutline(graph.dragging, true); + // Move the dragged element - graph.move(graph.dragging, graph.mkpath().move(newX, newY)); + graph.move(graph.dragging, graph.mkpath().pos(newX, newY)); - return true; + return false; }; - // Support touch devices - div.ontouchmove = window.onmousemove; + if (!ui.isMobile()) { + window.onmousemove = function(e) { + //log('onmousemove'); + + // Remember mouse position + graph.moveX = e.screenX; + graph.moveY = e.screenY; + + var suspend = svg.suspendRedraw(10); + var r = onmousemove(e); + svg.unsuspendRedraw(suspend); + return r; + } + } else { + div.ontouchmove = function(e) { + //log('ontouchmove'); + + // Remember 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) + return true; + + // Start async move renderer + if (graph.moverenderer == null) { + graph.moverenderer = setInterval(function() { + var suspend = svg.suspendRedraw(10); + onmousemove(e); + svg.unsuspendRedraw(suspend); + }, 10); + } + return true; + } + } /** * Handle field on change events. */ - cvalue.onchange = function() { + function onvaluechange() { if (graph.selected == null) return false; if (g.parentNode.style.visibility == 'hidden') @@ -370,11 +477,12 @@ graph.mkgraph = function(cdiv, pos, cvalue, cadd, cdelete) { setElement(compos, graph.sortcompos(graph.renamecomp(graph.selected.comp, compos, cvalue.value))); // Refresh the composite + //log('onchangename refresh'); var nodes = graph.refresh(svg); // Reselected the previously selected component graph.selected = graph.findcompnode(scdl.name(graph.selected.comp), nodes); - graph.compselect(graph.selected, true, cvalue, cdelete); + graph.compselect(graph.selected, true, cvalue, ccopy, cdelete); // Trigger component select event svg.oncompselect(graph.selected); @@ -391,11 +499,12 @@ graph.mkgraph = function(cdiv, pos, cvalue, cadd, cdelete) { cvalue.disabled = !graph.hasproperty(graph.selected.comp); // Refresh the composite + //log('onchangeprop refresh'); var nodes = graph.refresh(svg); // Reselected the previously selected component graph.selected = graph.findcompnode(scdl.name(graph.selected.comp), nodes); - graph.compselect(graph.selected, true, cvalue, cdelete); + graph.compselect(graph.selected, true, cvalue, ccopy, cdelete); // Trigger component select event svg.oncompselect(graph.selected); @@ -407,9 +516,16 @@ graph.mkgraph = function(cdiv, pos, cvalue, cadd, cdelete) { return graph.hasproperty(graph.selected.comp)? changeprop() : changename(); }; + + cvalue.onchange = function() { + var suspend = svg.suspendRedraw(10); + var r = onvaluechange(); + svg.unsuspendRedraw(suspend); + return r; + } // Handle delete event - cdelete.onclick = function() { + function ondeleteclick() { if (graph.selected == null) return false; if (graph.selected.id.substring(0, 8) != 'palette:') { @@ -421,10 +537,11 @@ graph.mkgraph = function(cdiv, pos, cvalue, cadd, cdelete) { setElement(compos, graph.sortcompos(graph.clonerefs(graph.gcollect(graph.removecomp(graph.selected.comp, compos))))); // Reset current selection - graph.compselect(graph.selected, false, cvalue, cdelete); + graph.compselect(graph.selected, false, cvalue, ccopy, cdelete); graph.selected = null; // Refresh the composite + //log('ondelete refresh'); graph.refresh(svg); // Trigger component select event @@ -436,6 +553,49 @@ graph.mkgraph = function(cdiv, pos, cvalue, cadd, cdelete) { return false; }; + cdelete.onclick = function() { + var suspend = svg.suspendRedraw(10); + var r = ondeleteclick(); + svg.unsuspendRedraw(suspend); + return r; + }; + + // Handle copy event + function oncopyclick() { + if (graph.selected == null) + return false; + if (graph.selected.id.substring(0, 8) == 'palette:') + return false; + + // Clone the selected component + var compos = scdl.composite(svg.compos); + var comps = graph.clonecomp(graph.selected, compos, svg); + setElement(compos, graph.sortcompos(graph.addcomps(comps, compos))); + + // Refresh the composite + //log('onclick refresh'); + var nodes = graph.refresh(svg); + + // Select the component clone + graph.selected = graph.findcompnode(scdl.name(car(comps)), nodes); + graph.compselect(graph.selected, true, cvalue, ccopy, cdelete); + + // Trigger component select event + svg.oncompselect(graph.selected); + + // Trigger composite change event + svg.oncomposchange(true); + + return false; + }; + + ccopy.onclick = function() { + var suspend = svg.suspendRedraw(10); + var r = oncopyclick(); + svg.unsuspendRedraw(suspend); + return r; + }; + // Handle add event cadd.onclick = function() { @@ -446,65 +606,99 @@ graph.mkgraph = function(cdiv, pos, cvalue, cadd, cdelete) { // Create a hidden SVG element to help compute the width // of component and reference titles - graph.titlewidthsvg = document.createElementNS(graph.svgns, 'svg'); - graph.titlewidthsvg.style.visibility = 'hidden'; - graph.titlewidthsvg.style.height = ui.pixpos(0); - graph.titlewidthsvg.style.width = ui.pixpos(0); - div.appendChild(graph.titlewidthsvg); + graph.svgtitles = document.createElementNS(graph.svgns, 'svg'); + graph.svgtitles.style.visibility = 'hidden'; + graph.svgtitles.style.height = ui.pixpos(0); + graph.svgtitles.style.width = ui.pixpos(0); + div.appendChild(graph.svgtitles); return svg; }; /** - * Make a path. + * Point class. */ -graph.mkpath = function() { - function Path() { - this.BasePath = graph.BasePath; - this.BasePath(); - - this.clone = function() { - return graph.mkpath().pos(this.xpos(), this.ypos()); - }; - - this.move = function(x, y) { - this.path += 'M' + x + ',' + y + ' '; - return this.pos(x, y); - }; - - this.line = function(x, y) { - this.path += 'L' + x + ',' + y + ' '; - return this.pos(x, y); - }; - - this.curve = function(x1, y1, x, y) { - this.path += 'Q' + x1 + ',' + y1 + ' ' + x + ',' + y + ' '; - return this.pos(x, y); - }; - - this.end = function() { - this.path += 'Z'; - return this; - }; - } +graph.Point = function(x, y) { + this.x = x; + this.y = y; +}; +graph.Point.prototype.xpos = function() { + return this.x; +}; +graph.Point.prototype.ypos = function() { + return this.y; +}; - return new Path(); +graph.mkpoint = function(x, y) { + return new graph.Point(x, y); +}; + +/** + * Path class. + */ +graph.Path = function() { + this.path = ''; + this.x = 0; + this.y = 0; +} +graph.Path.prototype.pos = function(x, y) { + this.x = x; + this.y = y; + return this; +}; +graph.Path.prototype.xpos = function() { + return this.x; +}; +graph.Path.prototype.ypos = function() { + return this.y; +}; +graph.Path.prototype.rmove = function(x, y) { + return this.move(this.x + x, this.y + y); +}; +graph.Path.prototype.rline = function(x, y) { + return this.line(this.x + x, this.y + y); +}; +graph.Path.prototype.rcurve = function(x1, y1, x, y) { + return this.curve(this.x + x1, this.y + y1, this.x + x1 + x, this.y + y1 + y); +}; +graph.Path.prototype.str = function() { + return this.path; +}; +graph.Path.prototype.clone = function() { + return graph.mkpath().pos(this.xpos(), this.ypos()); +}; +graph.Path.prototype.move = function(x, y) { + this.path += 'M' + x + ',' + y + ' '; + return this.pos(x, y); +}; +graph.Path.prototype.line = function(x, y) { + this.path += 'L' + x + ',' + y + ' '; + return this.pos(x, y); +}; +graph.Path.prototype.curve = function(x1, y1, x, y) { + this.path += 'Q' + x1 + ',' + y1 + ' ' + x + ',' + y + ' '; + return this.pos(x, y); +}; +graph.Path.prototype.end = function() { + this.path += 'Z'; + return this; +}; + +graph.mkpath = function() { + return new graph.Path(); }; /** * Return an element representing a title. */ -graph.mktitle = function(t, style) { +graph.mktitle = function(t, x, y) { var title = document.createElementNS(graph.svgns, 'text'); - title.setAttribute('x', 5); - title.setAttribute('y', 15); - title.setAttribute('text-anchor', 'start'); - if (style != '') - title.style.cssText = style; - if (fontsz != '') - title.style.fontSize = fontsz; - title.style.cursor = 'default'; + title.setAttribute('x', x); + title.setAttribute('y', y); + title.setAttribute('class', 'svgtitle'); + title.setAttribute('pointer-events', 'none'); title.appendChild(document.createTextNode(t)); + graph.svgtitles.appendChild(title); return title; }; @@ -512,7 +706,13 @@ graph.mktitle = function(t, style) { * Return an element representing the title of a component. */ graph.comptitle = function(comp) { - return graph.mktitle(graph.title(comp), graph.compstyle(comp)); + return memo(comp, 'title', function() { + var ct = graph.title(comp); + var pt = graph.propertytitle(comp); + if (ct == '' && pt == '') + return null; + return graph.mktitle((ct != '' && pt != '')? ct + ' ' + pt : ct + pt, titlex, titley); + }); }; /** @@ -520,78 +720,81 @@ graph.comptitle = function(comp) { */ graph.comptitlewidth = function(comp) { var title = graph.comptitle(comp); - graph.titlewidthsvg.appendChild(title); - var width = title.getBBox().width + 2; - graph.titlewidthsvg.removeChild(title); - return width; + if (isNil(title)) + return 0; + return title.getBBox().width + titlew; }; /** - * Return an element representing the title of a reference. + * Draw a component shape selection. */ -graph.reftitle = function(ref) { - return graph.mktitle(graph.title(ref), graph.refstyle(ref)); -}; +graph.compselect = function(g, s, cvalue, ccopy, cdelete) { + if (isNil(g) || !s) { + cvalue.value = ''; + cvalue.disabled = true; + ccopy.disabled = true; + cdelete.disabled = true; + if (isNil(g)) + return true; + g.shape.setAttribute('stroke', graph.colors.gray); + g.shape.setAttribute('stroke-width', '1'); + return true; + } -/** - * Return the width of the title of a reference. - */ -graph.reftitlewidth = function(ref) { - var title = graph.reftitle(ref); - graph.titlewidthsvg.appendChild(title); - var width = title.getBBox().width; - graph.titlewidthsvg.removeChild(title); - return width; -}; + cvalue.value = graph.hasproperty(g.comp)? graph.property(g.comp) : g.id; + cvalue.disabled = false; + ccopy.disabled = false; + cdelete.disabled = false; -/** - * Return an element representing the value of a property. - */ -graph.proptitle = function(comp) { - var title = graph.mktitle(graph.propertytitle(comp), graph.propstyle(comp)); - title.setAttribute('x', graph.comptitlewidth(comp) + 7); - return title; + g.shape.setAttribute('stroke', graph.colors.link); + g.shape.setAttribute('stroke-width', '2'); + g.parentNode.appendChild(g); + return true; }; /** - * Return the width of the title of a property. + * Draw a palette shape selection. */ -graph.proptitlewidth = function(comp) { - var title = graph.proptitle(comp); - graph.titlewidthsvg.appendChild(title); - var width = title.getBBox().width + 4; - graph.titlewidthsvg.removeChild(title); - return width; +graph.paletteselect = function(g, s) { + if (isNil(g)) + return true; + if (!s) { + g.shape.setAttribute('stroke', graph.colors.gray); + g.shape.setAttribute('stroke-width', '1'); + return true; + } + + g.shape.setAttribute('stroke', graph.colors.link); + g.shape.setAttribute('stroke-width', '2'); + g.parentNode.appendChild(g); + return true; }; /** - * Draw a component shape selection. + * Draw a component outline for faster rendering. */ -graph.compselect = function(g, s, cvalue, cdelete) { - if (isNil(g) || !s) { - if (!isNil(cvalue)) { - cvalue.value = ''; - cvalue.disabled = true; - } - if (!isNil(cdelete)) - cdelete.disabled = true; - if (isNil(g)) - return true; - g.contour.setAttribute('stroke', graph.colors.gray); - g.contour.setAttribute('stroke-opacity', '0.20'); +graph.compoutline = function(g, s) { + if (s == (isNil(g.outlined)? false : g.outlined)) return true; - } + g.outlined = s; - if (!isNil(cvalue)) { - cvalue.value = graph.hasproperty(g.comp)? graph.property(g.comp) : g.id; - cvalue.disabled = false; + if (s) { + g.shape.setAttribute('fill', 'none'); + if (!isNil(g.title)) + g.removeChild(g.title); + } else { + g.shape.setAttribute('fill', graph.color(g.comp)); + if (!isNil(g.title)) + g.appendChild(g.title); } - if (!isNil(cdelete)) - cdelete.disabled = false; - g.contour.setAttribute('stroke', graph.colors.link); - g.contour.setAttribute('stroke-opacity', '0.80'); - g.parentNode.appendChild(g); + map(function(r) { + var n = caddr(r); + if (isNil(n)) + return r; + graph.compoutline(n, s); + return r; + }, g.refpos); return true; }; @@ -600,47 +803,38 @@ graph.compselect = function(g, s, cvalue, cdelete) { */ graph.compnode = function(comp, cassoc, pos, parentg) { - // Make the component and property title elements + // Make the component title element var title = graph.comptitle(comp); - var prop = graph.proptitle(comp); // Compute the path of the component shape var path = graph.comppath(comp, cassoc); - var d = path.str(); // Create the main component shape var shape = document.createElementNS(graph.svgns, 'path'); - shape.setAttribute('d', d); + shape.setAttribute('d', path.str()); shape.setAttribute('fill', graph.color(comp)); - shape.setAttribute('fill-opacity', '0.60'); - - // Create an overlay contour shape - var contour = document.createElementNS(graph.svgns, 'path'); - contour.setAttribute('d', d); - contour.setAttribute('fill', 'none'); - contour.setAttribute('stroke', graph.colors.gray); - contour.setAttribute('stroke-width', '3'); - contour.setAttribute('stroke-opacity', '0.20'); - contour.setAttribute('transform', 'translate(1,1)'); - - // Create a group and add the component and contour shapes to it. + //shape.setAttribute('fill-opacity', '0.6'); + shape.setAttribute('stroke', graph.colors.gray); + shape.setAttribute('stroke-width', '1'); + shape.setAttribute('pointer-events', 'visible'); + + // Create an svg group and add the shape and title to it var g = document.createElementNS(graph.svgns, 'g'); + g.comp = comp; g.id = scdl.name(comp); g.setAttribute('transform', 'translate(' + pos.xpos() + ',' + pos.ypos() + ')'); + g.pos = pos.clone(); g.appendChild(shape); - g.appendChild(contour); - g.appendChild(title); - g.appendChild(prop); + g.shape = shape; + if (!isNil(title)) { + g.appendChild(title); + g.title = title; + } - // Store the component and the positions of its services - // and references in the component shape - g.comp = comp; + // Store the the positions of the services and references g.refpos = reverse(path.refpos); g.svcpos = reverse(path.svcpos); - // Store the contour in the component shape - g.contour = contour; - // Handle onclick events g.onclick = parentg.onclick; @@ -669,6 +863,7 @@ graph.findcompnode = function(name, nodes) { graph.mkgroup = function(pos) { var g = document.createElementNS(graph.svgns, 'g'); g.setAttribute('transform', 'translate(' + pos.xpos() + ',' + pos.ypos() + ')'); + g.pos = pos.clone(); return g; }; @@ -678,7 +873,7 @@ graph.mkgroup = function(pos) { graph.mkbutton = function(t, pos) { // Make the button title - var title = graph.mktitle(t, ''); + var title = graph.mktitle(t, titlex, titley); // Compute the path of the button shape var path = graph.buttonpath().str(); @@ -686,27 +881,21 @@ graph.mkbutton = function(t, pos) { // Create the main button shape var shape = document.createElementNS(graph.svgns, 'path'); shape.setAttribute('d', path); - shape.setAttribute('fill', graph.colors.lightgray); - shape.setAttribute('fill-opacity', '0.60'); - - // Create an overlay contour shape - var contour = document.createElementNS(graph.svgns, 'path'); - contour.setAttribute('d', path); - contour.setAttribute('fill', 'none'); - contour.setAttribute('stroke', graph.colors.gray); - contour.setAttribute('stroke-width', '3'); - contour.setAttribute('stroke-opacity', '0.20'); - contour.setAttribute('transform', 'translate(1,1)'); - - // Create a group and add the button and contour shapes to it + shape.setAttribute('fill', graph.colors.lightgray1); + //shape.setAttribute('fill-opacity', '0.6'); + shape.setAttribute('stroke', graph.colors.gray); + shape.setAttribute('stroke-width', '1'); + shape.setAttribute('pointer-events', 'visible'); + + // Create a group and add the button shape to it var g = document.createElementNS(graph.svgns, 'g'); g.setAttribute('transform', 'translate(' + pos.xpos() + ',' + pos.ypos() + ')'); + g.pos = pos.clone(); g.appendChild(shape); - g.appendChild(contour); g.appendChild(title); - // Store the contour in the button shape - g.contour = contour; + // Store the button shape in the group + g.shape = shape; return g; }; @@ -719,7 +908,7 @@ graph.relpos = function(e) { var matrix = e.getCTM(); var curX = pmatrix != null? (Number(matrix.e) - Number(pmatrix.e)): Number(matrix.e); var curY = pmatrix != null? (Number(matrix.f) - Number(pmatrix.f)): Number(matrix.f); - return graph.mkpath().move(curX, curY); + return graph.mkpath().pos(curX, curY); }; /** @@ -727,6 +916,7 @@ graph.relpos = function(e) { */ graph.move = function(e, pos) { e.setAttribute('transform', 'translate(' + pos.xpos() + ',' + pos.ypos() + ')'); + e.pos = pos.clone(); }; /** @@ -737,7 +927,7 @@ graph.abspos = function(e, g) { return graph.mkpath(); var gpos = graph.relpos(e); var pgpos = graph.abspos(e.parentNode, g); - return graph.mkpath().move(gpos.xpos() + pgpos.xpos(), gpos.ypos() + pgpos.ypos()); + return graph.mkpath().pos(gpos.xpos() + pgpos.xpos(), gpos.ypos() + pgpos.ypos()); }; /** @@ -770,14 +960,6 @@ graph.title = function(e) { }; /** - * Return the display style of an SCDL component or reference. - */ -graph.compstyle = graph.refstyle = function(e) { - var s = scdl.style(e); - return isNil(s)? '' : s; -}; - -/** * Return the property value of a SCDL component. */ graph.property = function(e) { @@ -814,19 +996,6 @@ graph.hasproperty = function(e) { }; /** - * Return the display style of the property of an SCDL component. - */ -graph.propstyle = function(e) { - var p = scdl.properties(e); - if (isNil(p)) - return ''; - if (scdl.visible(car(p)) == 'false') - return ''; - var s = scdl.style(car(p)); - return isNil(s)? '' : s; -}; - -/** * Change the property value of a SCDL component. */ graph.setproperty = function(e, value) { @@ -851,19 +1020,6 @@ graph.color = function(comp) { }; /** - * Return the services on the top side of a component. - */ -graph.tsvcs = function(comp) { - return memo(comp, 'tsvcs', function() { - var svcs = scdl.services(comp); - var l = filter(function(s) { return scdl.align(s) == 'top' && scdl.visible(s) != 'false'; }, svcs); - if (isNil(l)) - return mklist(); - return mklist(car(l)); - }); -}; - -/** * Return the services on the left side of a component. */ graph.lsvcs = function(comp) { @@ -878,22 +1034,11 @@ graph.lsvcs = function(comp) { }, svcs); if (isNil(l)) return mklist(); - if (!isNil(graph.tsvcs(comp))) - return mklist(); return mklist(car(l)); }); }; /** - * Return the references on the bottom side of a component. - */ -graph.brefs = function(comp) { - return memo(comp, 'brefs', function() { - return filter(function(r) { return scdl.align(r) == 'bottom' && scdl.visible(r) != 'false'; }, scdl.references(comp)); - }); -}; - -/** * Return the references on the right side of a component. */ graph.rrefs = function(comp) { @@ -913,19 +1058,7 @@ graph.rrefheight = function(ref, cassoc) { return memo(ref, 'rheight', function() { var target = assoc(scdl.target(ref), cassoc); if (isNil(target)) - return tabsz * 10; - return graph.compclosureheight(cadr(target), cassoc); - }); -}; - -/** - * Return the height of a reference on the bottom side of a component. - */ -graph.brefheight = function(ref, cassoc) { - return memo(ref, 'bheight', function() { - var target = assoc(scdl.target(ref), cassoc); - if (isNil(target)) - return 0; + return tabsz * 8; return graph.compclosureheight(cadr(target), cassoc); }); }; @@ -940,27 +1073,15 @@ graph.rrefsheight = function(refs, cassoc) { }; /** - * Return the max height of the references on the bottom side of a component. - */ -graph.brefsheight = function(refs, cassoc) { - if (isNil(refs)) - return 0; - return Math.max(graph.brefheight(car(refs), cassoc), graph.brefsheight(cdr(refs), cassoc)); -}; - -/** * Return the height of a component node. */ graph.compheight = function(comp, cassoc) { return memo(comp, 'height', function() { var lsvcs = graph.lsvcs(comp); - var lsvcsh = Math.max(1, length(lsvcs)) * (tabsz * 10) + (tabsz * 4); + var lsvcsh = Math.max(1, length(lsvcs)) * (tabsz * 8) + (tabsz * 4); var rrefs = graph.rrefs(comp); - var rrefsh = graph.rrefsheight(rrefs, cassoc) + (tabsz * 4); - var height = Math.max(lsvcsh, rrefsh); - if (!isNil(graph.brefs(comp))) - height = Math.max(height, (tabsz * 10) + (tabsz * 4) + (tabsz * 2)); - return height; + var rrefsh = graph.rrefsheight(rrefs, cassoc) + (tabsz * 2); + return Math.max(lsvcsh, rrefsh); }); }; @@ -969,40 +1090,17 @@ graph.compheight = function(comp, cassoc) { */ graph.compclosureheight = function(comp, cassoc) { return memo(comp, 'closureheight', function() { - var brefs = graph.brefs(comp); - var height = graph.compheight(comp, cassoc) + graph.brefsheight(brefs, cassoc); - return height; + return graph.compheight(comp, cassoc); }); }; /** - * Return the width of a reference on the bottom side of a component. - */ -graph.brefwidth = function(ref, cassoc) { - return memo(ref, 'width', function() { - var target = assoc(scdl.target(ref), cassoc); - if (isNil(target)) - return tabsz * 10; - return graph.compclosurewidth(cadr(target), cassoc); - }); -}; - -/** - * Return the total width of the references on the bottom side of a component. - */ -graph.brefswidth = function(refs, cassoc) { - if (isNil(refs)) - return 0; - return graph.brefwidth(car(refs), cassoc) + graph.brefswidth(cdr(refs), cassoc); -}; - -/** * Return the max width of the references on the right side of a component. */ graph.rrefswidth = function(refs, cassoc) { if (isNil(refs)) return 0; - return Math.max(graph.brefwidth(car(refs), cassoc), graph.rrefswidth(cdr(refs), cassoc)); + return Math.max(graph.rrefwidth(car(refs), cassoc), graph.rrefswidth(cdr(refs), cassoc)); }; /** @@ -1010,23 +1108,10 @@ graph.rrefswidth = function(refs, cassoc) { */ graph.compwidth = function(comp, cassoc) { return memo(comp, 'width', function() { - var twidth = graph.comptitlewidth(comp) + graph.proptitlewidth(comp) + (tabsz * 8); - var tsvcs = graph.tsvcs(comp); - var tsvcsw = Math.max(1, length(tsvcs)) * (tabsz * 10) + (tabsz * 4); - var brefs = graph.brefs(comp); - var brefsw = graph.brefswidth(brefs, cassoc) + (tabsz * 4); - var width = Math.max(twidth, Math.max(tsvcsw, brefsw)); - return width; - }); -}; - -/** - * Return the width of a component and all the components wired to its right side. - */ -graph.compclosurewidth = function(comp, cassoc) { - return memo(comp, 'closurewidth', function() { - var rrefs = graph.rrefs(comp); - var width = graph.compwidth(comp, cassoc) + graph.rrefswidth(rrefs, cassoc); + var ctw = graph.comptitlewidth(comp); + var rrefsw = (isNil(graph.rrefs(comp))? 0 : (tabsz * 4)); + var twidth = (titlex * 2) + ctw + rrefsw; + var width = Math.max(twidth, (tabsz * 8) + (tabsz * 4)); return width; }); }; @@ -1034,62 +1119,31 @@ graph.compclosurewidth = function(comp, cassoc) { /** * Return a path representing a reference positioned to the right of a component. */ -graph.rrefpath = function(ref, cassoc, path) { +graph.rrefpath = function(ref, cassoc, path, maxheight) { var height = graph.rrefheight(ref, cassoc); // Record reference position in the path var xpos = path.xpos(); var ypos = path.ypos(); - //path.refpos = cons(mklist(ref, graph.mkpath().move(xpos, ypos + (tabsz * 6))), path.refpos); - path.refpos = cons(mklist(ref, graph.mkpath().move(xpos, ypos + (tabsz * 5))), path.refpos); - - // Compute the reference path - return path.rline(0,tabsz).rline(0,tabsz * 2).rcurve(0,tabsz,-tabsz,0).rcurve(-tabsz,0,0,-tabsz).rcurve(0,-tabsz,-tabsz,0).rcurve(-tabsz,0,0,tabsz).rline(0,tabsz * 4).rcurve(0,tabsz,tabsz,0).rcurve(tabsz,0,0,-tabsz).rcurve(0,-tabsz,tabsz,0).rcurve(tabsz,0,0,tabsz).line(path.xpos(),ypos + height); -}; - -/** - * Return a path representing a reference positioned at the bottom of a component. - */ -graph.brefpath = function(ref, cassoc, path) { - var width = graph.brefwidth(ref, cassoc); - - // Record reference position in the path - var xpos = path.xpos(); - var ypos = path.ypos(); - path.refpos = cons(mklist(ref, graph.mkpath().move(xpos - width + tabsz * 5, ypos)), path.refpos); + path.refpos = cons(mklist(ref, graph.mkpath().pos(xpos, ypos + (tabsz * 5))), path.refpos); // Compute the reference path - return path.line(xpos - width + (tabsz * 10),path.ypos()).rline(-tabsz,0).rline(-(tabsz *2),0).rcurve(-tabsz,0,0,-tabsz).rcurve(0,-tabsz,tabsz,0).rcurve(tabsz,0,0,-tabsz).rcurve(0,-tabsz,-tabsz,0).rline(-(tabsz * 4),0).rcurve(-tabsz,0,0,tabsz).rcurve(0,tabsz,tabsz,0).rcurve(tabsz,0,0,tabsz).rcurve(0,tabsz,-tabsz,0).line(xpos - width,path.ypos()); + return path.rline(0,tabsz * 2).rcurve(0,tabsz,-tabsz,0).rcurve(-tabsz,0,0,-tabsz/2.0).rcurve(0,-tabsz/2.0,-tabsz,0).rcurve(-tabsz,0,0,tabsz/2.0).rline(0,tabsz * 3).rcurve(0,tabsz/2.0,tabsz,0).rcurve(tabsz,0,0,-tabsz/2.0).rcurve(0,-tabsz/2.0,tabsz,0).rcurve(tabsz,0,0,tabsz).line(path.xpos(), Math.min(ypos + height, maxheight)); }; /** * Return a path representing a service positioned to the left of a component. */ -graph.lsvcpath = function(svc, cassoc, path) { - var height = tabsz * 10; - - // Record service position in the path - var xpos = path.xpos(); - var ypos = path.ypos(); - path.svcpos = cons(mklist(svc, graph.mkpath().move(xpos, ypos - (tabsz * 6))), path.svcpos); - - // Compute the service path - return path.rline(0,-tabsz).rline(0, -(tabsz * 2)).rcurve(0,-tabsz,-tabsz,0).rcurve(-tabsz,0,0,tabsz).rcurve(0,tabsz,-tabsz,0).rcurve(-tabsz,0,0,-tabsz).rline(0,-(tabsz * 4)).rcurve(0,-tabsz,tabsz,0).rcurve(tabsz,0,0,tabsz).rcurve(0,tabsz,tabsz,0).rcurve(tabsz,0,0,-tabsz).line(path.xpos(), ypos - height); -}; - -/** - * Return a path representing a service positioned at the top of a component. - */ -graph.tsvcpath = function(svc, cassoc, path) { - var width = tabsz * 10; +graph.lsvcpath = function(svc, cassoc, path, minheight) { + var height = tabsz * 8; // Record service position in the path var xpos = path.xpos(); var ypos = path.ypos(); - path.svcpos = cons(mklist(svc, graph.mkpath().move(xpos + (tabsz * 5), ypos)), path.svcpos); + path.svcpos = cons(mklist(svc, graph.mkpath().pos(xpos, ypos - (tabsz * 6))), path.svcpos); // Compute the service path - return path.rline(tabsz,0).rline(tabsz * 2,0).rcurve(tabsz,0,0,-tabsz).rcurve(0,-tabsz,-tabsz,0).rcurve(-tabsz,0,0,-tabsz).rcurve(0,-tabsz,tabsz,0).rline(tabsz * 4,0).rcurve(tabsz,0,0,tabsz).rcurve(0,tabsz,-tabsz,0).rcurve(-tabsz,0,0,tabsz).rcurve(0,tabsz,tabsz,0).line(xpos + width,path.ypos()); + return path.rline(0, -(tabsz * 2)).rcurve(0,-tabsz,-tabsz,0).rcurve(-tabsz,0,0,tabsz/2.0).rcurve(0,tabsz/2.0,-tabsz,0).rcurve(-tabsz,0,0,-tabsz/2.0).rline(0,-(tabsz * 3)).rcurve(0,-tabsz/2.0,tabsz,0).rcurve(tabsz,0,0,tabsz/2.0).rcurve(0,tabsz/2.0,tabsz,0).rcurve(tabsz,0,0,-tabsz).line(path.xpos(), Math.max(ypos - height, minheight)); }; /** @@ -1104,10 +1158,10 @@ graph.comppath = function(comp, cassoc) { /** * Apply a path rendering function to a list of services or references. */ - function renderpath(x, f, cassoc, path) { + function renderpath(x, f, cassoc, path, height) { if (isNil(x)) return path; - return renderpath(cdr(x), f, cassoc, f(car(x), cassoc, path)); + return renderpath(cdr(x), f, cassoc, f(car(x), cassoc, path, height), height); } var path = graph.mkpath().move(curvsz,0); @@ -1116,26 +1170,20 @@ graph.comppath = function(comp, cassoc) { path.refpos = mklist(); path.svcpos = mklist(); - // Render the services on the top side of the component - var tsvcs = graph.tsvcs(comp); - path = renderpath(tsvcs, graph.tsvcpath, cassoc, path); - // Render the references on the right side of the component var rrefs = graph.rrefs(comp); path = path.line(width - curvsz,path.ypos()).rcurve(curvsz,0,0,curvsz); - path = renderpath(rrefs, graph.rrefpath, cassoc, path); + path = renderpath(rrefs, graph.rrefpath, cassoc, path, height - curvsz); // Render the references on the bottom side of the component - var brefs = reverse(graph.brefs(comp)); - var boffset = curvsz + graph.brefswidth(brefs, cassoc); + var boffset = curvsz; path = path.line(path.xpos(),height - curvsz).rcurve(0,curvsz,curvsz * -1,0).line(boffset, path.ypos()); - path = renderpath(brefs, graph.brefpath, cassoc, path); // Render the services on the left side of the component var lsvcs = graph.lsvcs(comp); - var loffset = curvsz + (length(lsvcs) * (tabsz * 10)); + var loffset = curvsz + (length(lsvcs) * (tabsz * 8)); path = path.line(curvsz,path.ypos()).rcurve(curvsz * -1,0,0,curvsz * -1).line(path.xpos(), loffset); - path = renderpath(lsvcs, graph.lsvcpath, cassoc, path); + path = renderpath(lsvcs, graph.lsvcpath, cassoc, path, curvsz); // Close the component node path path = path.line(0,curvsz).rcurve(0,curvsz * -1,curvsz,0); @@ -1144,6 +1192,15 @@ graph.comppath = function(comp, cassoc) { }; /** + * Return the position of a component. + */ +graph.comppos = function(comp, pos) { + var x = scdl.x(comp); + var y = scdl.y(comp); + return graph.mkpath().pos(x != null? Number(x) + palcx : pos.xpos(), y != null? Number(y) : pos.ypos()); +}; + +/** * Return a path representing a button node. */ graph.buttonpath = function(t) { @@ -1209,38 +1266,6 @@ graph.composite = function(compos, pos, aspalette, g) { return cons(mklist(car(refs), grefcomp), renderrrefs(cdr(refs), cassoc, rendermove(car(refs), cassoc, pos), gcomp)); } - /** - * Render the references on the bottom side of a component. - */ - function renderbrefs(refs, cassoc, pos, gcomp) { - - /** - * Render a reference on the bottom side of a component. - */ - function renderbref(ref, cassoc, pos, gcomp) { - var target = assoc(scdl.target(ref), cassoc); - if (isNil(target)) - return null; - - // Render the component target of the reference - return rendercomp(cadr(target), cassoc, pos); - } - - /** - * Move the rendering cursor to the right of a reference. - */ - function rendermove(ref, cassoc, pos) { - return pos.clone().rmove(graph.brefwidth(ref, cassoc), 0); - } - - if (isNil(refs)) - return mklist(); - - // Return list of (ref, comp rendering) pairs - var grefcomp = renderbref(car(refs), cassoc, pos, gcomp); - return cons(mklist(car(refs), grefcomp), renderbrefs(cdr(refs), cassoc, rendermove(car(refs), cassoc, pos), gcomp)); - } - // Compute the component shape var gcomp = graph.compnode(comp, cassoc, pos, g); @@ -1249,10 +1274,6 @@ graph.composite = function(compos, pos, aspalette, g) { var rpos = graph.mkpath().rmove(graph.compwidth(comp, cassoc), 0); var grrefs = renderrrefs(rrefs, cassoc, rpos, gcomp); - var brefs = graph.brefs(comp); - var bpos = graph.mkpath().rmove(0 , graph.compheight(comp, cassoc)); - var gbrefs = renderbrefs(brefs, cassoc, bpos, gcomp); - // Store list of (ref, pos, component rendering) triplets in the component function refposgcomp(refpos, grefs) { if (isNil(refpos)) @@ -1261,11 +1282,11 @@ graph.composite = function(compos, pos, aspalette, g) { // Append component rendering to component var gref = cadr(car(grefs)); if (gref != null) - appendNodes(mklist(gref), gcomp); + gcomp.appendChild(gref); return cons(mklist(car(car(refpos)), cadr(car(refpos)), gref), refposgcomp(cdr(refpos), cdr(grefs))); } - gcomp.refpos = refposgcomp(gcomp.refpos, append(grrefs, gbrefs)); + gcomp.refpos = refposgcomp(gcomp.refpos, grrefs); return gcomp; } @@ -1286,17 +1307,6 @@ graph.composite = function(compos, pos, aspalette, g) { } /** - * Return the position of a component. - */ - function comppos(comp, pos) { - var x = scdl.x(comp); - var y = scdl.y(comp); - return graph.mkpath().move( - x != null? Number(x) + palcx : pos.xpos(), - y != null? Number(y) : (isNil(graph.tsvcs(comp))? pos.ypos() : pos.ypos() + (tabsz * 4))); - } - - /** * Move the rendering cursor down below a component. */ function rendermove(comp, cassoc, pos) { @@ -1312,7 +1322,7 @@ graph.composite = function(compos, pos, aspalette, g) { if (isNil(comp)) return renderproms(cdr(svcs), cassoc, rendermove(car(svcs), cassoc, pos)); - var cpos = comppos(comp, pos); + var cpos = graph.comppos(comp, pos); return cons(rendercomp(comp, cassoc, cpos), renderproms(cdr(svcs), cassoc, rendermove(comp, cassoc, cpos))); } @@ -1325,8 +1335,8 @@ graph.composite = function(compos, pos, aspalette, g) { // move them to the palette area return map(function(r) { r.id = 'palette:' + r.id; - var gpos = graph.relpos(r); - graph.move(r, graph.mkpath().move(gpos.xpos() - palcx, gpos.ypos())); + var gpos = r.pos; + graph.move(r, graph.mkpath().pos(gpos.xpos() - palcx, gpos.ypos())); return r; }, rproms); @@ -1340,10 +1350,10 @@ graph.composite = function(compos, pos, aspalette, g) { /** * Return a component unique id. */ -graph.ucid = function(prefix, compos, clone) { +graph.ucid = function(prefix, compos1, compos2, clone) { // Build an assoc list keyed by component name - var comps = map(function(c) { return mklist(scdl.name(c), c); }, namedElementChildren("'component", compos)); + var comps = map(function(c) { return mklist(scdl.name(c), c); }, append(namedElementChildren("'component", compos1), namedElementChildren("'component", compos2))); if (!clone && isNil(assoc(prefix, comps))) return prefix; @@ -1357,7 +1367,16 @@ graph.ucid = function(prefix, compos, clone) { return ucid(p, id + 1); } - return ucid(prefix == ''? 'comp' : prefix, 1); + /** + * Remove trailing digits from a prefix. + */ + function untrail(p) { + if (p.length < 2 || p[p.length - 1] < '0' || p[p.length - 1] > '9') + return p; + return untrail(p.substring(0, p.length - 1)); + } + + return ucid(prefix == ''? 'comp' : (clone? untrail(prefix) : prefix), 1); }; /** @@ -1365,19 +1384,17 @@ graph.ucid = function(prefix, compos, clone) { */ graph.clonepalette = function(e, compos, g) { - // Clone the SCDL component and give it a unique name - var wcomp = append(mklist(element, "'component", mklist(attribute, "'name", graph.ucid(scdl.name(e.comp), compos, true))), + // Clone the SCDL component and give it a unique name + var wcomp = append(mklist(element, "'component", mklist(attribute, "'name", graph.ucid(scdl.name(e.comp), compos, compos, true))), filter(function(c) { return !(isAttribute(c) && attributeName(c) == "'name")}, elementChildren(e.comp))); var x = '<composite>' + writeXML(mklist(wcomp), false) + '</composite>'; - var rcompos = readXML(mklist(x)); - var comp = car(scdl.components(rcompos)); + var rcompos = scdl.composite(readXML(mklist(x))); + var comp = car(scdl.components(mklist(rcompos))); - // Make a component node - var gcomp = graph.compnode(comp, mklist(), graph.mkpath(), g); - graph.move(gcomp, graph.relpos(e)); - e.parentNode.appendChild(gcomp); + // Update component position + setElement(comp, graph.movecomp(comp, graph.abspos(e, g).rmove(palcx, 0))); - return gcomp; + return comp; }; /** @@ -1399,6 +1416,54 @@ graph.gridsnap = function(x) { } /** + * Clone a component node and all the components it references. + */ +graph.clonecomp = function(e, compos, g) { + + // Write the component and the components it references to XML + function collectcomp(e) { + function collectrefs(refpos) { + if (isNil(refpos)) + return mklist(); + var r = car(refpos); + var n = caddr(r); + if (isNil(n)) + return collectrefs(cdr(refpos)); + return append(collectcomp(n), collectrefs(cdr(refpos))); + } + + return cons(e.comp, collectrefs(e.refpos)); + } + + var allcomps = collectcomp(e); + var ls = map(function(e) { return writeXML(mklist(e), false); }, allcomps); + var x = '<composite>' + writeStrings(ls) + '</composite>'; + + // Read them back from XML to clone them + var rcompos = scdl.composite(readXML(mklist(x))); + var comps = scdl.components(mklist(rcompos)); + + // Give them new unique names + map(function(e) { + + // Rename each component + var oname = scdl.name(e); + var name = graph.ucid(oname, compos, rcompos, true); + setElement(e, append(mklist(element, "'component", mklist(attribute, "'name", name)), + filter(function(c) { return !(isAttribute(c) && attributeName(c) == "'name")}, elementChildren(e)))); + + // Refactor references to the component + map(function(c) { return graph.refactorrefs(scdl.references(c), oname, name); }, comps); + }, comps); + + // Update the top component position + var comp = car(comps); + setElement(comp, graph.movecomp(comp, graph.abspos(e, g).rmove(10, 10))); + + return comps; +}; + +/** * Sort elements of a composite. */ graph.sortcompos = function(compos) { @@ -1431,12 +1496,14 @@ graph.sortcompos = function(compos) { } /** - * Add a component to a SCDL composite. + * Add a list of components to a SCDL composite. The first + * component in the list is a promoted component. */ -graph.addcomp = function(comp, compos) { +graph.addcomps = function(comps, compos) { + var comp = car(comps); var name = scdl.name(comp); var prom = mklist(element, "'service", mklist(attribute, "'name", name), mklist(attribute, "'promote", name)); - return append(mklist(element, "'composite"), append(elementChildren(compos), mklist(prom, comp))); + return append(mklist(element, "'composite"), append(elementChildren(compos), cons(prom, comps))); }; /** @@ -1495,31 +1562,31 @@ graph.clonerefs = function(compos) { } /** - * Rename a component. + * Refactor references to a component. */ -graph.renamecomp = function(comp, compos, name) { +graph.refactorrefs = function(refs, oname, nname) { + if (isNil(refs)) + return true; + var ref = car(refs); + if (scdl.target(ref) != oname) + return graph.refactorrefs(cdr(refs), oname, nname); - /** - * Refactor references to a component. - */ - function refactorrefs(refs, oname, nname) { - if (isNil(refs)) - return true; - var ref = car(refs); - if (scdl.target(ref) != oname) - return refactorrefs(cdr(refs), oname, nname); + // Change the reference's target attribute + setElement(ref, append(mklist(element, "'reference"), + append(filter(function(e) { return !(isAttribute(e) && attributeName(e) == "'target"); }, elementChildren(ref)), + mklist(mklist(attribute, "'target", nname))))); - // Change the reference's target attribute - setElement(ref, append(mklist(element, "'reference"), - append(filter(function(e) { return !(isAttribute(e) && attributeName(e) == "'target"); }, elementChildren(ref)), - mklist(mklist(attribute, "'target", nname))))); + return graph.refactorrefs(cdr(refs), oname, nname); +}; - return refactorrefs(cdr(refs), oname, nname); - } +/** + * Rename a component. + */ +graph.renamecomp = function(comp, compos, name) { // Refactor all the references to the renamed component var oname = scdl.name(comp); - map(function(c) { return refactorrefs(scdl.references(c), oname, name); }, namedElementChildren("'component", compos)); + map(function(c) { return graph.refactorrefs(scdl.references(c), oname, name); }, namedElementChildren("'component", compos)); // Rename the SCDL promoted service and component var proms = filter(function(s) { return scdl.name(s) == oname }, scdl.services(compos)); @@ -1645,10 +1712,13 @@ graph.wire = function(n, compos, g) { /** * Display a list of graphical nodes. */ -graph.display = function(nodes, g) { +graph.display = function(nodes, g, svg) { + var suspend = svg.suspendRedraw(10); // Append the nodes to the graphical canvas appendNodes(nodes, g); + + svg.unsuspendRedraw(suspend); return nodes; }; @@ -1666,12 +1736,15 @@ graph.hide = function(g) { * Refresh a graph. */ graph.refresh = function(g) { + //log('refresh'); // Remove existing nodes from the graph map(function(n) { if (!isNil(n.comp) && n.id.substr(0, 8) != 'palette:') { g.removeChild(n); } return n; }, nodeList(g.childNodes)); // Redisplay the composite associated with the graph - return graph.display(graph.composite(g.compos, graph.mkpath().move(palcx,0), false, g), g); + var nodes = graph.composite(g.compos, graph.mkpath().pos(palcx,0), false, g); + appendNodes(nodes, g); + return nodes; }; /** @@ -1679,6 +1752,7 @@ graph.refresh = function(g) { * nodes that represent it. */ graph.edit = function(appname, compos, nodes, onchange, onselect, g) { + var suspend = g.suspendRedraw(10); // Store the appname and composite in the graphical canvas g.appname = appname; @@ -1692,7 +1766,13 @@ graph.edit = function(appname, compos, nodes, onchange, onselect, g) { g.oncomposchange = onchange; g.oncompselect = onselect; + // Remove existing nodes from the graph + map(function(n) { if (!isNil(n.comp) && n.id.substr(0, 8) != 'palette:') { g.removeChild(n); } return n; }, nodeList(g.childNodes)); + // Display the composite nodes - return graph.display(nodes, g); + appendNodes(nodes, g); + + g.unsuspendRedraw(suspend); + return nodes; }; diff --git a/sca-cpp/trunk/modules/edit/htdocs/graph/index.html b/sca-cpp/trunk/modules/edit/htdocs/graph/index.html index aea21acf1e..6e93548814 100644 --- a/sca-cpp/trunk/modules/edit/htdocs/graph/index.html +++ b/sca-cpp/trunk/modules/edit/htdocs/graph/index.html @@ -17,7 +17,7 @@ * specific language governing permissions and limitations * under the License. --> -<html> +<html manifest="/cache-manifest.cmf"> <head> <title></title> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0"/> @@ -29,49 +29,65 @@ <script type="text/javascript" src="/menu.js"></script> <script type="text/javascript" src="graph.js"></script> </head> -<body class="delayed" onload="ui.onload();"> -<div id="bodydiv" class="devicewidth"> +<body class="delayed" onload="ui.onload();" onbeforeunload="ui.onbeforeunload();"> +<div id="bodydiv" class="bodydiv" style="overflow: visible;"> <div id="headdiv" class="hsection"> <script type="text/javascript" src="/headconfig.js"></script> </div> +<div id="menubackground" style="position: absolute; top: 0px; left: 0px; z-index: -1; width: 2500px;"> +<table cellpadding="0" cellspacing="0" width="100%" class="tbar"><tr><td class="dtbar"> +<table border="0" cellspacing="0" cellpadding="0"><tr><td class="ltbar"><span class="tbarsmenu">> </span></td></tr></table> +</td></tr></table> +</div> + <div id="menu"></div> <table style="width: 100%;"> <tr> -<td><h2><span id="h1"></span><span id="appNameHeader"></span></h2></td> -<td style="vertical-align: middle; text-align: right; padding-right: 2px;"><span id="saveStatus" style="font-weight: bold; color: #808080;">Saved</span></td> +<td><h2><span id="appNameHeader"></span></h2></td> +<td style="vertical-align: middle; text-align: right; padding-right: 8px;"><span id="saveStatus" style="font-weight: bold; color: #808080;">Saved</span></td> </tr> </table> -<table style="width: 100%;"> +<table id="compValueBackground" style="width: 2500px; position: absolute; top: 59px; left: 0px; z-index: -1;"> <tr> -<th class="thr thl" style="padding-left: 2px; padding-right: 2px; width: 100%"> +<th class="thr thl"><span style="display: inline-block; padding-top: 0px; padding-bottom: 0px; height: 24px;"></span></th> +</tr> +</table> + +<table id="compValueTable" style="width: 100%;"> +<tr> +<td class="thr thl" style="padding-left: 2px; padding-right: 2px; vertical-align: top; width: 100%"> <input id="compValue" type="text" value="" title="Component value" autocapitalize="off" placeholder="Value" style="position: relative; width: 100%;"/> -</th> +</td> -<th class="thl thr" style="text-align: right; padding-right: 2px;"> -<span id="deleteCompButton" title="Delete a component" class="redbutton" style="font-weight: bold; font-size: 16px; color: #808080; display: inline-block; width: 24px; height: 20px; padding-top: 0px; padding-bottom: 0px; vertical-align: middle; text-align: center; margin-left: 0px; margin-right: 0px;">-</span> +<td class="thl thr" style="text-align: right; padding-right: 2px; vertical-align: top;"> +<span id="deleteCompButton" title="Delete a component" class="graybutton" style="font-weight: bold; font-size: 16px; color: #808080; display: inline-block; width: 24px; height: 20px; padding-top: 0px; padding-bottom: 0px; text-align: center; margin-left: 0px; margin-right: 0px;">-</span> -<span id="addCompButton" title="Add a component" class="greenbutton" style="font-weight: bold; font-size: 16px; display: inline-block; width: 24px; height: 20px; padding-top: 0px; padding-bottom: 0px; vertical-align: middle; text-align: center; margin-left: 0px; margin-right: 0px;">+</span> +<span id="copyCompButton" title="Copy a component" class="graybutton" style="font-weight: bold; font-size: 16px; color: #808080; display: inline-block; width: 24px; height: 20px; padding-top: 0px; padding-bottom: 0px; text-align: center; margin-left: 0px; margin-right: 0px;">c</span> -<span id="playCompButton" title="View component value" class="bluebutton" style="font-weight: bold; font-size: 16px; color: #808080; display: inline-block; width: 24px; height: 20px; padding-top: 0px; padding-bottom: 0px; vertical-align: middle; text-align: center; margin-left: 0px; margin-right: 0px;">></span> -</th> +<span id="addCompButton" title="Add a component" class="graybutton" style="font-weight: bold; font-size: 16px; display: inline-block; width: 24px; height: 20px; padding-top: 0px; padding-bottom: 0px; text-align: center; margin-left: 0px; margin-right: 0px;">+</span> + +<span id="playCompButton" title="View component value" class="graybutton" style="font-weight: bold; font-size: 16px; color: #808080; display: inline-block; width: 24px; height: 20px; padding-top: 0px; padding-bottom: 0px; text-align: center; margin-left: 0px; margin-right: 0px;">></span> +</td> </tr> </table> -<div id="contentdiv" style="margin-top: 4px; width: 100%;"> -<div id="playdiv" style="position:relative; top: 0x; left: 0px; right: 0px; height: 5000px; visibility: hidden"> +<div id="contentdiv" style="margin-top: 4px; width: 2500px;"> +<div id="playdiv" style="position:relative; top: 0x; left: 0px; right: 0px; width: 2500px; height: 5000px; visibility: hidden"> </div> </div> <script type="text/javascript"> +ui.initbody(); + // Get the app name -var appname = ui.queryParams()['app']; +var appname = ui.fragmentParams()['app']; var ispalette = false; if (isNil(appname)) { - appname = ui.queryParams()['palette']; + appname = ui.fragmentParams()['palette']; if (isNil(appname)) window.open('/', '_self'); @@ -94,8 +110,7 @@ function applink(appname) { // Set page titles document.title = windowtitle(window.location.hostname) + ' - ' + (isNil(config.compose)? 'Composition' : config.compose) + ' - ' + appname; -//$('h1').innerHTML = hometitle(window.location.hostname); -$('appNameHeader').innerHTML = '<a href=\"' + applink(appname) + '\" target=\"' + '_blank' + '\">' + appname + '.' + window.location.hostname + '</a>'; +$('appNameHeader').innerHTML = '<a href=\"' + applink(appname) + '\" target=\"' + '_blank' + '\">' + appname + '</a>'; // Load the menu bar displaymenu(); @@ -106,10 +121,20 @@ displaymenu(); var cvalue = $('compValue'); var cadd = $('addCompButton'); var cdelete = $('deleteCompButton'); +var ccopy = $('copyCompButton'); var cplay = $('playCompButton'); +// Position background divs +var mbackground = $('menubackground'); +var menudiv = $('menu'); +mbackground.style.top = ui.pixpos(menudiv.offsetTop); + +var cvbackground = $('compValueBackground'); +var cvtable = $('compValueTable'); +cvbackground.style.top = ui.pixpos(cvtable.offsetTop); + /** - * Adjust field size. + * Adjust component value field size. */ function resizeFields() { cvalue.style.width = '0px'; @@ -176,6 +201,11 @@ function getapp(name, g) { if (isNil(name)) return false; return composites.get(name, function(doc) { + + // Stop now if we didn't get a composite + if (doc == null) + return false; + composite = atomcomposite(doc); if (isNil(composite)) { @@ -197,16 +227,19 @@ function getapp(name, g) { /** * Display a palette. Get it from the server if needed. */ -function displaypalette(name, g, palette, gpalettes) { +function displaypalette(name, g, svg, palette, gpalettes) { if (isNil(name)) return; if (isNil(gpalettes[name])) { // Get the palette from the server - var doc = palettes.get(name); - gpalettes[name] = graph.composite(atomcomposite(doc), graph.mkpath().move(2580,0), true, g); + palettes.get(name, function(doc) { + gpalettes[name] = graph.composite(atomcomposite(doc), graph.mkpath().move(2580,0), true, g); + graph.display(gpalettes[name], g, svg); + }); + return true; } - graph.display(gpalettes[name], g); + graph.display(gpalettes[name], g, svg); return true; } @@ -216,16 +249,16 @@ function displaypalette(name, g, palette, gpalettes) { */ function installpalette(name, pos, g, bg, palette, gpalettes) { var b = graph.mkbutton(name, pos); - graph.display(mklist(b), g); + graph.display(mklist(b), g, g); b.onclick = function(e) { // Swap the selected palette - graph.compselect(bpalette, false); - displaypalette(spalette, bg, palette, gpalettes); + graph.paletteselect(bpalette, false); + displaypalette(spalette, bg, g, palette, gpalettes); bpalette = b; - graph.compselect(b, true, null, null); + graph.paletteselect(b, true); spalette = name; - return displaypalette(spalette, g, palette, gpalettes); + return displaypalette(spalette, g, g, palette, gpalettes); }; if (name != spalette) { @@ -236,8 +269,8 @@ function installpalette(name, pos, g, bg, palette, gpalettes) { } // Display the selected palette - graph.compselect(b, true, null, null); - displaypalette(name, g, palette, gpalettes); + graph.paletteselect(b, true); + displaypalette(name, g, g, palette, gpalettes); return b; } @@ -251,8 +284,11 @@ function save(savexml) { var entry = '<entry xmlns="http://www.w3.org/2005/Atom">' + '<title type="text">' + appname + '</title><id>' + appname + '</id><content type="application/xml">' + savedcomposxml + '</content></entry>'; - composites.put(appname, entry, function(r) { + composites.put(appname, entry, function(e) { + if (e) + return false; $('saveStatus').innerHTML = 'Saved'; + return false; }); return true; } @@ -293,7 +329,7 @@ function compdatalink(appname, cname) { var port = ':' + window.location.port; if (port == ':80' || port == ':443' || port == ':') port = ''; - var link = protocol + '//' + appname + '.' + host + port + '/data/?component=' + cname; + var link = protocol + '//' + appname + '.' + host + port + '/data/#component=' + cname; return link; } @@ -327,6 +363,7 @@ function oncompselect(gsel) { } updateButton(cdelete, link != ''); + updateButton(ccopy, link != ''); updateButton(cplay, link != ''); return true; } @@ -344,7 +381,8 @@ function showdata(gcomp) { gdiv.style.visibility = 'hidden' gvisible = false; pdiv.style.visibility = 'visible'; - pdiv.innerHTML = '<iframe id="dataFrame" style="position: relative; height: 5000px; width: 100%; border: 0px;" scrolling="no" frameborder="0" src="' + + pdiv.innerHTML = ''; + pdiv.innerHTML = '<iframe id="dataFrame" style="position: relative; height: 5000px; width: 2500px; border: 0px;" scrolling="no" frameborder="0" src="' + compdatalink(appname, gcomp.id) + '"></iframe>'; return true; } @@ -360,7 +398,7 @@ function showgraph(gcomp) { pdiv.innerHTML = ''; gdiv.style.visibility = 'visible' gvisible = true; - graph.compselect(gcomp, true, cvalue, cdelete); + graph.compselect(gcomp, true, cvalue, ccopy, cdelete); return true; } @@ -376,26 +414,26 @@ cplay.onclick = function() { } // Create editor graph area -g = graph.mkgraph(cdiv, graph.mkpath().move(-2500,0), cvalue, cadd, cdelete); +g = graph.mkgraph(cdiv, graph.mkpath().move(-2500,0), cvalue, cadd, ccopy, cdelete); gdiv = g.parentNode; bg = graph.mkgroup(graph.mkpath()); // Install the palettes var pos = graph.mkpath().move(0, 0); -bpalette = installpalette('control', pos.rmove(5,0), g, bg, spalette, gpalettes); -installpalette('values', pos.rmove(0,35), g, bg, spalette, gpalettes); -installpalette('lists', pos.rmove(0, 35), g, bg, spalette, gpalettes); -installpalette('transform', pos.rmove(0, 35), g, bg, spalette, gpalettes); -installpalette('text', pos.rmove(0, 35), g, bg, spalette, gpalettes); -installpalette('http', pos.rmove(0, 35), g, bg, spalette, gpalettes); -installpalette('animation', pos.rmove(0, 35), g, bg, spalette, gpalettes); -installpalette('talk', pos.rmove(0, 35), g, bg, spalette, gpalettes); -installpalette('social', pos.rmove(0, 35), g, bg, spalette, gpalettes); -installpalette('search', pos.rmove(0, 35), g, bg, spalette, gpalettes); -installpalette('database', pos.rmove(0, 35), g, bg, spalette, gpalettes); -installpalette('logic', pos.rmove(0, 35), g, bg, spalette, gpalettes); -installpalette('math', pos.rmove(0, 35), g, bg, spalette, gpalettes); -installpalette('python', pos.rmove(0, 35), g, bg, spalette, gpalettes); +bpalette = installpalette('control', pos.rmove(5,2), g, bg, spalette, gpalettes); +installpalette('values', pos.rmove(0,28), g, bg, spalette, gpalettes); +installpalette('lists', pos.rmove(0, 28), g, bg, spalette, gpalettes); +installpalette('transform', pos.rmove(0, 28), g, bg, spalette, gpalettes); +installpalette('text', pos.rmove(0, 28), g, bg, spalette, gpalettes); +installpalette('http', pos.rmove(0, 28), g, bg, spalette, gpalettes); +installpalette('animation', pos.rmove(0, 28), g, bg, spalette, gpalettes); +installpalette('talk', pos.rmove(0, 28), g, bg, spalette, gpalettes); +installpalette('social', pos.rmove(0, 28), g, bg, spalette, gpalettes); +installpalette('search', pos.rmove(0, 28), g, bg, spalette, gpalettes); +installpalette('database', pos.rmove(0, 28), g, bg, spalette, gpalettes); +installpalette('logic', pos.rmove(0, 28), g, bg, spalette, gpalettes); +installpalette('math', pos.rmove(0, 28), g, bg, spalette, gpalettes); +installpalette('python', pos.rmove(0, 28), g, bg, spalette, gpalettes); // Get and display the current app getapp(appname, g); diff --git a/sca-cpp/trunk/modules/edit/htdocs/index.html b/sca-cpp/trunk/modules/edit/htdocs/index.html index 20ccc8f416..3bc871d47b 100644 --- a/sca-cpp/trunk/modules/edit/htdocs/index.html +++ b/sca-cpp/trunk/modules/edit/htdocs/index.html @@ -28,8 +28,8 @@ <script type="text/javascript" src="/all-min.js"></script> <script type="text/javascript" src="/menu.js"></script> </head> -<body class="delayed" onload="ui.onload();"> -<div id="bodydiv" class="devicewidth"> +<body class="delayed" onload="ui.onload();" onbeforeunload="ui.onbeforeunload();"> +<div id="bodydiv" class="bodydiv"> <div id="headdiv" class="hsection"> <script type="text/javascript" src="/headconfig.js"></script> @@ -46,7 +46,6 @@ <div id="maintitle" style="font-size: 150%;"></div> <div id="maindiagram"><div id="diagram" style="width: 320px; height: 280px; background: url(home.png); padding: 0px; margin: 0px auto;"></div></div> -<br/> <input type="button" class="greenbutton" style="font-size: 150%; font-weight: bold; font-style: italic; padding: 10px;" id="getstarted" title="Get Started" value="Get Started"/> @@ -56,6 +55,17 @@ </div> <script type="text/javascript"> + +// On mobile devices, redirect to the last visited page +if (ui.isMobile() && (document.referrer == null || document.referrer == '')) { + var last = ui.lastvisited(); + if (!isNil(last) && last != document.location) + window.open(last, '_self'); +} + +// Init and display this page +ui.initbody(); + // Set page titles document.title = windowtitle(window.location.hostname); $('h1').innerHTML = hometitle(window.location.hostname); @@ -65,7 +75,7 @@ displaymenu(); $('maintitle').innerHTML = isNil(config.maintitle)? 'Simple App Builder' : config.maintitle; $('getstarted').onclick = function() { - return window.open('/store/', '_self'); + return ui.navigate('/store/', '_self'); }; // Display the main diagram diff --git a/sca-cpp/trunk/modules/edit/htdocs/login/index.html b/sca-cpp/trunk/modules/edit/htdocs/login/index.html index 4c7c90cea1..e51a6ac2ae 100644 --- a/sca-cpp/trunk/modules/edit/htdocs/login/index.html +++ b/sca-cpp/trunk/modules/edit/htdocs/login/index.html @@ -17,7 +17,7 @@ * specific language governing permissions and limitations * under the License. --> -<html> +<html manifest="/cache-manifest.cmf"> <head> <title>Sign in</title> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0"/> @@ -27,8 +27,8 @@ <link rel="stylesheet" type="text/css" href="/ui-min.css"/> <script type="text/javascript" src="/all-min.js"></script> </head> -<body class="delayed" onload="ui.onload();"> -<div id="bodydiv" class="devicewidth"> +<body class="delayed" onload="ui.onload();" onbeforeunload="ui.onbeforeunload();"> +<div id="bodydiv" class="bodydiv"> <h1>Sign in</h1> @@ -38,12 +38,14 @@ <tr><td><input type="text" id="httpd_username" name="httpd_username" value="" size="15" autocapitalize="off" placeholder="Enter your user name" style="width: 300px;"/></td></tr> <tr><td><b>Password:</b></td></tr> <tr><td><input type="password" name="httpd_password" value="" size="15" placeholder="Enter your password" style="width: 300px;"/></td></tr> -<tr><td><input type="submit" value="Sign in" class="greenbutton" style="font-weight: bold;"/></td><td></td></tr> +<tr><td><input type="submit" value="Sign in" class="graybutton" style="font-weight: bold;"/></td><td></td></tr> </table> <input type="hidden" name="httpd_location" value="/"/> </form> <script type="text/javascript"> +ui.initbody(); + function queryParams() { qp = new Array(); qs = window.location.search.substring(1).split('&'); diff --git a/sca-cpp/trunk/modules/edit/htdocs/logout/index.html b/sca-cpp/trunk/modules/edit/htdocs/logout/index.html index 1d6079354b..c1f7a57408 100644 --- a/sca-cpp/trunk/modules/edit/htdocs/logout/index.html +++ b/sca-cpp/trunk/modules/edit/htdocs/logout/index.html @@ -17,7 +17,7 @@ * specific language governing permissions and limitations * under the License. --> -<html> +<html manifest="/cache-manifest.cmf"> <head> <title>Sign out</title> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0"/> @@ -27,19 +27,23 @@ <link rel="stylesheet" type="text/css" href="/ui-min.css"/> <script type="text/javascript" src="/all-min.js"></script> </head> -<body class="delayed" onload="ui.onload();"> -<div id="bodydiv" class="devicewidth"> +<body class="delayed" onload="ui.onload();" onbeforeunload="ui.onbeforeunload();"> +<div id="bodydiv" class="bodydiv"> <h1>Sign out</h1> <form name="signout" onsubmit="submitSignout();" action="/" method="GET"> -<input type="submit" id="signOut" value="Sign out" class="greenbutton" style="font-weight: bold"/> +<input type="submit" id="signOut" value="Sign out" class="graybutton" style="font-weight: bold"/> </form> <script type="text/javascript"> +ui.initbody(); + function submitSignout() { - var reset = 'TuscanyOpenAuth=;expires=' + new Date(1970,01,01).toGMTString() + ';domain=.' + domainname(window.location.hostname) + ';path=/;secure=TRUE'; + // Clear session cookie and local storage + var reset = 'TuscanyOpenAuth=; expires=' + new Date(1970,01,01).toGMTString() + '; domain=.' + domainname(window.location.hostname) + '; path=/; secure; version=1'; document.cookie = reset; + localStorage.clear(); document.signout.submit(); return true; } diff --git a/sca-cpp/trunk/modules/edit/htdocs/menu.js b/sca-cpp/trunk/modules/edit/htdocs/menu.js index efddeec1dc..42f18534bc 100644 --- a/sca-cpp/trunk/modules/edit/htdocs/menu.js +++ b/sca-cpp/trunk/modules/edit/htdocs/menu.js @@ -38,16 +38,16 @@ function userMenu() { */ function displaymenu() { var mdiv = $('menu'); - var name = ui.queryParams()['app']; + var name = ui.fragmentParams()['app']; mdiv.innerHTML = ui.menubar( append(mklist(ui.menu('Home', '/'), ui.menu('Store', '/store/')), (isNil(name) || name == 'undefined')? mklist() : mklist( - ui.menu('Stats', '/stats/?app=' + name), - ui.menu('Page', '/page/?app=' + name), - ui.menu(isNil(config.compose)? 'Composition' : config.compose, '/graph/?app=' + name))), + ui.menu('Stats', '/stats/#app=' + name), + ui.menu('Page', '/page/#app=' + name), + ui.menu(isNil(config.compose)? 'Composition' : config.compose, '/graph/#app=' + name))), mklist(ui.menu('Account', '/account/'), ui.menu('Sign out', '/logout/'))); } diff --git a/sca-cpp/trunk/modules/edit/htdocs/page/index.html b/sca-cpp/trunk/modules/edit/htdocs/page/index.html index 0102f4edac..ca2619e07b 100644 --- a/sca-cpp/trunk/modules/edit/htdocs/page/index.html +++ b/sca-cpp/trunk/modules/edit/htdocs/page/index.html @@ -17,7 +17,7 @@ * specific language governing permissions and limitations * under the License. --> -<html> +<html manifest="/cache-manifest.cmf"> <head> <title>Page</title> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0"/> @@ -29,40 +29,54 @@ <script type="text/javascript" src="/menu.js"></script> <script type="text/javascript" src="page.js"></script> </head> -<body class="delayed" onload="ui.onload();"> -<div id="bodydiv" class="devicewidth"> +<body class="delayed" onload="ui.onload();" onbeforeunload="ui.onbeforeunload();"> +<div id="bodydiv" class="bodydiv" style="overflow: visible;"> <div id="headdiv" class="hsection"> <script type="text/javascript" src="/headconfig.js"></script> </div> +<div id="menubackground" style="position: absolute; top: 0px; left: 0px; z-index: -1; width: 2500px;"> +<table cellpadding="0" cellspacing="0" width="100%" class="tbar"><tr><td class="dtbar"> +<table border="0" cellspacing="0" cellpadding="0"><tr><td class="ltbar"><span class="tbarsmenu"> </span></td></tr></table> +</td></tr></table> +</div> + <div id="menu"></div> <table style="width: 100%;"> <tr> -<td><h2><span id="h1"></span><span id="appNameHeader"></span></h2></td> -<td style="vertical-align: middle; text-align: right; padding-right: 2px;"><span id="saveStatus" style="font-weight: bold; color: #808080;">Saved</span></td> +<td><h2><span id="appNameHeader"></span></h2></td> +<td style="vertical-align: middle; text-align: right; padding-right: 8px;"><span id="saveStatus" style="font-weight: bold; color: #808080;">Saved</span></td> </tr> </table> -<table style="width: 100%;"> +<table id="widgetValueBackground" style="width: 2500px; position: absolute; top: 59px; left: 0px; z-index: -1;"> +<tr> +<th class="thr thl"><span style="display: inline-block; padding-top: 0px; padding-bottom: 0px; height: 24px;"></span></th> +</tr> +</table> + +<table id="widgetValueTable" style="width: 100%;"> <tr> -<th class="thr thl" style="padding-left: 2px; padding-right: 2px; width: 100%;"> +<td class="thr thl" style="padding-left: 2px; padding-right: 2px; vertical-align: top; width: 100%;"> <input id="widgetValue" type="text" value="" title="Widget value" autocapitalize="off" placeholder="Value" style="position: relative; width: 100%;"/> -</th> +</td> + +<td class="thl thr" style="text-align: right; padding-right: 2px; vertical-align: top;"> +<span id="deleteWidgetButton" title="Delete a Widget" class="graybutton" style="font-weight: bold; font-size: 16px; color: #808080; display: inline-block; width: 24px; height: 20px; padding-top: 0px; padding-bottom: 0px; text-align: center; margin-left: 0px; margin-right: 0px;">-</span> -<th class="thl thr" style="text-align: right; padding-right: 2px;"> -<span id="deleteWidgetButton" title="Delete a Widget" class="redbutton" style="font-weight: bold; font-size: 16px; color: #808080; display: inline-block; width: 24px; height: 20px; padding-top: 0px; padding-bottom: 0px; vertical-align: middle; text-align: center; margin-left: 0px; margin-right: 0px;">-</span> +<span id="copyWidgetButton" title="Copy a Widget" class="graybutton" style="font-weight: bold; font-size: 16px; color: #808080; display: inline-block; width: 24px; height: 20px; padding-top: 0px; padding-bottom: 0px; text-align: center; margin-left: 0px; margin-right: 0px;">c</span> -<span id="addWidgetButton" title="Add a Widget" class="greenbutton" style="font-weight: bold; font-size: 16px; display: inline-block; width: 24px; height: 20px; padding-top: 0px; padding-bottom: 0px; vertical-align: middle; text-align: center; margin-left: 0px; margin-right: 0px;">+</span> +<span id="addWidgetButton" title="Add a Widget" class="graybutton" style="font-weight: bold; font-size: 16px; display: inline-block; width: 24px; height: 20px; padding-top: 0px; padding-bottom: 0px; middle; text-align: center; margin-left: 0px; margin-right: 0px;">+</span> -<span id="playPageButton" title="View page" class="bluebutton" style="font-weight: bold; font-size: 16px; display: inline-block; width: 24px; height: 20px; padding-top: 0px; padding-bottom: 0px; vertical-align: middle; text-align: center; margin-left: 0px; margin-right: 0px;">></span> -</th> +<span id="playPageButton" title="View page" class="graybutton" style="font-weight: bold; font-size: 16px; display: inline-block; width: 24px; height: 20px; padding-top: 0px; padding-bottom: 0px; middle; text-align: center; margin-left: 0px; margin-right: 0px;">></span> +</td> </tr> </table> -<div id="contentdiv" style="margin-top: 4px; width: 100%;"> -<div id="editdiv" style="visibility: visible; position: relative; top: 0px; left: -2500px; right: 0px; height: 5000px;"> +<div id="contentdiv" style="margin-top: 4px; width: 2500px"> +<div id="editdiv" style="visibility: visible; position: relative; top: 0px; left: -2500px; width: 2500px; height: 5000px;"> <div style="position: relative; left: 2500px; top: 0px; right: 0px; height: 5000px; border:1px; border-style: solid; border-color: #a2bae7; background: url(/public/grid72.png);"></div> <div class="guide" style="position: absolute; left: 2500px; top: 0px; width: 320px; height: 460px;"></div> @@ -90,15 +104,18 @@ <span class="img" id="palette:img" style="position: absolute; left: 0px; top: 430px;"><img src="/public/img.png"/></span> </div> -<div id="playdiv" style="visibility: hidden; position: absolute; top: 0px; left: 0px; right: 0px; height: 5000px;"> +<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> <script type="text/javascript"> +ui.initbody(); + // Get the app name -var appname = ui.queryParams()['app']; +var appname = ui.fragmentParams()['app']; if (isNil(appname)) window.open('/', '_self'); @@ -117,8 +134,7 @@ function applink(appname) { // Set page titles document.title = windowtitle(window.location.hostname) + ' - Page - ' + appname; -//$('h1').innerHTML = hometitle(window.location.hostname); -$('appNameHeader').innerHTML = '<a href=\"' + applink(appname) + '\" target=\"' + '_blank' + '\">' + appname + '.' + window.location.hostname + '</a>'; +$('appNameHeader').innerHTML = '<a href=\"' + applink(appname) + '\" target=\"' + '_blank' + '\">' + appname + '</a>'; // Load the menu bar displaymenu(); @@ -133,6 +149,7 @@ var pdiv = $('playdiv'); var wvalue = $('widgetValue'); var wadd = $('addWidgetButton'); var wdelete = $('deleteWidgetButton'); +var wcopy = $('copyWidgetButton'); var pplay = $('playPageButton'); // Position edit and play divs inside the content div @@ -141,8 +158,17 @@ ediv.style.top = cdiv.offsetTop + 'px'; pdiv.style.position = 'absolute'; pdiv.style.top = cdiv.offsetTop + 'px'; +// Position background divs +var mbackground = $('menubackground'); +var menudiv = $('menu'); +mbackground.style.top = ui.pixpos(menudiv.offsetTop); + +var wvbackground = $('widgetValueBackground'); +var wvtable = $('widgetValueTable'); +wvbackground.style.top = ui.pixpos(wvtable.offsetTop); + /** - * Adjust fields sizes. + * Adjust widget value field size. */ function resizeFields() { wvalue.style.width = '0px'; @@ -188,6 +214,10 @@ function getpage(name, ediv) { return false; return pages.get(name, function(doc) { + // Stop now if we didn't get a page + if (doc == null) + return false; + // Convert the page to XHTML and place it in a hidden buffer var buffer = $('buffer'); var el = atompage(doc); @@ -198,7 +228,21 @@ function getpage(name, ediv) { else buffer.innerHTML = writeStrings(writeXML(atompage(doc), false)); - // Append page nodes to editor + // 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) + return false; + return true; + }, nodeList(ediv.childNodes)); + + map(function(e) { + ediv.removeChild(e); + }, fnodes); + + // Append new page nodes to editor map(function(e) { ediv.appendChild(e); if (!isNil(e.style)) @@ -295,8 +339,11 @@ function save(newxml) { '<title type="text">' + appname + '</title><id>' + appname + '</id><content type="application/xml">' + newxml + '</content></entry>'; - pages.put(appname, entry, function(r) { + pages.put(appname, entry, function(e) { + if (e) + return false; $('saveStatus').innerHTML = 'Saved'; + return false; }); return true; }; @@ -336,7 +383,7 @@ function compvaluelink(appname, cname) { var port = ':' + window.location.port; if (port == ':80' || port == ':443' || port == ':') port = ''; - var link = protocol + '//' + appname + '.' + host + port + '/data/?component=' + cname; + var link = protocol + '//' + appname + '.' + host + port + '/data/#component=' + cname; return link; } @@ -354,6 +401,7 @@ function onwidgetselect(w) { } updateButton(wdelete, link != ''); + updateButton(wcopy, link != ''); return true; } @@ -363,14 +411,15 @@ function onwidgetselect(w) { function playpage() { if (!evisible) return true; - page.widgetselect(widget, false, wvalue, wdelete); + page.widgetselect(widget, false, wvalue, wcopy, wdelete); page.selected = null; wvalue.value = applink(appname); pplay.innerHTML = '<'; ediv.style.visibility = 'hidden' evisible = false; pdiv.style.visibility = 'visible'; - pdiv.innerHTML = '<iframe id="playappframe" style="position: relative; height: 5000px; width: 100%; border: 0px;" scrolling="no" frameborder="0" src="' + + pdiv.innerHTML = ''; + pdiv.innerHTML = '<iframe id="playappframe" style="position: relative; height: 5000px; width: 2500px; border: 0px;" scrolling="no" frameborder="0" src="' + applink(appname) + '"></iframe>'; return true; } @@ -386,7 +435,7 @@ function showedit() { pdiv.innerHTML = ''; ediv.style.visibility = 'visible' evisible = true; - page.widgetselect(widget, true, wvalue, wdelete); + page.widgetselect(widget, true, wvalue, wcopy, wdelete); page.selected = widget; return true; } @@ -401,7 +450,7 @@ pplay.onclick = function() { } // Initialize the page editor -page.edit(ediv, wvalue, wadd, wdelete, onpagechange, onwidgetselect); +page.edit(ediv, wvalue, wadd, wcopy, wdelete, onpagechange, onwidgetselect); // Get and display the current app page getpage(appname, ediv); diff --git a/sca-cpp/trunk/modules/edit/htdocs/page/page.js b/sca-cpp/trunk/modules/edit/htdocs/page/page.js index d316cb72dd..2fd88c0c6b 100644 --- a/sca-cpp/trunk/modules/edit/htdocs/page/page.js +++ b/sca-cpp/trunk/modules/edit/htdocs/page/page.js @@ -30,12 +30,13 @@ var palcx = 2500; /** * Init a page editor. Works with all browsers except IE. */ -page.edit = function(elem, wvalue, wadd, wdelete, onchange, onselect) { +page.edit = function(elem, wvalue, wadd, wcopy, wdelete, onchange, onselect) { // Track element dragging and selection page.dragging = null; page.selected = null; wvalue.disabled = true; + wcopy.disabled = true; wdelete.disabled = true; // Trigger widget select and page change events @@ -59,7 +60,7 @@ page.edit = function(elem, wvalue, wadd, wdelete, onchange, onselect) { page.dragging = dragging; // Remember mouse position - var pos = typeof e.touches != "undefined" ? e.touches[0] : e; + var pos = typeof e.touches != "undefined"? e.touches[0] : e; page.dragX = pos.screenX; page.dragY = pos.screenY; @@ -110,7 +111,7 @@ page.edit = function(elem, wvalue, wadd, wdelete, onchange, onselect) { return true; // Get the mouse position - var pos = typeof e.touches != "undefined" ? e.touches[0] : e; + var pos = typeof e.touches != "undefined"? e.touches[0] : e; if (pos.screenX == page.dragX && pos.screenY == page.dragY) return true; @@ -150,7 +151,7 @@ page.edit = function(elem, wvalue, wadd, wdelete, onchange, onselect) { if (page.selected != null) { // Reset current selection - page.widgetselect(page.selected, false, wvalue, wdelete); + page.widgetselect(page.selected, false, wvalue, wcopy, wdelete); page.selected = null; // Trigger widget select event @@ -165,7 +166,7 @@ page.edit = function(elem, wvalue, wadd, wdelete, onchange, onselect) { } // Deselect the previously selected element - page.widgetselect(page.selected, false, wvalue, wdelete); + page.widgetselect(page.selected, false, wvalue, wcopy, wdelete); // Clone element dragged from palette if (selected.id.substring(0, 8) == 'palette:') { @@ -190,7 +191,7 @@ page.edit = function(elem, wvalue, wadd, wdelete, onchange, onselect) { } // Select the element - page.widgetselect(page.selected, true, wvalue, wdelete); + page.widgetselect(page.selected, true, wvalue, wcopy, wdelete); // Trigger widget select event page.onwidgetselect(page.selected); @@ -227,7 +228,7 @@ page.edit = function(elem, wvalue, wadd, wdelete, onchange, onselect) { return false; // Reset current selection - page.widgetselect(page.selected, false, wvalue, wdelete); + page.widgetselect(page.selected, false, wvalue, wcopy, wdelete); // Remove selected widget page.selected.parentNode.removeChild(page.selected); @@ -242,6 +243,39 @@ page.edit = function(elem, wvalue, wadd, wdelete, onchange, onselect) { 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.widgetselect(page.selected, false, 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.selected.cover.style.left = ui.pixpos(ui.numpos(page.selected.cover.style.left) + 10); + page.selected.cover.style.top = ui.pixpos(ui.numpos(page.selected.cover.style.top) + 10); + + // Bring it to the top + page.bringtotop(page.selected); + + // Select the element + page.widgetselect(page.selected, true, wvalue, wcopy, wdelete); + + // Trigger widget select event + page.onwidgetselect(page.selected); + + // Trigger page change event + page.onpagechange(true); + return false; + }; + // Cover child elements with span elements to prevent // any input events to reach them map(page.cover, nodeList(elem.childNodes)); @@ -253,35 +287,54 @@ page.edit = function(elem, wvalue, wadd, wdelete, onchange, onselect) { * Return the text of a widget. */ page.text = function(e) { - var formula = e.id; - if (formula.substring(0, 5) != 'page:') { - return '=' + formula; + function formula(e) { + var f = e.id; + if (f.substring(0, 5) != 'page:') + return '=' + f; + return ''; } - if (e.className == 'h1' || e.className == 'h2' || e.className == 'text' || e.className == 'section') - return car(childElements(e)).innerHTML; - if (e.className == 'button' || e.className == 'checkbox') - return car(childElements(e)).value; - if (e.className == 'entry' || e.className == 'password') - return car(childElements(e)).defaultValue; - if (e.className == 'select') - return car(childElements(car(childElements(e)))).value; - if (e.className == 'link') { - var hr = car(childElements(e)).href; - var t = car(childElements(car(childElements(e)))).innerHTML; - return hr == t? hr : hr + ',' + t; - } - if (e.className == 'img') { - var src = car(childElements(e)).src; - return src == window.location.href? '' : src; - } - if (e.className == 'iframe') - return car(childElements(e)).href; - if (e.className == 'list') - return ''; - if (e.className == 'table') + function constant(e, f) { + if (e.className == 'h1' || e.className == 'h2' || e.className == 'text' || e.className == 'section') { + var t = car(childElements(e)).innerHTML; + return t == f? '' : t; + } + if (e.className == 'button' || e.className == 'checkbox') { + var t = car(childElements(e)).value; + return t == f? '' : t; + } + if (e.className == 'entry' || e.className == 'password') { + var t = car(childElements(e)).defaultValue; + return t == f? '' : t; + } + if (e.className == 'select') { + var t = car(childElements(car(childElements(e)))).value; + return t == f? '' : t; + } + if (e.className == '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') { + var src = car(childElements(e)).src; + return src == window.location.href? '' : src; + } + if (e.className == 'iframe') { + var hr = car(childElements(e)).href; + return hr == window.location.href? '' : hr; + } + if (e.className == 'list') + return ''; + if (e.className == 'table') + return ''; return ''; - return ''; + } + + var f = formula(e); + var c = constant(e, f); + return f == ''? c : (c == ''? f : f + ',' + c); }; /** @@ -313,49 +366,60 @@ page.hastext = function(e) { * Set the text of a widget. */ page.settext = function(e, t) { - var formula = t.length > 1 && t.substring(0, 1) == '='; - e.id = formula? t.substring(1) : 'page:' + e.className; + function formula(t) { + if (t.length > 1 && t.substring(0, 1) == '=') + return car(t.split(',')); + return ''; + } + + function constant(t) { + return t.length > 1 && t.substring(0, 1) == '='? cdr(t.split(',')) : t.split(','); + } + + var f = formula(t); + var c = constant(t); + + e.id = f != ''? f.substring(1) : ('page:' + e.className); if (e.className == 'h1' || e.className == 'h2' || e.className == 'text' || e.className == 'section') { - car(childElements(e)).innerHTML = t; + car(childElements(e)).innerHTML = isNil(c)? f : car(c); return t; } if (e.className == 'button' || e.className == 'entry' || e.className == 'password') { - car(childElements(e)).defaultValue = t; + car(childElements(e)).defaultValue = isNil(c)? f : car(c); return t; } if (e.className == 'checkbox') { - car(childElements(e)).value = t; - map(function(n) { if (n.nodeName == "SPAN") n.innerHTML = t; return n; }, nodeList(e.childNodes)); + 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') { var ce = car(childElements(car(childElements(e)))); - ce.value = t; - ce.innerHTML = t; + ce.value = isNil(c)? f : car(c); + ce.innerHTML = isNil(c)? f : car(c); return t; } if (e.className == 'list') { - e.innerHTML = '<table class="datatable" style="width: 100%;;"><tr><td class="datatd">' + t + '</td></tr><tr><td class="datatd">...</td></tr></table>'; - return ''; + 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') { - e.innerHTML = '<table class="datatable" style="width: 100%;"><tr><td class="datatdl">' + t + '</td><td class="datatdr">...</td></tr><tr><td class="datatdl">...</td><td class="datatdr">...</td></tr></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') { - var l = t.split(','); var ce = car(childElements(e)); - ce.href = car(l); - car(childElements(ce)).innerHTML = isNil(cdr(l))? car(l) : cadr(l); + 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') { - car(childElements(e)).src = formula? '/public/img.png' : t; + car(childElements(e)).src = isNil(c)? '/public/img.png' : car(c); return t; } if (e.className == 'iframe') { - car(childElements(e)).href = formula? '/public/iframe.html' : t; + car(childElements(e)).href = isNil(c)? '/public/iframe.html' : car(c); return t; } return ''; @@ -418,11 +482,12 @@ page.bringtotop = function(n) { /** * Draw widget selection. */ -page.widgetselect = function(n, s, wvalue, wdelete) { +page.widgetselect = function(n, s, wvalue, wcopy, wdelete) { if (isNil(n) || !s) { // Clear the widget value field wvalue.value = ''; wvalue.disabled = true; + wcopy.disabled = true; wdelete.disabled = true; // Clear the widget outline @@ -434,6 +499,7 @@ page.widgetselect = function(n, s, wvalue, wdelete) { // Update the widget value field wvalue.value = page.text(n); wvalue.disabled = false; + wcopy.disabled = false; wdelete.disabled = false; // Outline the widget diff --git a/sca-cpp/trunk/modules/edit/htdocs/public/iframe.html b/sca-cpp/trunk/modules/edit/htdocs/public/iframe.html index 060e929dd1..a9a9efc4b3 100644 --- a/sca-cpp/trunk/modules/edit/htdocs/public/iframe.html +++ b/sca-cpp/trunk/modules/edit/htdocs/public/iframe.html @@ -17,7 +17,7 @@ * specific language governing permissions and limitations * under the License. --> -<html> +<html manifest="/cache-manifest.cmf"> <head> <title>frame</title> <meta name="viewport" content="width=device-width user-scalable=no initial-scale=1.0"/> diff --git a/sca-cpp/trunk/modules/edit/htdocs/public/notauth.html b/sca-cpp/trunk/modules/edit/htdocs/public/notauth.html index 63f9de36f4..44e68da5de 100644 --- a/sca-cpp/trunk/modules/edit/htdocs/public/notauth.html +++ b/sca-cpp/trunk/modules/edit/htdocs/public/notauth.html @@ -17,7 +17,7 @@ * specific language governing permissions and limitations * under the License. --> -<html> +<html manifest="/cache-manifest.cmf"> <head> <title>Sorry</title> <meta name="viewport" content="width=device-width user-scalable=no initial-scale=1.0"/> @@ -27,8 +27,8 @@ <script type="text/javascript" src="/all-min.js"></script> <script type="text/javascript" src="/menu.js"></script> </head> -<body class="delayed" onload="ui.onload();"> -<div id="bodydiv" class="devicewidth"> +<body class="delayed" onload="ui.onload();" onbeforeunload="ui.onbeforeunload();"> +<div id="bodydiv" class="bodydiv"> <div id="headdiv" class="hsection"> <script type="text/javascript" src="/headconfig.js"></script> @@ -48,6 +48,8 @@ </form> <script type="text/javascript"> +ui.initbody(); + // Set page title $('h1').innerHTML = hometitle(window.location.hostname); diff --git a/sca-cpp/trunk/modules/edit/htdocs/public/notfound.html b/sca-cpp/trunk/modules/edit/htdocs/public/notfound.html index 0d1ce6bb6e..c71f4aa0ef 100644 --- a/sca-cpp/trunk/modules/edit/htdocs/public/notfound.html +++ b/sca-cpp/trunk/modules/edit/htdocs/public/notfound.html @@ -17,7 +17,7 @@ * specific language governing permissions and limitations * under the License. --> -<html> +<html manifest="/cache-manifest.cmf"> <head> <title>Page not found</title> <meta name="viewport" content="width=device-width user-scalable=no initial-scale=1.0"/> @@ -27,8 +27,8 @@ <script type="text/javascript" src="/all-min.js"></script> <script type="text/javascript" src="/menu.js"></script> </head> -<body class="delayed" onload="ui.onload();"> -<div id="bodydiv" class="devicewidth"> +<body class="delayed"> +<div id="bodydiv" class="bodydiv" onload="ui.onload();" onbeforeunload="ui.onbeforeunload();"> <div id="headdiv" class="hsection"> <script type="text/javascript" src="/headconfig.js"></script> @@ -46,6 +46,8 @@ </div> <script type="text/javascript"> +ui.initbody(); + // Set page title $('h1').innerHTML = hometitle(window.location.hostname); diff --git a/sca-cpp/trunk/modules/edit/htdocs/public/notyet.html b/sca-cpp/trunk/modules/edit/htdocs/public/notyet.html index 01413549f6..591d8be991 100644 --- a/sca-cpp/trunk/modules/edit/htdocs/public/notyet.html +++ b/sca-cpp/trunk/modules/edit/htdocs/public/notyet.html @@ -17,7 +17,7 @@ * specific language governing permissions and limitations * under the License. --> -<html> +<html manifest="/cache-manifest.cmf"> <head> <title>Page not found</title> <meta name="viewport" content="width=device-width user-scalable=no initial-scale=1.0"/> @@ -27,8 +27,8 @@ <script type="text/javascript" src="/all-min.js"></script> <script type="text/javascript" src="/menu.js"></script> </head> -<body class="delayed" onload="ui.onload();"> -<div id="bodydiv" class="devicewidth"> +<body class="delayed" onload="ui.onload();" onbeforeunload="ui.onbeforeunload();"> +<div id="bodydiv" class="bodydiv"> <div id="headdiv" class="hsection"> <script type="text/javascript" src="/headconfig.js"></script> @@ -45,6 +45,8 @@ </div> <script type="text/javascript"> +ui.initbody(); + // Set page title $('h1').innerHTML = hometitle(window.location.hostname); diff --git a/sca-cpp/trunk/modules/edit/htdocs/public/oops.html b/sca-cpp/trunk/modules/edit/htdocs/public/oops.html index 5e4c638487..e85c40c172 100644 --- a/sca-cpp/trunk/modules/edit/htdocs/public/oops.html +++ b/sca-cpp/trunk/modules/edit/htdocs/public/oops.html @@ -17,7 +17,7 @@ * specific language governing permissions and limitations * under the License. --> -<html> +<html manifest="/cache-manifest.cmf"> <head> <title>Oops</title> <meta name="viewport" content="width=device-width user-scalable=no initial-scale=1.0"/> @@ -27,8 +27,8 @@ <script type="text/javascript" src="/all-min.js"></script> <script type="text/javascript" src="/menu.js"></script> </head> -<body class="delayed" onload="ui.onload();"> -<div id="bodydiv" class="devicewidth"> +<body class="delayed" onload="ui.onload();" onbeforeunload="ui.onbeforeunload();"> +<div id="bodydiv" class="bodydiv"> <div id="headdiv" class="hsection"> <script type="text/javascript" src="/headconfig.js"></script> @@ -45,6 +45,8 @@ </div> <script type="text/javascript"> +ui.initbody(); + // Set page title $('h1').innerHTML = hometitle(window.location.hostname); diff --git a/sca-cpp/trunk/modules/edit/htdocs/stats/index.html b/sca-cpp/trunk/modules/edit/htdocs/stats/index.html index a40f8b7a32..b7dd4648c6 100644 --- a/sca-cpp/trunk/modules/edit/htdocs/stats/index.html +++ b/sca-cpp/trunk/modules/edit/htdocs/stats/index.html @@ -17,7 +17,7 @@ * specific language governing permissions and limitations * under the License. --> -<html> +<html manifest="/cache-manifest.cmf"> <head> <title>Stats</title> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0"/> @@ -28,8 +28,8 @@ <script type="text/javascript" src="/all-min.js"></script> <script type="text/javascript" src="/menu.js"></script> </head> -<body class="delayed" onload="ui.onload();"> -<div id="bodydiv" class="devicewidth"> +<body class="delayed" onload="ui.onload();" onbeforeunload="ui.onbeforeunload();"> +<div id="bodydiv" class="bodydiv"> <div id="headdiv" class="hsection"> <script type="text/javascript" src="/headconfig.js"></script> @@ -49,7 +49,7 @@ <th class="thl thr" style="padding-top: 4px; padding-bottom: 4px; padding-left: 2px; padding-right: 2px; ">Stats</th> <th class="thl thr" style="width: 100%; text-align: right; padding-right: 2px; padding-top: 0px; padding-bottom: 0px;"> -<input type="button" class="greenbutton" style="font-weight: bold; margin-top: 0px; margin-bottom: 0px; height: 24px;" id="cloneApp" value="Clone" title="Clone this app"/> +<input type="button" class="graybutton" style="font-weight: bold; margin-top: 0px; margin-bottom: 0px; height: 24px;" id="cloneApp" value="Clone" title="Clone this app"/> </th> </tr> </table> @@ -70,8 +70,10 @@ </form> <script type="text/javascript"> +ui.initbody(); + // Get the app name -var appname = ui.queryParams()['app']; +var appname = ui.fragmentParams()['app']; if (isNil(appname)) window.open('/', '_self'); @@ -90,8 +92,7 @@ function applink(appname) { // Set page titles document.title = windowtitle(window.location.hostname) + ' - Stats - ' + appname; -//$('h1').innerHTML = hometitle(window.location.hostname); -$('appNameHeader').innerHTML = '<a href=\"' + applink(appname) + '\" target=\"' + '_blank' + '\">' + appname + '.' + window.location.hostname + '</a>'; +$('appNameHeader').innerHTML = '<a href=\"' + applink(appname) + '\" target=\"' + '_blank' + '\">' + appname + '</a>'; var tclone = isNil(config.clone)? 'Clone' : config.clone; $('cloneApp').value = tclone; $('cloneApp').title = tclone + ' this app'; @@ -102,6 +103,7 @@ displaymenu(); // Init service references var editWidget = sca.component("EditWidget"); var dashboards = sca.reference(editWidget, "dashboards"); +var apps = sca.reference(editWidget, "apps"); /** * The current app entry and corresponding saved XML content. @@ -115,7 +117,12 @@ var savedappentryxml = ''; function getapp(name) { if (isNil(name)) return false; - return dashboards.get(name, function(doc) { + return apps.get(name, function(doc) { + + // Stop now if we didn't get the app + if (doc == null) + return false; + appentry = doc != null? car(elementsToValues(atom.readATOMEntry(mklist(doc)))) : mklist("'entry", mklist("'title", ''), mklist("'id", name)); var title = cadr(assoc("'title", cdr(appentry))); $('appTitle').value = title; @@ -132,8 +139,12 @@ function getapp(name) { function save(entryxml) { $('saveStatus').innerHTML = 'Saving'; savedappentryxml = entryxml; - dashboards.put(appname, savedappentryxml); - $('saveStatus').innerHTML = 'Saved'; + dashboards.put(appname, savedappentryxml, function(e) { + if (e) + return false; + $('saveStatus').innerHTML = 'Saved'; + return false; + }); return true; } @@ -165,7 +176,7 @@ $('appForm').onsubmit = function() { * Handle Clone button event. */ $('cloneApp').onclick = function() { - return window.open('/clone/?app=' + appname, '_self'); + return ui.navigate('/clone/#app=' + appname, '_self'); } // Get the current app diff --git a/sca-cpp/trunk/modules/edit/htdocs/store/index.html b/sca-cpp/trunk/modules/edit/htdocs/store/index.html index ce8b9d1251..e63dbdb834 100644 --- a/sca-cpp/trunk/modules/edit/htdocs/store/index.html +++ b/sca-cpp/trunk/modules/edit/htdocs/store/index.html @@ -17,7 +17,7 @@ * specific language governing permissions and limitations * under the License. --> -<html> +<html manifest="/cache-manifest.cmf"> <head> <title>Store</title> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0"/> @@ -28,8 +28,8 @@ <script type="text/javascript" src="/all-min.js"></script> <script type="text/javascript" src="/menu.js"></script> </head> -<body class="delayed" onload="ui.onload();"> -<div id="bodydiv" class="devicewidth"> +<body class="delayed" onload="ui.onload();" onbeforeunload="ui.onbeforeunload();"> +<div id="bodydiv" class="bodydiv"> <div id="headdiv" class="hsection"> <script type="text/javascript" src="/headconfig.js"></script> @@ -46,6 +46,8 @@ <div id="apps"></div> <script type="text/javascript"> +ui.initbody(); + // Set page titles document.title = windowtitle(window.location.hostname) + ' - Store'; $('h1').innerHTML = hometitle(window.location.hostname); @@ -54,7 +56,7 @@ $('h1').innerHTML = hometitle(window.location.hostname); displaymenu(); // Get the store category -var category = ui.queryParams()['category']; +var category = ui.fragmentParams()['category']; if (isNil(category)) category = 'myapps'; @@ -65,10 +67,10 @@ function catmenu() { function catmenuitem(name, cat) { var c = cat == category? 'smenu' : 'amenu'; return '<th class="thl thr" style="width: 10px; padding-top: 4px; padding-bottom: 4px; padding-right: 6px;">' - + ui.ahref('/store/?category=' + cat, '_self', '<span class="' + c + '">' + name + '</span>') + '</th>'; + + ui.ahref('/store/#category=' + cat, '_reload', '<span class="' + c + '">' + name + '</span>') + '</th>'; } - var m = '<table style="width: 100%;"><tr>'; + var m = '<table style="width: 100%; margin-bottom: 2px;"><tr>'; m += catmenuitem('My Apps', 'myapps'); m += catmenuitem('New', 'new'); m += catmenuitem('Top', 'top'); @@ -76,7 +78,7 @@ function catmenu() { m += catmenuitem('All', 'all'); if (category == 'myapps') { m += '<th class="thl thr" style="width: 100%; padding-top: 0px; padding-bottom: 0px; padding-right: 0px; text-align: right;">'; - m += '<input type="button" class="greenbutton" id="createApp" title="Create a new app" style="font-weight: bold; margin-top: 0px; margin-bottom: 0px; height: 24px;" Value="New App"/>'; + m += '<input type="button" class="graybutton" id="createApp" title="Create a new app" style="font-weight: bold; margin-top: 0px; margin-bottom: 0px; height: 24px;" Value="New App"/>'; m += '</th></tr></table>'; return m; } @@ -111,14 +113,14 @@ function applink(appname) { * Edit an app. */ function editApp(appname) { - return window.open('/page/?app=' + appname, '_self'); + return ui.navigate('/page/#app=' + appname, '_self'); } /** * View an app. */ function viewApp(appname) { - return window.open('/stats/?app=' + appname, '_self'); + return ui.navigate('/stats/#app=' + appname, '_self'); } /** @@ -126,7 +128,7 @@ function viewApp(appname) { */ if (category == 'myapps') { $('createApp').onclick = function() { - return window.open('/create/', '_self'); + return ui.navigate('/create/', '_self'); } } @@ -135,21 +137,29 @@ if (category == 'myapps') { */ function getapps(category) { function display(doc) { + + // Stop now if we didn't get the apps + if (doc == null) + return false; + var apps = '<div>'; var feed = car(elementsToValues(atom.readATOMFeed(mklist(doc)))); var aentries = assoc("'entry", cdr(feed)); var entries = isNil(aentries)? mklist() : isList(car(cadr(aentries)))? cadr(aentries) : mklist(cdr(aentries)); - for (var i = 0; i < length(entries); i++) { - var entry = entries[i]; + + 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 = 'joe'; var clone = isNil(config.clone)? 'Clone' : config.clone; - apps += '<div class="box" style="width: 285px; display: inline-block; border: 1px; border-style: solid; border-color: #dcdcdc; border-collapse: collapse; margin: 5px; padding: 10px; vertical-align: top;">' + apps += '<div class="box" style="width: 150px; display: inline-block; border: 1px; border-style: solid; border-color: #dcdcdc; border-collapse: collapse; margin: 2px; padding: 2px; vertical-align: top;">' apps += '<table><tr>'; apps += '<td>'; - apps += '<div>' + ui.ahref('/stats/?app=' + name, '_self', '<img src="/public/app.png" width="50" height="50" style="height: 50px; width: 50px; vertical-align: top; margin-right: 10px; margin-bottom: 5px;"></img>') + '</div>'; + apps += '<div>' + ui.ahref('/stats/#app=' + name, '_self', '<img src="/public/app.png" width="50" height="50" style="height: 50px; width: 50px; vertical-align: top; margin: 0px; padding: 0px;"></img>') + '</div>'; apps += '</td>'; apps += '<td class="tdw">'; apps += '<div style="font-weight: bold">' + ui.ahref(applink(name), '_blank', name) + '</div>'; @@ -157,13 +167,14 @@ function getapps(category) { apps += '<div style="color: #808080;">Shared</div>'; else apps += '<div>' + 'by ' + '<span style="font-weight: bold;">' + author + '</span></div>'; - apps += '<div>Feb 4, 2011</div>'; - apps += '<br/>'; - apps += '<div>' + title + '</div>'; apps += '</td>'; apps += '</tr></table>'; apps += '</div>'; + return displayentries(cdr(entries)); } + + displayentries(entries); + apps += '</div>'; $('apps').innerHTML = apps; } diff --git a/sca-cpp/trunk/modules/edit/log.py b/sca-cpp/trunk/modules/edit/log.py index d316831db6..8aa3d3bd30 100644 --- a/sca-cpp/trunk/modules/edit/log.py +++ b/sca-cpp/trunk/modules/edit/log.py @@ -20,5 +20,5 @@ from sys import stderr # Log a message def log(msg): - print >> stderr, msg + print >> stderr, '[rconsole]', msg diff --git a/sca-cpp/trunk/modules/js/htdocs/all-min.js b/sca-cpp/trunk/modules/js/htdocs/all-min.js index 05ae9ce35b..921abf170e 100644 --- a/sca-cpp/trunk/modules/js/htdocs/all-min.js +++ b/sca-cpp/trunk/modules/js/htdocs/all-min.js @@ -1,39 +1,37 @@ function cons(car,cdr){var a=new Array();a.push(car);return a.concat(cdr);} function car(l){return l[0];} -function first(l){return car(l);} +function first(l){return l[0];} function cdr(l){return l.slice(1);} -function rest(l){return cdr(l);} -function cadr(l){return car(cdr(l));} -function cddr(l){return cdr(cdr(l));} -function caddr(l){return car(cddr(l));} -function cdddr(l){return cdr(cdr(cdr(l)));} -function cadddr(l){return car(cdddr(l));} +function rest(l){return l.slice(1);} +function cadr(l){return l[1];} +function cddr(l){return l.slice(2);} +function caddr(l){return l[2];} +function cdddr(l){return l.slice(3);} +function cadddr(l){return l[3];} function append(a,b){return a.concat(b);} function reverse(l){return l.slice(0).reverse();} function range(a,b){var l=new Array();for(var x=a;x<b;x++) l.push(x);return l;} -function isNil(v){if(v==null||typeof v=='undefined'||(v.constructor==Array&&v.length==0)) -return true;return false;} -function isSymbol(v){if(typeof v=='string'&&v.slice(0,1)=="'") -return true;return false;} -function isString(v){if(typeof v=='string'&&v.slice(0,1)!="'") -return true;return false;} -function isList(v){if(v!=null&&typeof v!='undefined'&&v.constructor==Array) -return true;return false;} -function isTaggedList(v,t){if(isList(v)&&!isNil(v)&&car(v)==t) -return true;return false;} +function isNil(v){return(v==null||typeof v=='undefined'||(v.constructor==Array&&v.length==0));} +function isSymbol(v){return(typeof v=='string'&&v.slice(0,1)=="'");} +function isString(v){return(typeof v=='string'&&v.slice(0,1)!="'");} +function isList(v){return(v!=null&&typeof v!='undefined'&&v.constructor==Array);} +function isTaggedList(v,t){return(isList(v)&&!isNil(v)&&car(v)==t);} var emptylist=new Array();function mklist(){if(arguments.length==0) return emptylist;var a=new Array();for(i=0;i<arguments.length;i++) a[i]=arguments[i];return a;} function length(l){return l.length;} function assoc(k,l){if(isNil(l)) -return mklist();if(k==car(car(l))) -return car(l);return assoc(k,cdr(l));} +return emptylist;var n=l.length;for(var i=0;i<n;i++){if(k==car(l[i])) +return l[i];} +return emptylist;} function map(f,l){if(isNil(l)) -return l;return cons(f(car(l)),map(f,cdr(l)));} +return l;var n=l.length;var a=new Array();for(var i=0;i<n;i++){a.push(f(l[i]));} +return a;} function filter(f,l){if(isNil(l)) -return l;if(f(car(l))) -return cons(car(l),filter(f,cdr(l)));return filter(f,cdr(l));} +return l;var n=l.length;var a=new Array();for(var i=0;i<n;i++){if(f(l[i])) +a.push(l[i]);} +return a;} function reduce(f,i,l){if(isNil(l)) return i;return reduce(f,f(i,car(l)),cdr(l));} function tokens(path){return filter(function(s){return length(s)!=0;},path.split("/"));} @@ -50,7 +48,8 @@ config={};function AssertException(){} AssertException.prototype.toString=function(){return'AssertException';};function assert(exp){if(!exp) throw new AssertException();} function writeStrings(l){if(isNil(l)) -return'';return car(l)+writeStrings(cdr(l));} +return'';var s='';var n=l.length;for(var i=0;i<n;i++){s=s+l[i];} +return s;} function writeValue(v){function writePrimitive(p){if(isSymbol(p)) return''+p.substring(1);if(isString(p)) return'"'+p+'"';return''+p;} @@ -84,18 +83,11 @@ return b;a.length=0;return setappend(a,b);} var element="'element" var attribute="'attribute" var atsign="'@" -function isElement(v){if(!isList(v)||isNil(v)||car(v)!=element) -return false;return true;} -function isAttribute(v){if(!isList(v)||isNil(v)||car(v)!=attribute) -return false;return true;} -function attributeName(l){return cadr(l);} -function attributeValue(l){return caddr(l);} -function elementName(l){return cadr(l);} -function elementHasChildren(l){return!isNil(cddr(l));} -function elementChildren(l){return cddr(l);} -function elementHasValue(l){r=reverse(l);if(isSymbol(car(r))) -return false;if(isList(car(r))&&!isNil(car(r))&&isSymbol(car(car(r)))) -return false;return true;} +function isElement(v){return(!(!isList(v)||isNil(v)||car(v)!=element));} +function isAttribute(v){return(!(!isList(v)||isNil(v)||car(v)!=attribute));} +attributeName=cadr;attributeValue=caddr;elementName=cadr;function elementHasChildren(l){return!isNil(cddr(l));} +elementChildren=cddr;function elementHasValue(l){var r=reverse(l);if(isSymbol(car(r))) +return false;return(!(isList(car(r))&&!isNil(car(r))&&isSymbol(car(car(r)))))} function elementValue(l){return car(reverse(l));} function elementToValueIsList(v){if(!isList(v)) return false;return isNil(v)||!isSymbol(car(v));} @@ -105,10 +97,7 @@ return mklist(elementName(t),elementValue(t));return cons(elementName(t),mklist( return cons(elementName(t),elementsToValues(elementChildren(t)));} if(!isList(t)) return t;return elementsToValues(t);} -function elementToValueIsSymbol(v){if(!isList(v)) -return false;if(isNil(v)) -return false;if(!isSymbol(car(v))) -return false;return true;} +function elementToValueIsSymbol(v){return(!(!isList(v))||isNil(v)||!isSymbol(car(v)));} function elementToValueGroupValues(v,l){if(isNil(l)||!elementToValueIsSymbol(v)||!elementToValueIsSymbol(car(l))) return cons(v,l);if(car(car(l))!=car(v)) return cons(v,l);if(!elementToValueIsList(cadr(car(l)))){var g=mklist(car(v),mklist(cdr(v),cdr(car(l))));return elementToValueGroupValues(g,cdr(l));} @@ -243,12 +232,13 @@ var turi=targetURI();if(isNil(turi)) return turi;return car(tokens(turi));};scdl.properties=function(l){return namedElementChildren("'property",l);};scdl.propertyValue=function(l){if(!elementHasValue(l)) return'';return elementValue(l);};scdl.nameToElementAssoc=function(l){if(isNil(l)) return l;return cons(mklist(scdl.name(car(l)),car(l)),scdl.nameToElementAssoc(cdr(l)));};var ui={};ui.ahref=function(loc,target,html){if(target=='_blank') -return'<a href="'+loc+'" target="_blank">'+html+'</a>';return'<a href="javascript:void(0)" onclick="window.open(\''+loc+'\', \''+target+'\');">'+html+'</a>';};ui.menu=function(name,href,target){function Menu(n,h,t){this.name=n;this.href=h;this.target=isNil(t)?'_parent':t;this.content=function(){function complete(uri){var q=uri.indexOf('?');if(q!=-1) +return'<a href="'+loc+'" target="_blank">'+html+'</a>';return'<a href="javascript:void(0)" onclick="ui.navigate(\''+loc+'\', \''+target+'\');">'+html+'</a>';};ui.menu=function(name,href,target){function Menu(n,h,t){this.name=n;this.href=h;this.target=isNil(t)?'_parent':t;this.content=function(){function complete(uri){var h=uri.indexOf('#');if(h!=-1) +return complete(uri.substr(0,h));var q=uri.indexOf('?');if(q!=-1) return complete(uri.substr(0,q));if(uri.match('.*\.html$')) return uri;if(uri.match('.*/$')) return uri+'index.html';return uri+'/index.html';} if(complete(this.href)!=complete(window.top.location.pathname)) -return ui.ahref(this.href,this.target,'<span class="amenu">'+this.name+'</span>');return ui.ahref(this.href,this.target,'<span class="smenu">'+this.name+'</span>');};} +return ui.ahref(this.href,this.target,'<span class="tbaramenu">'+this.name+'</span>');return ui.ahref(this.href,this.target,'<span class="tbarsmenu">'+this.name+'</span>');};} return new Menu(name,href,target);};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>';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>';for(i in right) @@ -267,18 +257,30 @@ items+='</table>';this.suggestDiv.innerHTML=items;if(items.length!=0){var node=i 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);};};ui.content=function(win){if(!isNil(win.document)) -return win.document;if(!isNil(win.contentDocument)) -return win.contentDocument;return null;};ui.elementByID=function(node,id){for(var i in node.childNodes){var child=node.childNodes[i];if(child.id==id) +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);};};ui.elementByID=function(node,id){for(var i in node.childNodes){var child=node.childNodes[i];if(child.id==id) return child;var gchild=ui.elementByID(child,id);if(gchild!=null) return gchild;} return null;};function $(id){if(id==document){if(!isNil(document.widget)) return document.widget;return document;} return ui.elementByID($(document),id);};ui.queryParams=function(){var qp=new Array();var qs=window.location.search.substring(1).split('&');for(var i=0;i<qs.length;i++){var e=qs[i].indexOf('=');if(e>0) qp[qs[i].substring(0,e)]=unescape(qs[i].substring(e+1));} -return qp;};ui.isMobile=function(){var ua=navigator.userAgent;if(ua.match(/iPhone/i)||ua.match(/iPad/i)||ua.match(/Android/i)||ua.match(/Blackberry/i)||ua.match(/WebOs/i)) -return true;return false;};ui.onload=function(){document.body.style.visibility='visible';document.body.onorientationchange=function(){window.open(window.location,'_self');return true;};return true;};ui.numpos=function(p){if(p=='') -return 0;return Number(p.substr(0,p.length-2));};ui.pixpos=function(p){return p+'px';};ui.datatable=function(l){function indent(i){if(i==0) +return qp;};ui.fragmentParams=function(){var qp=new Array();var qs=window.location.hash.substring(1).split('&');for(var i=0;i<qs.length;i++){var e=qs[i].indexOf('=');if(e>0) +qp[qs[i].substring(0,e)]=unescape(qs[i].substring(e+1));} +return qp;};ui.mobiledetected=false;ui.mobile=false;ui.isMobile=function(){if(ui.mobiledetected) +return ui.mobile;var ua=navigator.userAgent;if(ua.match(/iPhone/i)||ua.match(/iPad/i)||ua.match(/Android/i)||ua.match(/Blackberry/i)||ua.match(/WebOs/i)) +ui.mobile=true;ui.mobiledetected=true;return ui.mobile;};ui.pagetransitions=false;ui.initbody=function(){if(ui.isMobile()){if(ui.pagetransitions){var bdiv=$('bodydiv');if(!isNil(bdiv)){bdiv.className='bodydivloading';}} +document.body.onorientationchange=ui.onorientationchange;} +return true;} +ui.onorientationchange=function(){window.open(window.location,'_self');return true;} +ui.onload=function(){var path=document.location.pathname;if(path.indexOf('/login/')!=0&&path.indexOf('/logout/')!=0) +localStorage.setItem('ui.lastvisited',''+document.location);document.body.style.visibility='visible';if(ui.pagetransitions&&ui.isMobile()){setTimeout(function(){var bdiv=$('bodydiv');if(!isNil(bdiv)){function transitionend(e){bdiv.removeEventListener('webkitTransitionEnd',transitionend,false);bdiv.removeEventListener('transitionend',transitionend,false);bdiv.className='bodydiv';};bdiv.addEventListener('webkitTransitionEnd',transitionend,false);bdiv.addEventListener('transitionend',transitionend,false);bdiv.className='bodydivloaded';}},0);} +return true;};ui.navigate=function(url,win){function opendoc(url,win){if(win=='_reload'){window.location=url;return window.location.reload();} +return window.open(url,win);} +if(ui.pagetransitions&&ui.isMobile()&&win!='_blank'){var bdiv=$('bodydiv');if(!isNil(bdiv)){function transitionend(e){bdiv.removeEventListener('webkitTransitionEnd',transitionend,false);bdiv.removeEventListener('transitionend',transitionend,false);return opendoc(url,win);};bdiv.addEventListener('webkitTransitionEnd',transitionend,false);bdiv.addEventListener('transitionend',transitionend,false);bdiv.className='bodydivunloaded';return true;}} +return opendoc(url,win);} +ui.onbeforeunload=function(){if(ui.pagetransitions&&ui.isMobile()){var bdiv=$('bodydiv');if(!isNil(bdiv)) +bdiv.className='bodydivunloaded';}};ui.lastvisited=function(){return localStorage.getItem('ui.lastvisited');} +ui.numpos=function(p){return p==''?0:Number(p.substr(0,p.length-2));};ui.pixpos=function(p){return p+'px';};ui.datatable=function(l){function indent(i){if(i==0) return'';return' '+indent(i-1);} function rows(l,i){if(isNil(l)) return'';var e=car(l);if(!isList(e)) @@ -310,30 +312,31 @@ return"{"+v.join(", ")+"}";};function HTTPBindingClient(name,uri){this.name=name HTTPBindingClient.jsonrpcID=1;HTTPBindingClient.prototype.createApplyMethod=function(){var fn=function(){var methodName=arguments[0];var args=[];for(var i=1;i<arguments.length;i++) args.push(arguments[i]);var cb=null;if(typeof args[args.length-1]=="function") cb=args.pop();var req=HTTPBindingClient.makeJSONRequest(methodName,args,cb);return fn.client.jsonApply(req);};fn.client=this;return fn;};HTTPBindingClient.makeJSONRequest=function(methodName,args,cb){var req={};req.id=HTTPBindingClient.jsonrpcID++;if(cb) -req.cb=cb;var obj={};obj.id=req.id;obj.method=methodName;obj.params=args;req.data=JSONClient.toJSON(obj);return req;};HTTPBindingClient.jsonResult=function(http){function httpCharset(http){try{var contentType=http.getResponseHeader("Content-type");var parts=contentType.split(/\s*;\s*/);for(var i=0;i<parts.length;i++){if(parts[i].substring(0,8)=="charset=") +req.cb=cb;var obj={};obj.id=req.id;obj.method=methodName;obj.params=args;req.data=JSONClient.toJSON(obj);return req;};HTTPBindingClient.jsonResult=function(http){function httpCharset(http){try{var contentType=http.getResponseHeader("Content-Type");var parts=contentType.split(/\s*;\s*/);for(var i=0;i<parts.length;i++){if(parts[i].substring(0,8)=="charset=") return parts[i].substring(8,parts[i].length);}}catch(e){} return"UTF-8";} if(!HTTPBindingClient.charset) HTTPBindingClient.charset=httpCharset(http);var obj;eval("obj = "+http.responseText);if(obj.error) -throw new HTTPBindingClient.Exception(obj.error.code,obj.error.msg);var res=obj.result;return res;};HTTPBindingClient.prototype.jsonApply=function(req){var http=HTTPBindingClient.getHTTPRequest();var hascb=req.cb?true:false;http.open("POST",this.uri,hascb);http.setRequestHeader("Content-type","application/json-rpc");if(hascb){http.onreadystatechange=function(){if(http.readyState==4){if(http.status==200){var res=null;try{res=HTTPBindingClient.jsonResult(http);}catch(e){req.cb(null,e);} -req.cb(res);}else -req.cb(null,HTTPBindingClient.Exception(http.status,http.statusText));}};http.send(req.data);return req.id;} +throw new HTTPBindingClient.Exception(obj.error.code,obj.error.msg);var res=obj.result;return res;};HTTPBindingClient.prototype.jsonApply=function(req){var http=HTTPBindingClient.getHTTPRequest();var hascb=req.cb?true:false;http.open("POST",this.uri,hascb);http.setRequestHeader("Content-Type","application/json-rpc");if(hascb){http.onreadystatechange=function(){if(http.readyState==4){if(http.status==200){var res=null;try{res=HTTPBindingClient.jsonResult(http);try{req.cb(res);}catch(cbe){}}catch(e){try{req.cb(null,e);}catch(cbe){}}}else +try{req.cb(null,HTTPBindingClient.Exception(http.status,http.statusText));}catch(cbe){}}};http.send(req.data);return req.id;} http.send(req.data);if(http.status==200) -return HTTPBindingClient.jsonResult(http);throw new HTTPBindingClient.Exception(http.status,http.statusText);};HTTPBindingClient.prototype.get=function(id,cb){var http=HTTPBindingClient.getHTTPRequest();var hascb=cb?true:false;http.open("GET",this.uri+'/'+id,hascb);if(hascb){http.onreadystatechange=function(){if(http.readyState==4){if(http.status==200) -cb(http.responseText);else -cb(null,new HTTPBindingClient.Exception(http.status,http.statusText));}};http.send(null);return true;} -http.send(null);if(http.status==200) -return http.responseText;throw new HTTPBindingClient.Exception(http.status,http.statusText);};HTTPBindingClient.prototype.post=function(entry,cb){var http=HTTPBindingClient.getHTTPRequest();var hascb=cb?true:false;http.open("POST",this.uri,hascb);http.setRequestHeader("Content-Type","application/atom+xml");if(hascb){http.onreadystatechange=function(){if(http.readyState==4){if(http.status==201) -cb(http.responseText);else -cb(null,new HTTPBindingClient.Exception(http.status,http.statusText));}};http.send(entry);return true;} +return HTTPBindingClient.jsonResult(http);throw new HTTPBindingClient.Exception(http.status,http.statusText);};HTTPBindingClient.prototype.get=function(id,cb){var u=this.uri+'/'+id;var hascb=cb?true:false;var item=localStorage.getItem(u);if(item!=null&&item!=''){if(!hascb) +return item;try{cb(item);}catch(cbe){}} +var http=HTTPBindingClient.getHTTPRequest();http.open("GET",u,hascb);if(hascb){http.onreadystatechange=function(){if(http.readyState==4){if(http.status==200){if(http.getResponseHeader("X-Login")!=null){try{cb(null,new HTTPBindingClient.Exception(403,'X-Login'));}catch(cbe){}}else if(http.responseText==''||http.getResponseHeader("Content-Type")==null){try{cb(null,new HTTPBindingClient.Exception(403,'No-Content'));}catch(cbe){}}else{if(item==null||http.responseText!=item){if(http.responseText!=null){localStorage.setItem(u,http.responseText);} +try{cb(http.responseText);}catch(cbe){}}}} +else{if(item==null){try{cb(null,new HTTPBindingClient.Exception(http.status,http.statusText));}catch(cbe){}}}}};http.send(null);return true;} +http.send(null);if(http.status==200){if(http.getResponseHeader("X-Login")!=null){throw new HTTPBindingClient.Exception(403,'X-Login');}else if(http.responseText==''||http.getResponseHeader("Content-Type")==null){throw new HTTPBindingClient.Exception(403,'No-Content');} +return http.responseText;} +throw new HTTPBindingClient.Exception(http.status,http.statusText);};HTTPBindingClient.prototype.getnocache=function(id,cb){var u=this.uri+'/'+id;var hascb=cb?true:false;var http=HTTPBindingClient.getHTTPRequest();http.open("GET",u,hascb);if(hascb){http.onreadystatechange=function(){if(http.readyState==4){if(http.status==200){if(http.getResponseHeader("X-Login")!=null){try{return cb(null,new HTTPBindingClient.Exception(403,'X-Login'));}catch(cbe){}}else if(http.responseText==''||http.getResponseHeader("Content-Type")==null){try{return cb(null,new HTTPBindingClient.Exception(403,'No-Content'));}catch(cbe){}}else{try{cb(http.responseText);}catch(cbe){}}}else{try{cb(null,new HTTPBindingClient.Exception(http.status,http.statusText));}catch(cbe){}}}};http.send(null);return true;} +http.send(null);if(http.status==200){if(http.getResponseHeader("X-Login")!=null){throw new HTTPBindingClient.Exception(403,'X-Login');}else if(http.responseText==''||http.getResponseHeader("Content-Type")==null){throw new HTTPBindingClient.Exception(403,'No-Content');} +return http.responseText;} +throw new HTTPBindingClient.Exception(http.status,http.statusText);};HTTPBindingClient.prototype.post=function(entry,cb){var http=HTTPBindingClient.getHTTPRequest();var hascb=cb?true:false;http.open("POST",this.uri,hascb);http.setRequestHeader("Content-Type","application/atom+xml");if(hascb){http.onreadystatechange=function(){if(http.readyState==4){if(http.status==201){try{cb(http.responseText);}catch(cbe){}} +else{try{cb(null,new HTTPBindingClient.Exception(http.status,http.statusText));}catch(cbe){}}}};http.send(entry);return true;} http.send(entry);if(http.status==201) -return http.responseText;throw new HTTPBindingClient.Exception(http.status,http.statusText);};HTTPBindingClient.prototype.put=function(id,entry,cb){var http=HTTPBindingClient.getHTTPRequest();var hascb=cb?true:false;http.open("PUT",this.uri+'/'+id,hascb);http.setRequestHeader("Content-Type","application/atom+xml");if(hascb){http.onreadystatechange=function(){if(http.readyState==4){if(http.status==200) -cb();else -cb(new HTTPBindingClient.Exception(http.status,http.statusText));}};http.send(entry);return true;} +return http.responseText;throw new HTTPBindingClient.Exception(http.status,http.statusText);};HTTPBindingClient.prototype.put=function(id,entry,cb){var u=this.uri+'/'+id;localStorage.setItem(u,entry);var http=HTTPBindingClient.getHTTPRequest();var hascb=cb?true:false;http.open("PUT",u,hascb);http.setRequestHeader("Content-Type","application/atom+xml");if(hascb){http.onreadystatechange=function(){if(http.readyState==4){if(http.status==200){try{cb();}catch(cbe){}}else{try{cb(new HTTPBindingClient.Exception(http.status,http.statusText));}catch(cbe){}}}};http.send(entry);return true;} http.send(entry);if(http.status==200) -return true;throw new HTTPBindingClient.Exception(http.status,http.statusText);};HTTPBindingClient.prototype.del=function(id,cb){var http=HTTPBindingClient.getHTTPRequest();var hascb=cb?true:false;http.open("DELETE",this.uri+'/'+id,hascb);if(cb){http.onreadystatechange=function(){if(http.readyState==4){if(http.status==200) -cb();else -cb(new HTTPBindingClient.Exception(http.status,http.statusText));}};http.send(null);return true;} +return true;throw new HTTPBindingClient.Exception(http.status,http.statusText);};HTTPBindingClient.prototype.del=function(id,cb){var u=this.uri+'/'+id;localStorage.removeItem(u);var http=HTTPBindingClient.getHTTPRequest();var hascb=cb?true:false;http.open("DELETE",u,hascb);if(cb){http.onreadystatechange=function(){if(http.readyState==4){if(http.status==200){try{cb();}catch(cbe){}} +else{try{cb(new HTTPBindingClient.Exception(http.status,http.statusText));}catch(cbe){}}}};http.send(null);return true;} http.send(null);if(http.status==200) return true;throw new HTTPBindingClient.Exception(http.status,http.statusText);};HTTPBindingClient.Exception=function(code,message){this.name="HTTPBindingClientException";this.code=code;this.message=message;};HTTPBindingClient.Exception.prototype=new Error();HTTPBindingClient.Exception.prototype.toString=function(){return this.name+": "+this.message;};HTTPBindingClient.msxmlNames=["MSXML2.XMLHTTP.5.0","MSXML2.XMLHTTP.4.0","MSXML2.XMLHTTP.3.0","MSXML2.XMLHTTP","Microsoft.XMLHTTP"];HTTPBindingClient.getHTTPRequest=function(){if(HTTPBindingClient.httpFactory) return HTTPBindingClient.httpFactory();try{HTTPBindingClient.httpFactory=function(){return new XMLHttpRequest();};return HTTPBindingClient.httpFactory();}catch(e){} diff --git a/sca-cpp/trunk/modules/js/htdocs/component.js b/sca-cpp/trunk/modules/js/htdocs/component.js index 3712ee59cb..742e7be930 100644 --- a/sca-cpp/trunk/modules/js/htdocs/component.js +++ b/sca-cpp/trunk/modules/js/htdocs/component.js @@ -161,7 +161,7 @@ HTTPBindingClient.jsonResult = function(http) { // Get the charset function httpCharset(http) { try { - var contentType = http.getResponseHeader("Content-type"); + var contentType = http.getResponseHeader("Content-Type"); var parts = contentType.split(/\s*;\s*/); for (var i = 0; i < parts.length; i++) { if (parts[i].substring(0, 8) == "charset=") @@ -190,7 +190,7 @@ HTTPBindingClient.prototype.jsonApply = function(req) { var http = HTTPBindingClient.getHTTPRequest(); var hascb = req.cb? true : false; http.open("POST", this.uri, hascb); - http.setRequestHeader("Content-type", "application/json-rpc"); + http.setRequestHeader("Content-Type", "application/json-rpc"); // Construct call back if we have one if(hascb) { @@ -201,12 +201,18 @@ HTTPBindingClient.prototype.jsonApply = function(req) { var res = null; try { res = HTTPBindingClient.jsonResult(http); + try { + req.cb(res); + } catch(cbe) {} } catch(e) { - req.cb(null, e); + try { + req.cb(null, e); + } catch(cbe) {} } - req.cb(res); } else - req.cb(null, HTTPBindingClient.Exception(http.status, http.statusText)); + try { + req.cb(null, HTTPBindingClient.Exception(http.status, http.statusText)); + } catch(cbe) {} } }; @@ -222,24 +228,137 @@ HTTPBindingClient.prototype.jsonApply = function(req) { throw new HTTPBindingClient.Exception(http.status, http.statusText); }; + /** * REST ATOMPub GET method. */ HTTPBindingClient.prototype.get = function(id, cb) { + var u = this.uri + '/' + id; + var hascb = cb? true : false; + + // Get from local storage first + var item = localStorage.getItem(u); + //log('localStorage.getItem', u, item); + if (item != null && item != '') { + if (!hascb) + return item; + + // Pass local result to callback + try { + cb(item); + } catch (cbe) {} + } + // Connect to the service var http = HTTPBindingClient.getHTTPRequest(); + http.open("GET", u, hascb); + + // Construct call back if we have one + if (hascb) { + http.onreadystatechange = function() { + //log('readystate', http.readyState, 'status', http.status, 'headers', http.getAllResponseHeaders()); + if (http.readyState == 4) { + // Pass result if different from local result + if (http.status == 200) { + + if (http.getResponseHeader("X-Login") != null) { + // Detect redirect to a login page + try { + cb(null, new HTTPBindingClient.Exception(403, 'X-Login')); + } catch(cbe) {} + + } else if (http.responseText == '' || http.getResponseHeader("Content-Type") == null) { + // Report empty response + try { + cb(null, new HTTPBindingClient.Exception(403, 'No-Content')); + } catch(cbe) {} + + } else { + if (item == null || http.responseText != item) { + // Store retrieved entry in local storage + if (http.responseText != null) { + //log('localStorage.setItem', u, http.responseText); + localStorage.setItem(u, http.responseText); + } + try { + cb(http.responseText); + } catch(cbe) {} + } + } + } + else { + // Pass exception if we didn't have a local result + if (item == null) { + try { + cb(null, new HTTPBindingClient.Exception(http.status, http.statusText)); + } catch(cbe) {} + } + } + } + }; + + // Send the request + http.send(null); + return true; + } + + // Send the request and return the result or exception + http.send(null); + if (http.status == 200) { + if (http.getResponseHeader("X-Login") != null) { + + // Detect redirect to a login page + throw new HTTPBindingClient.Exception(403, 'X-Login'); + + } else if (http.responseText == '' || http.getResponseHeader("Content-Type") == null) { + + // Report empty response + throw new HTTPBindingClient.Exception(403, 'No-Content'); + } + return http.responseText; + } + throw new HTTPBindingClient.Exception(http.status, http.statusText); +}; + +/** + * REST ATOMPub GET method, does not use the local cache. + */ +HTTPBindingClient.prototype.getnocache = function(id, cb) { + var u = this.uri + '/' + id; var hascb = cb? true : false; - http.open("GET", this.uri + '/' + id, hascb); + + // Connect to the service + var http = HTTPBindingClient.getHTTPRequest(); + http.open("GET", u, hascb); // Construct call back if we have one if (hascb) { http.onreadystatechange = function() { if (http.readyState == 4) { - // Pass the result or exception - if (http.status == 200) - cb(http.responseText); - else - cb(null, new HTTPBindingClient.Exception(http.status, http.statusText)); + if (http.status == 200) { + + if (http.getResponseHeader("X-Login") != null) { + // Detect redirect to a login page + try { + return cb(null, new HTTPBindingClient.Exception(403, 'X-Login')); + } catch(cbe) {} + + } else if (http.responseText == '' || http.getResponseHeader("Content-Type") == null) { + // Report empty response + try { + return cb(null, new HTTPBindingClient.Exception(403, 'No-Content')); + } catch(cbe) {} + + } else { + try { + cb(http.responseText); + } catch(cbe) {} + } + } else { + try { + cb(null, new HTTPBindingClient.Exception(http.status, http.statusText)); + } catch(cbe) {} + } } }; @@ -250,8 +369,19 @@ HTTPBindingClient.prototype.get = function(id, cb) { // Send the request and return the result or exception http.send(null); - if (http.status == 200) + if (http.status == 200) { + if (http.getResponseHeader("X-Login") != null) { + + // Detect redirect to a login page + throw new HTTPBindingClient.Exception(403, 'X-Login'); + + } else if (http.responseText == '' || http.getResponseHeader("Content-Type") == null) { + + // Report empty response + throw new HTTPBindingClient.Exception(403, 'No-Content'); + } return http.responseText; + } throw new HTTPBindingClient.Exception(http.status, http.statusText); }; @@ -259,6 +389,7 @@ HTTPBindingClient.prototype.get = function(id, cb) { * REST ATOMPub POST method. */ HTTPBindingClient.prototype.post = function (entry, cb) { + // Connect to the service var http = HTTPBindingClient.getHTTPRequest(); var hascb = cb? true : false; @@ -270,10 +401,16 @@ HTTPBindingClient.prototype.post = function (entry, cb) { http.onreadystatechange = function() { // Pass the result or exception if (http.readyState == 4) { - if (http.status == 201) - cb(http.responseText); - else - cb(null, new HTTPBindingClient.Exception(http.status, http.statusText)); + if (http.status == 201) { + try { + cb(http.responseText); + } catch(cbe) {} + } + else { + try { + cb(null, new HTTPBindingClient.Exception(http.status, http.statusText)); + } catch(cbe) {} + } } }; // Send the request @@ -292,10 +429,16 @@ HTTPBindingClient.prototype.post = function (entry, cb) { * REST ATOMPub PUT method. */ HTTPBindingClient.prototype.put = function (id, entry, cb) { + var u = this.uri + '/' + id; + + // Update local storage + localStorage.setItem(u, entry); + //log('localStorage.setItem', u, entry); + // Connect to the service var http = HTTPBindingClient.getHTTPRequest(); var hascb = cb? true : false; - http.open("PUT", this.uri + '/' + id, hascb); + http.open("PUT", u, hascb); http.setRequestHeader("Content-Type", "application/atom+xml"); // Construct call back if we have one @@ -303,10 +446,15 @@ HTTPBindingClient.prototype.put = function (id, entry, cb) { http.onreadystatechange = function() { if (http.readyState == 4) { // Pass any exception - if (http.status == 200) - cb(); - else - cb(new HTTPBindingClient.Exception(http.status, http.statusText)); + if (http.status == 200) { + try { + cb(); + } catch(cbe) {} + } else { + try { + cb(new HTTPBindingClient.Exception(http.status, http.statusText)); + } catch(cbe) {} + } } }; // Send the request @@ -325,20 +473,32 @@ HTTPBindingClient.prototype.put = function (id, entry, cb) { * REST ATOMPub DELETE method. */ HTTPBindingClient.prototype.del = function (id, cb) { + var u = this.uri + '/' + id; + + // Update local storage + localStorage.removeItem(u); + //log('localStorage.removeItem', u); + // Connect to the service var http = HTTPBindingClient.getHTTPRequest(); var hascb = cb? true : false; - http.open("DELETE", this.uri + '/' + id, hascb); + http.open("DELETE", u, hascb); // Construct call back if we have one if (cb) { http.onreadystatechange = function() { if (http.readyState == 4) { // Pass any exception - if (http.status == 200) - cb(); - else - cb(new HTTPBindingClient.Exception(http.status, http.statusText)); + if (http.status == 200) { + try { + cb(); + } catch(cbe) {} + } + else { + try { + cb(new HTTPBindingClient.Exception(http.status, http.statusText)); + } catch(cbe) {} + } } }; // Send the request diff --git a/sca-cpp/trunk/modules/js/htdocs/elemutil.js b/sca-cpp/trunk/modules/js/htdocs/elemutil.js index 1c006e1e7c..37d641f7b3 100644 --- a/sca-cpp/trunk/modules/js/htdocs/elemutil.js +++ b/sca-cpp/trunk/modules/js/htdocs/elemutil.js @@ -29,40 +29,30 @@ var atsign = "'@" * Return true if a value is an element. */ function isElement(v) { - if (!isList(v) || isNil(v) || car(v) != element) - return false; - return true; + return (!(!isList(v) || isNil(v) || car(v) != element)); } /** * Return true if a value is an attribute. */ function isAttribute(v) { - if (!isList(v) || isNil(v) || car(v) != attribute) - return false; - return true; + return (!(!isList(v) || isNil(v) || car(v) != attribute)); } /** * Return the name of an attribute. */ -function attributeName(l) { - return cadr(l); -} +attributeName = cadr; /** * Return the value of an attribute. */ -function attributeValue(l) { - return caddr(l); -} +attributeValue = caddr; /** * Return the name of an element. */ -function elementName(l) { - return cadr(l); -} +elementName = cadr; /** * Return true if an element has children. @@ -74,21 +64,16 @@ function elementHasChildren(l) { /** * Return the children of an element. */ -function elementChildren(l) { - return cddr(l); -} - +elementChildren = cddr; /** * Return true if an element has a value. */ function elementHasValue(l) { - r = reverse(l); + var r = reverse(l); if (isSymbol(car(r))) return false; - if (isList(car(r)) && !isNil(car(r)) && isSymbol(car(car(r)))) - return false; - return true; + return (!(isList(car(r)) && !isNil(car(r)) && isSymbol(car(car(r))))) } /** @@ -127,13 +112,7 @@ function elementToValue(t) { * Convert a list of elements to a list of values. */ function elementToValueIsSymbol(v) { - if (!isList(v)) - return false; - if (isNil(v)) - return false; - if (!isSymbol(car(v))) - return false; - return true; + return (!(!isList(v)) || isNil(v) || !isSymbol(car(v))); } function elementToValueGroupValues(v, l) { diff --git a/sca-cpp/trunk/modules/js/htdocs/ui-min.css b/sca-cpp/trunk/modules/js/htdocs/ui-min.css index c4cdc288a1..c8798583c6 100644 --- a/sca-cpp/trunk/modules/js/htdocs/ui-min.css +++ b/sca-cpp/trunk/modules/js/htdocs/ui-min.css @@ -1,13 +1,17 @@ -body{margin:2px;font-family:"Helvetica Neue", Helvetica;font-style:normal;font-variant:normal;font-size:13px;-webkit-text-size-adjust:none;-webkit-touch-callout:none;-webkit-tap-highlight-color:rgba(0,0,0,0);-webkit-user-select:none;} +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;-webkit-text-size-adjust:none;-webkit-touch-callout:none;-webkit-user-select:none;} .delayed{visibility:hidden;} -.devicewidth{position:absolute;top:0px;left:0px;right:0px;height:5000px;overflow:hidden;} +.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;} +.bodydivloading{position:absolute;top:0px;left:0px;width:100%;height:5000px;overflow:hidden;-webkit-transform:translate(100%, 0px);-webkit-backface-visibility:hidden;-moz-transform:translate(100%, 0px);-ms-transform:translate(100%, 0px);transform:translate(100%, 0px);} +.bodydivloaded{-webkit-transition:-webkit-transform 0.4s linear;-moz-transition:-moz-transform 0.4s linear;-ms-transition:-ms-transform 0.4s linear;transition:transform 0.4s linear;position:absolute;top:0px;left:0px;width:100%;height:5000px;overflow:hidden;-webkit-transform:translate3d(0px, 0px, 0px);-webkit-backface-visibility:hidden;-moz-transform:translate(0px, 0px);-ms-transform:translate(0px, 0px);transform:translate(0px, 0px);} +.bodydivunloaded{-webkit-transition:-webkit-transform 0.4s linear;-moz-transition:-moz-transform 0.4s linear;-ms-transition:-ms-transform 0.4s linear;transition:transform 0.4s linear;position:absolute;top:0px;left:0px;width:100%;height:5000px;overflow:hidden;-webkit-transform:translate3d(-100%, 0px, 0px);-webkit-backface-visibility:hidden;-moz-transform:translate(-100%, 0px);-ms-transform:translate(-100%, 0px);transform:translate(-100%, 0px);} 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;overflow:visible;} .trb{border-bottom:1px;border-bottom-style:solid;border-color:#dcdcdc;} -th{font-weight:bold;background-color:#e5ecf9;color:#000000;height:18px;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;overflow:hidden;} -.section{font-weight:bold;background-color:#e5ecf9;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;overflow:hidden;} -.hsection{width:100%;height:50px;border-top:0px;border-bottom:1px;border-left:0px;border-right:0px;border-style:solid;border-bottom-color:#000000;background-color:#ffffff;padding:0px;margin-bottom:4px;margin-left:auto;margin-right:auto;text-align:center;} -.fsection{width:100%;height:50px;border-top:0px;border-bottom:0px;border-left:0px;border-right:0px;border-style:solid;border-top-color:#a2bae7;padding:0px;margin-top:4px;margin-left:auto;margin-right:auto;text-align:center;} -.text{padding-top:3px;padding-bottom:4px;vertical-align:middle;} +th{font-weight:bold;background-color:#d4e6fc;color:#000000;height:18px;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;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;overflow:hidden;} +.hsection{width:100%;height:50px;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;} +.fsection{width:100%;height:50px;border-top:0px;border-bottom:0px;border-left:0px;border-right:0px;border-style:solid;border-top-color:#a2bae7;padding:0px;margin-top:0px;margin-left:auto;margin-right:auto;text-align:center;} +.text{padding-top:3px;padding-bottom:4px;vertical-align:middle;white-space:nowrap;} .thl{border-left:0px;} .thr{border-right:0px;} .ths{padding:0px;} @@ -26,28 +30,31 @@ iframe{border:0px;margin:0px;padding:0px;} input{vertical-align:middle;font-family:"Helvetica Neue", Helvetica;font-style:normal;font-variant:normal;font-size:13px;-webkit-text-size-adjust:100%;} textarea{font-family:"Helvetica Neue", Helvetica;font-style:normal;font-variant:normal;font-size:13px;overflow:auto;resize:none;} .editable{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%;border:0px;} -a:link{color:#598edd;text-decoration:none;} -a:visited{color:#598edd;text-decoration:none;} -.amenu{color:#598edd;text-decoration:none;} -.smenu{font-weight:bold;color:#000000;text-decoration:none;} -h1{font-size:150%;font-weight:bold;vertical-align:middle;margin-top:5px;margin-bottom:5px;margin-left:2px;margin-right:2px;} -h2{font-size:120%;font-weight:bold;vertical-align:middle;margin-top:5px;margin-bottom:5px;margin-left:2px;margin-right:2px;} -.hd1{font-size:150%;font-weight:bold;} -.hd2{font-size:120%;font-weight:bold;} +a:link{color:#598edd;text-decoration:none;white-space:nowrap;} +a:visited{color:#598edd;text-decoration:none;white-space:nowrap;} +.amenu{color:#598edd;text-decoration:none;white-space:nowrap;} +.smenu{font-weight:bold;color:#000000;text-decoration:none;white-space:nowrap;} +h1{font-size:150%;font-weight:bold;vertical-align:middle;margin-top:5px;margin-bottom:5px;margin-left:2px;margin-right:2px;white-space:nowrap;} +h2{font-size:120%;font-weight:bold;vertical-align:middle;margin-top:5px;margin-bottom:5px;margin-left:2px;margin-right:2px;white-space:nowrap;} +.hd1{font-size:150%;font-weight:bold;white-space:nowrap;} +.hd2{font-size:120%;font-weight:bold;white-space:nowrap;} img{border:0px;} .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;} -.greenbutton{-webkit-border-radius:4px;border-radius:4px;background:#96d333;background:-moz-linear-gradient(top, #f8f8f8 0%, #96d333 100%);background:-webkit-gradient(linear, left top, left bottom, color-stop(0%,#f8f8f8), color-stop(100%,#96d333));filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#f8f8f8', endColorstr='#96d333',GradientType=0);background:-o-linear-gradient(top, #f8f8f8 0%,#96d333 100%);border:1px outset #dcdcdc;padding-left:4px;padding-right:4px;padding-top:2px;padding-bottom:2px;margin:2px;cursor:pointer;} -.tgreenbutton{-webkit-border-radius:4px;border-radius:4px;background:#96d333;background:-moz-linear-gradient(top, #f8f8f8 0%, #96d333 100%);background:-webkit-gradient(linear, left top, left bottom, color-stop(0%,#f8f8f8), color-stop(100%,#96d333));filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#f8f8f8', endColorstr='#96d333',GradientType=0);background:-o-linear-gradient(top, #f8f8f8 0%,#96d333 100%);border:1px outset #dcdcdc;padding-left:4px;padding-right:4px;padding-top:2px;padding-bottom:2px;margin:2px;cursor:pointer;} -.bluebutton{-webkit-border-radius:4px;border-radius:4px;background:#598edd;background:-moz-linear-gradient(top, #f8f8f8 0%, #598edd 100%);background:-webkit-gradient(linear, left top, left bottom, color-stop(0%,#f8f8f8), color-stop(100%,#598edd));filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#f8f8f8', endColorstr='#598edd',GradientType=0);background:-o-linear-gradient(top, #f8f8f8 0%,#598edd 100%);border:1px outset #dcdcdc;padding-left:4px;padding-right:4px;padding-top:2px;padding-bottom:2px;margin:2px;cursor:pointer;} -.redbutton{-webkit-border-radius:4px;border-radius:4px;background:#d03f41;background:-moz-linear-gradient(top, #f8f8f8 0%, #d03f41 100%);background:-webkit-gradient(linear, left top, left bottom, color-stop(0%,#f8f8f8), color-stop(100%,#d03f41));filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#f8f8f8', endColorstr='#d03f41',GradientType=0);background:-o-linear-gradient(top, #f8f8f8 0%,#d03f41 100%);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 100%);background:-webkit-gradient(linear, left top, left bottom, color-stop(0%,#f8f8f8), color-stop(100%,#ffbb00));filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#f8f8f8', endColorstr='#ffbb00',GradientType=0);background:-o-linear-gradient(top, #f8f8f8 0%,#ffbb00 100%);border:1px outset #dcdcdc;padding-left:4px;padding-right:4px;padding-top:2px;padding-bottom:2px;margin:2px;cursor:pointer;} -.graybutton{-webkit-border-radius:4px;border-radius:4px;background:#dcdcdc;background:-moz-linear-gradient(top, #f8f8f8 0%, #dcdcdc 100%);background:-webkit-gradient(linear, left top, left bottom, color-stop(0%,#f8f8f8), color-stop(100%,#dcdcdc));filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#f8f8f8', endColorstr='#dcdcdc',GradientType=0);background:-o-linear-gradient(top, #f8f8f8 0%,#dcdcdc 100%);border:1px outset #dcdcdc;padding-left:4px;padding-right:4px;padding-top:2px;padding-bottom:2px;margin:2px;margin:2px;cursor:pointer;} -.tbar{margin:0px;width:100%;padding-top:0px;padding-left:0px;padding-right:0px;padding-bottom:3px;border-bottom:1px solid #a2bae7;border-collapse:separate;} -.ltbar{padding-left:2px;padding-top:2px;padding-right:6px;white-space:nowrap;vertical-align:middle;} -.dtbar{padding-left:0px;padding-right:0px;padding-top:2px;white-space:nowrap;vertical-align:middle;text-align:right;} -.rtbar{padding-left:6px;padding-right:2px;padding-top:2px;white-space:nowrap;vertical-align:middle;text-align:right;} -.suggest{background-color:#e5ecf9;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;} +.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;} +.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;} +.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;} +.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;} +.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;} +.tbar{margin:0px;width:100%;padding-top:0px;padding-left:0px;padding-right:0px;padding-bottom:0px;border-collapse:separate;background-color:#2c2c2c;} +.ltbar{padding-left:2px;padding-right:6px;padding-top:3px;padding-bottom:4px;white-space:nowrap;vertical-align:middle;} +.dtbar{padding-left:0px;padding-right:0px;padding-top:3px;padding-bottom:4px;white-space:nowrap;vertical-align:middle;text-align:right;} +.rtbar{padding-left:6px;padding-right:2px;padding-top:3px;padding-bottom:4px;white-space:nowrap;vertical-align:middle;text-align:right;} +.tbaramenu{color:#cccccc;text-decoration:none;white-space:nowrap;} +.tbarsmenu{font-weight:bold;color:#ffffff;text-decoration:none;white-space:nowrap;} +.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;} .suggestTable{border:0px;border-collapse:separate;padding-left:5px;padding-right:5px;padding-top:2px;padding-bottom:2px;margin:0px;} -.suggestItem{padding-left:2px;padding-top:0px;padding-bottom:0px;padding-right:2px;vertical-align:middle;background-color:#e5ecf9;color:#598edd;} -.suggestHilighted{padding-left:2px;padding-top:0px;padding-bottom:0px;padding-right:2px;vertical-align:middle;background-color:#598edd;color:#e5ecf9;}
\ No newline at end of file +.suggestItem{padding-left:2px;padding-top:0px;padding-bottom:0px;padding-right:2px;vertical-align:middle;background-color:#d4e6fc;color:#598edd;} +.suggestHilighted{padding-left:2px;padding-top:0px;padding-bottom:0px;padding-right:2px;vertical-align:middle;background-color:#598edd;color:#d4e6fc;} +.svgtitle{margin:0px;padding:0px;font-family:"Helvetica Neue", Helvetica;font-style:normal;font-variant:normal;font-size:10px;cursor:default;}
\ No newline at end of file diff --git a/sca-cpp/trunk/modules/js/htdocs/ui.css b/sca-cpp/trunk/modules/js/htdocs/ui.css index 0842523bf2..b4c27a54e8 100644 --- a/sca-cpp/trunk/modules/js/htdocs/ui.css +++ b/sca-cpp/trunk/modules/js/htdocs/ui.css @@ -18,10 +18,10 @@ */ body { -margin: 2px; font-family: "Helvetica Neue", Helvetica; font-style: normal; font-variant: normal; font-size: 13px; +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; -webkit-text-size-adjust: none; -webkit-touch-callout: none; --webkit-tap-highlight-color: rgba(0,0,0,0); -webkit-user-select: none; } @@ -30,7 +30,43 @@ visibility: hidden; } .devicewidth { -position: absolute; top: 0px; left: 0px; right: 0px; height: 5000px; overflow: hidden; +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; +} + +.bodydivloading { +position: absolute; top: 0px; left: 0px; width: 100%; height: 5000px; overflow: hidden; +-webkit-transform: translate(100%, 0px); -webkit-backface-visibility: hidden; +-moz-transform: translate(100%, 0px); +-ms-transform: translate(100%, 0px); +transform: translate(100%, 0px); +} + +.bodydivloaded { +-webkit-transition: -webkit-transform 0.4s linear; +-moz-transition: -moz-transform 0.4s linear; +-ms-transition: -ms-transform 0.4s linear; +transition: transform 0.4s linear; +position: absolute; top: 0px; left: 0px; width: 100%; height: 5000px; overflow: hidden; +-webkit-transform: translate3d(0px, 0px, 0px); -webkit-backface-visibility: hidden; +-moz-transform: translate(0px, 0px); +-ms-transform: translate(0px, 0px); +transform: translate(0px, 0px); +} + +.bodydivunloaded { +-webkit-transition: -webkit-transform 0.4s linear; +-moz-transition: -moz-transform 0.4s linear; +-ms-transition: -ms-transform 0.4s linear; +transition: transform 0.4s linear; +position: absolute; top: 0px; left: 0px; width: 100%; height: 5000px; overflow: hidden; +-webkit-transform: translate3d(-100%, 0px, 0px); -webkit-backface-visibility: hidden; +-moz-transform: translate(-100%, 0px); +-ms-transform: translate(-100%, 0px); +transform: translate(-100%, 0px); } table { @@ -44,31 +80,31 @@ border-bottom: 1px; border-bottom-style: solid; border-color: #dcdcdc; } th { -font-weight: bold; background-color: #e5ecf9; color: #000000; height: 18px; +font-weight: bold; background-color: #d4e6fc; color: #000000; height: 18px; 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; overflow: hidden; } .section { -font-weight: bold; background-color: #e5ecf9; color: #000000; height: 24px; padding-top: 1px; padding-bottom: 0px; padding-left: 2px; padding-right: 2px; +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; overflow: hidden; } .hsection { width: 100%; height: 50px; -border-top: 0px; border-bottom: 1px; border-left: 0px; border-right: 0px; border-style: solid; border-bottom-color: #000000; background-color: #ffffff; -padding: 0px; margin-bottom: 4px; margin-left: auto; margin-right: auto; text-align: center; +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; } .fsection{ width: 100%; height: 50px; border-top: 0px; border-bottom: 0px; border-left: 0px; border-right: 0px; border-style: solid; border-top-color: #a2bae7; -padding: 0px; margin-top: 4px; margin-left: auto; margin-right: auto; text-align: center; +padding: 0px; margin-top: 0px; margin-left: auto; margin-right: auto; text-align: center; } .text { -padding-top: 3px; padding-bottom: 4px; vertical-align: middle; +padding-top: 3px; padding-bottom: 4px; vertical-align: middle; white-space: nowrap; } .thl { @@ -156,35 +192,35 @@ border: 0px; } a:link { -color: #598edd; text-decoration: none; +color: #598edd; text-decoration: none; white-space: nowrap; } a:visited { -color: #598edd; text-decoration: none; +color: #598edd; text-decoration: none; white-space: nowrap; } .amenu { -color: #598edd; text-decoration: none; +color: #598edd; text-decoration: none; white-space: nowrap; } .smenu { -font-weight: bold; color: #000000; text-decoration: none; +font-weight: bold; color: #000000; text-decoration: none; white-space: nowrap; } h1 { -font-size: 150%; font-weight: bold; vertical-align: middle; margin-top: 5px; margin-bottom: 5px; margin-left: 2px; margin-right: 2px; +font-size: 150%; font-weight: bold; vertical-align: middle; margin-top: 5px; margin-bottom: 5px; margin-left: 2px; margin-right: 2px; white-space: nowrap; } h2 { -font-size: 120%; font-weight: bold; vertical-align: middle; margin-top: 5px; margin-bottom: 5px; margin-left: 2px; margin-right: 2px; +font-size: 120%; font-weight: bold; vertical-align: middle; margin-top: 5px; margin-bottom: 5px; margin-left: 2px; margin-right: 2px; white-space: nowrap; } .hd1 { -font-size: 150%; font-weight: bold; +font-size: 150%; font-weight: bold; white-space: nowrap; } .hd2 { -font-size: 120%; font-weight: bold; +font-size: 120%; font-weight: bold; white-space: nowrap; } img { @@ -206,10 +242,10 @@ padding-left: 0px; padding-right: 0px; padding-top: 0px; padding-bottom: 0px; -webkit-border-radius: 4px; border-radius: 4px; background: #96d333; -background: -moz-linear-gradient(top, #f8f8f8 0%, #96d333 100%); -background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#f8f8f8), color-stop(100%,#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 100%); +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; @@ -219,10 +255,10 @@ cursor: pointer; -webkit-border-radius: 4px; border-radius: 4px; background: #96d333; -background: -moz-linear-gradient(top, #f8f8f8 0%, #96d333 100%); -background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#f8f8f8), color-stop(100%,#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 100%); +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; @@ -232,10 +268,10 @@ cursor: pointer; -webkit-border-radius: 4px; border-radius: 4px; background: #598edd; -background: -moz-linear-gradient(top, #f8f8f8 0%, #598edd 100%); -background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#f8f8f8), color-stop(100%,#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 100%); +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; @@ -245,10 +281,10 @@ cursor: pointer; -webkit-border-radius: 4px; border-radius: 4px; background: #d03f41; -background: -moz-linear-gradient(top, #f8f8f8 0%, #d03f41 100%); -background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#f8f8f8), color-stop(100%,#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 100%); +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; @@ -258,10 +294,10 @@ cursor: pointer; -webkit-border-radius: 4px; border-radius: 4px; background: #ffbb00; -background: -moz-linear-gradient(top, #f8f8f8 0%, #ffbb00 100%); -background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#f8f8f8), color-stop(100%,#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 100%); +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; @@ -271,10 +307,10 @@ cursor: pointer; -webkit-border-radius: 4px; border-radius: 4px; background: #dcdcdc; -background: -moz-linear-gradient(top, #f8f8f8 0%, #dcdcdc 100%); -background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#f8f8f8), color-stop(100%,#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 100%); +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; @@ -282,23 +318,32 @@ cursor: pointer; } .tbar { -margin: 0px; width: 100%; padding-top: 0px; padding-left: 0px; padding-right: 0px; padding-bottom: 3px; border-bottom: 1px solid #a2bae7; border-collapse: separate; +margin: 0px; width: 100%; padding-top: 0px; padding-left: 0px; padding-right: 0px; padding-bottom: 0px; border-collapse: separate; +background-color: #2c2c2c; } .ltbar { -padding-left: 2px; padding-top: 2px; padding-right: 6px; white-space: nowrap; vertical-align: middle; +padding-left: 2px; padding-right: 6px; padding-top: 3px; padding-bottom: 4px; white-space: nowrap; vertical-align: middle; } .dtbar { -padding-left: 0px; padding-right: 0px; padding-top: 2px; white-space: nowrap; vertical-align: middle; text-align: right; +padding-left: 0px; padding-right: 0px; padding-top: 3px; padding-bottom: 4px; white-space: nowrap; vertical-align: middle; text-align: right; } .rtbar { -padding-left: 6px; padding-right: 2px; padding-top: 2px; white-space: nowrap; vertical-align: middle; text-align: right; +padding-left: 6px; padding-right: 2px; padding-top: 3px; padding-bottom: 4px; white-space: nowrap; vertical-align: middle; text-align: right; +} + +.tbaramenu { +color: #cccccc; text-decoration: none; white-space: nowrap; +} + +.tbarsmenu { +font-weight: bold; color: #ffffff; text-decoration: none; white-space: nowrap; } .suggest { -background-color: #e5ecf9; color: #598edd; +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; @@ -309,10 +354,14 @@ border: 0px; border-collapse: separate; padding-left: 5px; padding-right: 5px; p } .suggestItem { -padding-left: 2px; padding-top: 0px; padding-bottom: 0px; padding-right: 2px; vertical-align: middle; background-color: #e5ecf9; color: #598edd; +padding-left: 2px; padding-top: 0px; padding-bottom: 0px; padding-right: 2px; vertical-align: middle; background-color: #d4e6fc; color: #598edd; } .suggestHilighted { -padding-left: 2px; padding-top: 0px; padding-bottom: 0px; padding-right: 2px; vertical-align: middle; background-color: #598edd; color: #e5ecf9; +padding-left: 2px; padding-top: 0px; padding-bottom: 0px; padding-right: 2px; vertical-align: middle; background-color: #598edd; color: #d4e6fc; +} + +.svgtitle { +margin: 0px; padding: 0px; font-family: "Helvetica Neue", Helvetica; font-style: normal; font-variant: normal; font-size: 10px; cursor: default; } diff --git a/sca-cpp/trunk/modules/js/htdocs/ui.js b/sca-cpp/trunk/modules/js/htdocs/ui.js index b5843d8916..7c079e3089 100644 --- a/sca-cpp/trunk/modules/js/htdocs/ui.js +++ b/sca-cpp/trunk/modules/js/htdocs/ui.js @@ -29,7 +29,7 @@ var ui = {}; ui.ahref = function(loc, target, html) { if (target == '_blank') return '<a href="' + loc + '" target="_blank">' + html + '</a>'; - return '<a href="javascript:void(0)" onclick="window.open(\'' + loc + '\', \'' + target + '\');">' + html + '</a>'; + return '<a href="javascript:void(0)" onclick="ui.navigate(\'' + loc + '\', \'' + target + '\');">' + html + '</a>'; }; /** @@ -43,6 +43,9 @@ ui.menu = function(name, href, target) { this.content = function() { function complete(uri) { + var h = uri.indexOf('#'); + if (h != -1) + return complete(uri.substr(0, h)); var q = uri.indexOf('?'); if (q != -1) return complete(uri.substr(0, q)); @@ -54,8 +57,8 @@ ui.menu = function(name, href, target) { } if (complete(this.href) != complete(window.top.location.pathname)) - return ui.ahref(this.href, this.target, '<span class="amenu">' + this.name + '</span>'); - return ui.ahref(this.href, this.target, '<span class="smenu">' + this.name + '</span>'); + return ui.ahref(this.href, this.target, '<span class="tbaramenu">' + this.name + '</span>'); + return ui.ahref(this.href, this.target, '<span class="tbarsmenu">' + this.name + '</span>'); }; } return new Menu(name, href, target); @@ -179,17 +182,6 @@ ui.suggest = function(input, suggestFunction) { }; /** - * Return the content document of a window. - */ -ui.content = function(win) { - if (!isNil(win.document)) - return win.document; - if (!isNil(win.contentDocument)) - return win.contentDocument; - return null; -}; - -/** * Return a child element of a node with the given id. */ ui.elementByID = function(node, id) { @@ -231,39 +223,165 @@ ui.queryParams = function() { }; /** + * Return a dictionary of the fragment parameters. + */ +ui.fragmentParams = function() { + var qp = new Array(); + var qs = window.location.hash.substring(1).split('&'); + for (var i = 0; i < qs.length; i++) { + var e = qs[i].indexOf('='); + if (e > 0) + qp[qs[i].substring(0, e)] = unescape(qs[i].substring(e + 1)); + } + return qp; +}; + +/** * Return true if the client is a mobile device. */ +ui.mobiledetected = false; +ui.mobile = false; ui.isMobile = function() { + if (ui.mobiledetected) + return ui.mobile; var ua = navigator.userAgent; if (ua.match(/iPhone/i) || ua.match(/iPad/i) || ua.match(/Android/i) || ua.match(/Blackberry/i) || ua.match(/WebOs/i)) - return true; - return false; + ui.mobile = true; + ui.mobiledetected = true; + return ui.mobile; }; /** - * Initialize a document after it's loaded. + * Initialize a document's body. + */ +ui.pagetransitions = false; + +ui.initbody = function() { + if (ui.isMobile()) { + //log('init', window.location); + + // Position the main body div off screen + if (ui.pagetransitions) { + var bdiv = $('bodydiv'); + if (!isNil(bdiv)) { + bdiv.className = 'bodydivloading'; + } + } + + // Install orientation handler + document.body.onorientationchange = ui.onorientationchange; + } + return true; +} + +/** + * Reload the current document when orientation changes. + */ +ui.onorientationchange = function() { + window.open(window.location, '_self'); + return true; +} + +/** + * Post process a document after it's loaded. */ ui.onload = function() { - // Make the document visible - document.body.style.visibility = 'visible'; + // Save the current page location in local storage + // (except for login and logout pages) + var path = document.location.pathname; + if (path.indexOf('/login/') != 0 && path.indexOf('/logout/') != 0) + localStorage.setItem('ui.lastvisited', '' + document.location); - // Install orientation handler - document.body.onorientationchange = function() { - window.open(window.location, '_self'); - return true; - }; + // Make the document body visible + //log('visible', $('bodydiv').className); + document.body.style.visibility = 'visible'; + if (ui.pagetransitions && ui.isMobile()) { + //log('onload', window.location); + + // Slide the main body div in + setTimeout(function() { + var bdiv = $('bodydiv'); + if (!isNil(bdiv)) { + function transitionend(e) { + bdiv.removeEventListener('webkitTransitionEnd', transitionend, false); + bdiv.removeEventListener('transitionend', transitionend, false); + bdiv.className = 'bodydiv'; + //log('loadtransitionend', window.location); + }; + bdiv.addEventListener('webkitTransitionEnd', transitionend, false); + bdiv.addEventListener('transitionend', transitionend, false); + //log('loadtransitionstart', window.location); + bdiv.className = 'bodydivloaded'; + } + }, 0); + } return true; }; /** + * Navigate to a new document. + */ +ui.navigate = function(url, win) { + + function opendoc(url, win) { + if (win == '_reload') { + window.location = url; + return window.location.reload(); + } + return window.open(url, win); + } + + if (ui.pagetransitions && ui.isMobile() && win != '_blank') { + + // Slide the main body div out, then open the new document + var bdiv = $('bodydiv'); + if (!isNil(bdiv)) { + function transitionend(e) { + bdiv.removeEventListener('webkitTransitionEnd', transitionend, false); + bdiv.removeEventListener('transitionend', transitionend, false); + //log('navigatetransitionend', window.location); + return opendoc(url, win); + }; + bdiv.addEventListener('webkitTransitionEnd', transitionend, false); + bdiv.addEventListener('transitionend', transitionend, false); + //log('navigatetransitionstart', window.location); + bdiv.className = 'bodydivunloaded'; + return true; + } + } + + return opendoc(url, win); +} + +/** + * Pre process a document just before it's unloaded. + */ +ui.onbeforeunload = function() { + + if (ui.pagetransitions && ui.isMobile()) { + + // Slide the main body div out + var bdiv = $('bodydiv'); + if (!isNil(bdiv)) + bdiv.className = 'bodydivunloaded'; + } +}; + + +/** + * Return the last visited page. + */ +ui.lastvisited = function() { + return localStorage.getItem('ui.lastvisited'); +} + +/** * Convert a CSS position to a numeric position. */ ui.numpos = function(p) { - if (p == '') - return 0; - return Number(p.substr(0, p.length - 2)); + return p == ''? 0 : Number(p.substr(0, p.length - 2)); }; /** diff --git a/sca-cpp/trunk/modules/js/htdocs/util.js b/sca-cpp/trunk/modules/js/htdocs/util.js index 4c09b2b13c..fd7005e9c7 100644 --- a/sca-cpp/trunk/modules/js/htdocs/util.js +++ b/sca-cpp/trunk/modules/js/htdocs/util.js @@ -35,7 +35,7 @@ function car(l) { } function first(l) { - return car(l); + return l[0]; } function cdr(l) { @@ -43,27 +43,27 @@ function cdr(l) { } function rest(l) { - return cdr(l); + return l.slice(1); } function cadr(l) { - return car(cdr(l)); + return l[1]; } function cddr(l) { - return cdr(cdr(l)); + return l.slice(2); } function caddr(l) { - return car(cddr(l)); + return l[2]; } function cdddr(l) { - return cdr(cdr(cdr(l))); + return l.slice(3); } function cadddr(l) { - return car(cdddr(l)); + return l[3]; } function append(a, b) { @@ -82,33 +82,23 @@ function range(a, b) { } function isNil(v) { - if (v == null || typeof v == 'undefined' || (v.constructor == Array && v.length == 0)) - return true; - return false; + return (v == null || typeof v == 'undefined' || (v.constructor == Array && v.length == 0)); } function isSymbol(v) { - if (typeof v == 'string' && v.slice(0, 1) == "'") - return true; - return false; + return (typeof v == 'string' && v.slice(0, 1) == "'"); } function isString(v) { - if (typeof v == 'string' && v.slice(0, 1) != "'") - return true; - return false; + return (typeof v == 'string' && v.slice(0, 1) != "'"); } function isList(v) { - if (v != null && typeof v != 'undefined' && v.constructor == Array) - return true; - return false; + return (v != null && typeof v != 'undefined' && v.constructor == Array); } function isTaggedList(v, t) { - if (isList(v) && !isNil(v) && car(v) == t) - return true; - return false; + return (isList(v) && !isNil(v) && car(v) == t); } var emptylist = new Array(); @@ -131,10 +121,13 @@ function length(l) { */ function assoc(k, l) { if (isNil(l)) - return mklist(); - if (k == car(car(l))) - return car(l); - return assoc(k, cdr(l)); + return emptylist; + var n = l.length; + for(var i = 0; i < n; i++) { + if (k == car(l[i])) + return l[i]; + } + return emptylist; } /** @@ -143,15 +136,24 @@ function assoc(k, l) { function map(f, l) { if (isNil(l)) return l; - return cons(f(car(l)), map(f, cdr(l))); + var n = l.length; + var a = new Array(); + for(var i = 0; i < n; i++) { + a.push(f(l[i])); + } + return a; } function filter(f, l) { if (isNil(l)) return l; - if (f(car(l))) - return cons(car(l), filter(f, cdr(l))); - return filter(f, cdr(l)); + var n = l.length; + var a = new Array(); + for(var i = 0; i < n; i++) { + if (f(l[i])) + a.push(l[i]); + } + return a; } function reduce(f, i, l) { @@ -245,7 +247,12 @@ function assert(exp) { function writeStrings(l) { if (isNil(l)) return ''; - return car(l) + writeStrings(cdr(l)); + var s = ''; + var n = l.length; + for(var i = 0; i < n; i++) { + s = s + l[i]; + } + return s; } /** |