diff options
author | jsdelfino <jsdelfino@13f79535-47bb-0310-9956-ffa450edef68> | 2011-08-06 05:59:32 +0000 |
---|---|---|
committer | jsdelfino <jsdelfino@13f79535-47bb-0310-9956-ffa450edef68> | 2011-08-06 05:59:32 +0000 |
commit | 3b3beac5adfa1995a9a4c92fd92a881f024be08e (patch) | |
tree | d958076da28db597359af0ae27db369925e253e4 /sca-cpp/trunk/modules/edit | |
parent | 4b14cefc9e79850ebb18844752771c3f141c7385 (diff) |
Javascript improvements: add local storage, improve caching using URI fragments instead of query strings, simplify component layout and optimize some of the Javascript functions, and add the ability to clone components.
git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@1154447 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'sca-cpp/trunk/modules/edit')
23 files changed, 1204 insertions, 759 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 |