diff options
author | giorgio <giorgio@13f79535-47bb-0310-9956-ffa450edef68> | 2012-09-05 08:31:30 +0000 |
---|---|---|
committer | giorgio <giorgio@13f79535-47bb-0310-9956-ffa450edef68> | 2012-09-05 08:31:30 +0000 |
commit | c9bfccc35345ce58fb5774d4b0b6a9868b262c0a (patch) | |
tree | fe84dd4b90f2acd0b933550b6978094926c1d733 /sca-cpp/branches/lightweight-sca/hosting/server/htdocs/page/index.html | |
parent | 5ddabdaf1ff856aae79dadc045ef2aeff08c7887 (diff) |
git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@1381061 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to '')
-rw-r--r-- | sca-cpp/branches/lightweight-sca/hosting/server/htdocs/page/index.html | 1081 |
1 files changed, 1081 insertions, 0 deletions
diff --git a/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/page/index.html b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/page/index.html new file mode 100644 index 0000000000..6a6e042c74 --- /dev/null +++ b/sca-cpp/branches/lightweight-sca/hosting/server/htdocs/page/index.html @@ -0,0 +1,1081 @@ +<!DOCTYPE html> +<!-- + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. +--> +<div id="bodydiv" class="body"> + +<div id="contentdiv" class="viewcontent" style="width: 2500px;"> +<div id="pagediv" class="pagediv" style="top: 0px; left: -2500px; width: 5000px; height: 5000px;"> + +<!-- +<div class="guide" style="position: absolute; left: 2500px; top: 0px; width: 320px; height: 460px;"></div> +<div class="guide" style="position: absolute; left: 2500px; top: 0px; width: 480px; height: 300px;"></div> +<div class="guide" style="position: absolute; left: 2500px; top: 0px; width: 768px; height: 911px;"></div> +<div class="guide" style="position: absolute; left: 2500px; top: 0px; width: 1024px; height: 655px;"></div> +--> + +<span class="h1" id="palette:h1" style="position: absolute; left: 0px; top: 0px;"><h1>Header Level 1</h1></span> +<span class="h2" id="palette:h2" style="position: absolute; left: 0px; top: 30px;"><h2>Header Level 2</h2></span> +<span class="section" id="palette:section" style="position: absolute; left: 0px; top: 60px; width: 220px;"><span class="Section">Section</span></span> +<span class="text" id="palette:text" style="position: absolute; left: 0px; top: 90px;"><span>Some text</span></span> +<span class="link" id="palette:link" style="position: absolute; left: 80px; top: 90px;"><a href="/"><span>Link</span></a></span> +<span class="button" id="palette:graybutton" style="position: absolute; left: 0px; top: 120px;"><input type="button" value="Button" class="graybutton"/></span> +<span class="button" id="palette:bluebutton" style="position: absolute; left: 80px; top: 120px;"><input type="button" value="Button" class="graybutton bluebutton"/></span> +<span class="button" id="palette:redbutton" style="position: absolute; left: 160px; top: 120px;"><input type="button" value="Button" class="graybutton redbutton"/></span> +<span class="entry" id="palette:entry" style="position: absolute; left: 0px; top: 160px;"><input type="text" value="Entry Field" class="flatentry" size="20" autocapitalize="off"/></span> +<span class="password" id="palette:password" style="position: absolute; left: 0px; top: 190px;"><input type="password" value="Password" class="flatentry" size="20"/></span> +<span class="checkbox" id="palette:checkbox" style="position: absolute; left: 0px; top: 220px;"><input type="checkbox" value="Checkbox" class="flatcheckbox"/><span>Checkbox</span></span> +<!-- +<span class="select" id="palette:select" style="position: absolute; left: 80px; top: 220px;"><select><option value="select">Selection</option></select></span> +--> +<span class="list" id="palette:list" style="position: absolute; left: 0px; top: 250px; width: 220px;"> +<table class="datatable" style="width: 220px;"> +<tr><td class="datatd">List</td></tr> +<tr><td class="datatd">List</td></tr> +<tr><td class="datatd">List</td></tr> +</table> +</span> +<span class="table" id="palette:table" style="position: absolute; left: 0px; top: 320px; width: 220px;"> +<table class="datatable" style="width: 220px;"> +<tr><td class="datatdl">Table</td><td class="datatdr">Table</td></tr> +<tr><td class="datatdl">Table</td><td class="datatdr">Table</td></tr> +<tr><td class="datatdl">Table</td><td class="datatdr">Table</td></tr> +</table> +</span> +<!-- +<span class="iframe fakeframe" id="palette:iframe" style="position: absolute; left: 0px; top: 380px; width: 200px;"><a href="/public/iframe-min.html"><span class="fakeframe"><span>Frame ...</span></span></a></span> +--> +<span class="img" id="palette:img" style="position: absolute; left: 0px; top: 410px;"><img id="imgimg"/></span> +</div> + +<div id="playdiv" style="visibility: hidden; position: absolute; top: 0px; left: 0px; width: 2500px; height: 5000px;"> +</div> + +</div> + +<div id="buffer" style="visibility: hidden; width: 0px; height: 0px"></div> + +<script type="text/javascript"> +(function() { + +/** + * Get the current app name. + */ +var appname = ui.fragmentParams(location)['app']; + +/** + * Return the link to an app. + */ +function applink(appname) { + var protocol = location.protocol; + var host = location.hostname; + var port = ':' + location.port; + if (port == ':80' || port == ':443' || port == ':') + port = ''; + var link = protocol + '//' + host + port + '/' + appname + '/'; + return link; +} + +/** + * Set page titles. + */ +document.title = config.windowtitle() + ' - Page - ' + appname; + +/** + * Set header div. + */ +$('viewhead').innerHTML = '<span id="appTitle" class="cmenu">' + appname + '</span>' + +'<input type="button" id="deleteWidgetButton" title="Delete a Widget" class="graybutton redbutton plusminus" style="position: absolute; top: 4px; left: 5px;" disabled="true" value="-"/>' + +'<span style="position: absolute; top: 0px; left: 45px; right: 115px; padding: 0px; background: transparent;"><input id="widgetValue" type="text" value="" class="flatentry" title="Widget value" autocapitalize="off" placeholder="Value" style="position: absolute; left: 0px; top: 4px; width: 100%; visibility: hidden;" readonly="readonly"/></span>' + +'<input type="button" id="playPageButton" title="View page" class="graybutton plusminus" style="position: absolute; top: 4px; right: 75px;" value=">"/>' + +'<input type="button" id="copyWidgetButton" title="Copy a Widget" class="graybutton bluebutton" style="position: absolute; top: 4px; right: 40px; font-size: 16px;" disabled="true" value="C"/>' + +'<input type="button" id="addWidgetButton" title="Add a Widget" class="graybutton bluebutton plusminus" style="position: absolute; top: 4px; right: 5px;" disabled="true" value="+"/>'; + +/** + * Track the current page, author, and saved XHTML content. + */ +var author = ''; +var editable = false; +var savedpagexhtml = ''; + +/** + * Page editor area, widget value field, add, delete and play page buttons. + */ +var cdiv = $('contentdiv'); +var pagediv = $('pagediv'); +var evisible = true; +var pdiv = $('playdiv'); +var wadd = $('addWidgetButton'); +var wdelete = $('deleteWidgetButton'); +var wcopy = $('copyWidgetButton'); +var wvalue = $('widgetValue'); +var atitle = $('appTitle'); +var pplay = $('playPageButton'); + +/** + * Set images. + */ +$('imgimg').src = ui.b64img(appcache.get('/public/img.b64')); + +/** + * Init component references. + */ +var editorComp = sca.component('Editor'); +var pages = sca.reference(editorComp, 'pages'); + +/** + * Page editing functions. + */ +var page = {}; + +/** + * Default positions and sizes. + */ +page.palcx = 2500; + +/** + * Init a page editor. + */ +page.mkedit = function(pagediv, atitle, wvalue, wadd, wcopy, wdelete, onchange, onselect) { + + // Track element dragging and selection + page.dragging = null; + page.selected = null; + wvalue.readOnly = true; + wvalue.style.visibility = 'hidden'; + atitle.style.visibility = 'visible'; + page.mousemoved = false; + wcopy.disabled = true; + wdelete.disabled = true; + wadd.disabled = !editable; + + // Trigger widget select and page change events + page.onpagechange = onchange; + page.onselectwidget = onselect; + + /** + * Handle a mouse down event. + */ + function onmousedown(e) { + // On mouse controlled devices, run component selection logic right away + var selected = page.selected; + if (typeof e.touches == 'undefined') { + //debug('onmousedown-click'); + onclick(e); + } + + // Find a draggable element + var dragging = page.draggable(e.target, pagediv); + if (dragging == null || dragging != page.selected) + return true; + page.dragging = dragging; + + // Remember mouse position + var pos = typeof e.touches != "undefined"? e.touches[0] : e; + page.mousemoved = false; + page.dragX = pos.screenX; + page.dragY = pos.screenY; + page.moveX = pos.screenX; + page.moveY = pos.screenY; + + // Prevent default behavior on first click on a widget + if (e.preventDefault) + e.preventDefault(); + else + e.returnValue = false; + + return true; + } + + if (!ui.isMobile()) { + pagediv.onmousedown = function(e) { + //debug('onmousedown'); + return onmousedown(e); + }; + } else { + pagediv.ontouchstart = function(e) { + //debug('ontouchstart'); + return onmousedown(e); + }; + } + + /** + * Handle a mouse up event. + */ + function onmouseup(e) { + if (page.dragging == null) + return true; + + // Snap to grid + var newX = page.gridsnap(ui.numpos(page.dragging.style.left)); + var newY = page.gridsnap(ui.numpos(page.dragging.style.top)); + page.dragging.style.left = ui.pixpos(newX); + page.dragging.style.top = ui.pixpos(newY); + + // Fixup widget style + page.initwidget(page.dragging); + + // Forget dragged element + page.dragging = null; + + // Trigger page change event + page.onpagechange(false); + + // Simulate onclick event + onclick(e); + + return true; + } + + if (!ui.isMobile()) { + pagediv.onmouseup = function(e) { + //debug('onmouseup'); + return onmouseup(e); + }; + } else { + pagediv.ontouchend = function(e) { + //debug('ontouchend'); + return onmouseup(e); + } + } + + /** + * Handle a mouse move event. + */ + function onmousemove(e) { + + // Track mouse moves + page.mousemoved = true; + + if (page.dragging == null) + return true; + + // Ignore duplicate mouse move events + if (page.moveX == page.dragX && page.moveY == page.dragY) + return true; + + // Compute position of dragged element + var curX = ui.numpos(page.dragging.style.left); + var curY = ui.numpos(page.dragging.style.top); + var newX = curX + (page.moveX - page.dragX); + var newY = curY + (page.moveY - page.dragY); + if (newX >= page.palcx) + page.dragX = page.moveX; + else + newX = page.palcx; + if (newY >= 0) + page.dragY = page.moveY; + else + newY = 0; + + // Move the dragged element + page.dragging.style.left = ui.pixpos(newX); + page.dragging.style.top = ui.pixpos(newY); + page.constrainwidget(page.dragging); + + return true; + } + + if (!ui.isMobile()) { + window.onmousemove = function(e) { + + // Remember mouse position + page.moveX = e.screenX; + page.moveY = e.screenY; + + return onmousemove(e); + }; + } else { + pagediv.ontouchmove = function(e) { + + // Remember touch position + var pos = e.touches[0]; + if (page.moveX == pos.screenX && page.moveY == pos.screenY) + return true; + page.moveX = pos.screenX; + page.moveY = pos.screenY; + if (page.moveX == page.dragX && page.moveY == page.dragY) + return true; + + onmousemove(e); + }; + } + + /** + * Handle a mouse click event. + */ + function onclick(e) { + + // Find selected element + var selected = page.draggable(e.target, pagediv); + if (selected == null) { + if (page.selected != null) { + + // Reset current selection + page.selectwidget(page.selected, false, atitle, wvalue, wcopy, wdelete); + page.selected = null; + + // Trigger widget select event + page.onselectwidget(null); + } + + // Dismiss the palette + if (ui.numpos(pagediv.style.left) != (page.palcx * -1)) + pagediv.style.left = ui.pixpos(page.palcx * -1); + + return true; + } + + // Deselect the previously selected element + page.selectwidget(page.selected, false, atitle, wvalue, wcopy, wdelete); + + // Clone element dragged from palette + if (selected.id.substring(0, 8) == 'palette:') { + page.selected = page.clone(selected); + + // Move into the editing area and hide the palette + page.selected.style.left = ui.pixpos(ui.numpos(page.selected.style.left) + page.palcx); + page.initwidget(page.selected); + pagediv.style.left = ui.pixpos(page.palcx * -1); + page.constrainwidget(page.selected); + + // Bring it to the top + page.bringtotop(page.selected); + + // Trigger page change event + page.onpagechange(true); + + // Select the element + page.selectwidget(page.selected, true, atitle, wvalue, wcopy, wdelete); + + // Trigger widget select event + page.onselectwidget(page.selected); + + return true; + + } + + // Bring selected element to the top + page.selected = selected; + page.bringtotop(page.selected); + + // Select the element + page.selectwidget(page.selected, true, atitle, wvalue, wcopy, wdelete); + + // Trigger widget select event + page.onselectwidget(page.selected); + + return true; + } + + if (!ui.isMobile()) { + pagediv.onclick = function(e) { + //debug('onclick'); + return onclick(e); + }; + } else { + pagediv.onclick = function(e) { + //debug('onclick'); + return onclick(e); + }; + } + + /** + * Handle field on change events. + */ + wvalue.onchange = wvalue.onblur = function() { + if (page.selected == null) + return false; + page.settext(page.selected, wvalue.value); + + // Trigger page change event + page.onpagechange(true); + return false; + }; + + // Handle add widget event. + wadd.onclick = function() { + + // Show the palette + pagediv.style.left = ui.pixpos(0); + return false; + }; + + // Handle delete event. + wdelete.onclick = function() { + if (page.selected == null) + return false; + + // Reset current selection + page.selectwidget(page.selected, false, atitle, wvalue, wcopy, wdelete); + + // Remove selected widget + page.selected.parentNode.removeChild(page.selected); + page.selected = null; + + // Trigger widget select event + page.onselectwidget(null); + + // Trigger page change event + page.onpagechange(true); + return false; + }; + + // Handle copy event. + wcopy.onclick = function() { + if (page.selected == null) + return false; + if (page.selected.id.substring(0, 8) == 'palette:') + return false; + + // Reset current selection + page.selectwidget(page.selected, false, atitle, wvalue, wcopy, wdelete); + + // Clone selected widget + page.selected = page.clone(page.selected); + + // Move 10 pixels down right + page.selected.style.left = ui.pixpos(ui.numpos(page.selected.style.left) + 10); + page.selected.style.top = ui.pixpos(ui.numpos(page.selected.style.top) + 10); + page.constrainwidget(page.selected); + + // Bring it to the top + page.bringtotop(page.selected); + + // Select the element + page.selectwidget(page.selected, true, atitle, wvalue, wcopy, wdelete); + + // Trigger widget select event + page.onselectwidget(page.selected); + + // Trigger page change event + page.onpagechange(true); + return false; + }; + + return pagediv; +}; + +/** + * Return the text of a widget. + */ +page.text = function(e) { + function formula(e) { + var f = e.id; + if (f.substring(0, 5) != 'page:') + return '=' + f; + return ''; + } + + 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 == location.href? '' : src; + } + /* + if (e.className == 'iframe') { + var hr = car(childElements(e)).href; + return hr == location.href? '' : hr; + } + */ + if (e.className == 'list') + return ''; + if (e.className == 'table') + return ''; + return ''; + } + + var f = formula(e); + var c = constant(e, f); + return f == ''? c : (c == ''? f : f + ',' + c); +}; + +/** + * Return true if a widget has editable text. + */ +page.hastext = function(e) { + if (e.className == 'h1' || e.className == 'h2' || e.className == 'text' || e.className == 'section') + return true; + if (e.className == 'button' || e.className == 'checkbox') + return true; + if (e.className == 'entry' || e.className == 'password') + return true; + /* + if (e.className == 'select') + return false; + */ + if (e.className == 'link') + return true; + if (e.className == 'img') + return true; + /* + if (e.className == 'iframe') + return true; + */ + if (e.className == 'list') + return false; + if (e.className == 'table') + return false; + return false; +}; + +/** + * Set the text of a widget. + */ +page.settext = function(e, t) { + 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 = isNil(c)? f : car(c); + return t; + } + if (e.className == 'button') { + car(childElements(e)).value = isNil(c)? f : car(c); + return t; + } + if (e.className == 'entry' || e.className == 'password') { + car(childElements(e)).defaultValue = isNil(c)? f : car(c); + return t; + } + if (e.className == 'checkbox') { + car(childElements(e)).value = isNil(c)? f : car(c); + map(function(n) { if (n.nodeName == "SPAN") n.innerHTML = isNil(c)? f : car(c); return n; }, nodeList(e.childNodes)); + return t; + } + /* + if (e.className == 'select') { + var ce = car(childElements(car(childElements(e)))); + ce.value = isNil(c)? f : car(c); + ce.innerHTML = isNil(c)? f : car(c); + return t; + } + */ + if (e.className == 'list') { + 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">' + (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 ce = car(childElements(e)); + ce.href = isNil(c)? 'link:/index.html' : ('link:' + car(c)); + car(childElements(ce)).innerHTML = isNil(c)? (f != ''? f : '/index.html') : isNil(cdr(c))? (f != ''? f : car(c)) : cadr(c); + return t; + } + if (e.className == 'img') { + car(childElements(e)).src = isNil(c)? '/public/img.png' : car(c); + return t; + } + /* + if (e.className == 'iframe') { + car(childElements(e)).href = isNil(c)? '/public/iframe-min.html' : car(c); + return t; + } + */ + return ''; +}; + +/** + * Initialize a widget. + */ +page.initwidget = function(e) { + + // Add a Webkit transform to leverage hardware acceleration + e.style.setProperty('-webkit-transform', 'translate(0px, 0px)', null); + + /* + if (e.className == 'iframe') { + var f = car(childElements(e)); + //e.innerHTML = '<iframe src="' + f.href + '" frameborder="no" scrolling="no"></iframe>'; + return e; + } + */ + + if (e.className == 'section') { + e.style.width = '100%'; + return e; + } + if (e.className == 'text' || e.className == 'h1' || e.className == 'h2') { + return e; + } + if (e.className == 'button') { + return e; + } + if (e.className == 'checkbox') { + return e; + } + if (e.className == 'list' || e.className == 'table') { + e.style.width = '100%'; + var t = car(childElements(e)); + t.style.width = '100%'; + return e; + } + if (e.className == 'img') { + var i = car(childElements(e)); + if (i.src != '' && i.src.substring(0, 5) == 'data:') + i.src = '/public/img.png'; + return e; + } + if (e.className == 'entry' || e.className == 'password') { + var i = car(childElements(e)); + i.readOnly = true; + i.style.cursor = 'default'; + return e; + } + if (e.className == 'link') { + var l = car(childElements(e)); + l.onclick = function(e) { return false; }; + return e; + } + return e; +} + +/** + * Enforce widget position and style constraints. + */ +page.constrainwidget = function(e) { + if (e.className == 'section' || e.className == 'list' || e.className == 'table') { + e.style.left = ui.pixpos(page.palcx); + return e; + } + return e; +}; + +/** + * Cleanup of a widget before saving it. + */ +page.cleanupwidget = function(e) { + //debug('cleanupwidget', e); + + // Clear outline + e.style.outline = null; + + // Clear the Webkit transform + e.style.removeProperty('-webkit-transform'); + + if (e.className == 'entry' || e.className == 'password') { + var i = car(childElements(e)); + i.readOnly = false; + i.style.cursor = null; + return e; + } + if (e.className == 'link') { + var l = car(childElements(e)); + l.onclick = null; + return e; + } + return e; +} + +/** + * Find a draggable element in a hierarchy of elements. + */ +page.draggable = function(n, e) { + if (n == e) + return null; + if (!isNil(n.id) && n.id != '') + return n; + return page.draggable(n.parentNode, e); +} + +/** + * Align a pos along a 9pixel grid. + */ +page.gridsnap = function(x) { + return Math.round(x / 9) * 9; +} + +/** + * Bring an element and its parent to the top. + */ +page.bringtotop = function(n) { + n.parentNode.appendChild(n); +} + +/** + * Select a widget. + */ +page.selectwidget = function(n, s, atitle, wvalue, wcopy, wdelete) { + //debug('selectwidget', n, s); + if (isNil(n) || !s) { + // Clear the widget value field + wvalue.value = ''; + wvalue.readOnly = true; + wvalue.style.visibility = 'hidden'; + atitle.style.visibility = 'visible'; + wcopy.disabled = true; + wdelete.disabled = true; + + // Clear the widget outline + if (!isNil(n)) + n.style.outline = null; + + return true; + } + + // Outline the widget + n.style.outline = '2px solid #598edd'; + + // Update the widget value field + wvalue.value = page.text(n); + wvalue.readOnly = false || !editable; + wvalue.style.visibility = 'visible'; + atitle.style.visibility = 'hidden'; + wcopy.disabled = false || !editable; + wdelete.disabled = false || !editable; + + return true; +}; + +/** + * Clone a palette element. + */ +page.clone = function(e) { + + /** + * Clone an element's HTML. + */ + function mkclone(e) { + var ne = document.createElement('span'); + + // Skip the palette: prefix + ne.id = 'page:' + e.id.substr(8); + + // Copy the class and HTML content + ne.className = e.className; + ne.innerHTML = e.innerHTML; + + // Fixup the widget style + page.initwidget(ne); + + return ne; + } + + /** + * Clone an element's position. + */ + function posclone(ne, e) { + ne.style.position = 'absolute'; + ne.style.left = ui.pixpos(ui.numpos(e.style.left)); + ne.style.top = ui.pixpos(ui.numpos(e.style.top)); + e.parentNode.appendChild(ne); + return ne; + } + + return posclone(mkclone(e), e); +}; + +/** + * Track the current widget. + */ +var widget = null; + +/** + * Get and display an app page. + */ +function getpage(name, pagediv) { + if (isNil(name)) + return false; + showStatus('Loading'); + + return pages.get(name, function(doc) { + + // Stop now if we didn't get a page + if (doc == null) { + showError('App not available'); + return false; + } + + // Get the page from the ATOM entry, convert it to XHTML and place it in a hidden buffer + var pageentry = car(atom.readATOMEntry(mklist(doc))); + var content = namedElementChild("'content", pageentry); + var el = isNil(content)? mklist() : elementChildren(content); + var buffer = $('buffer'); + if (isNil(el)) + buffer.innerHTML = '<div id="page"></div>'; + else + buffer.innerHTML = writeStrings(writeXML(el, false)); + + // Remove any existing page nodes from the editor div + var fnodes = filter(function(e) { + if (isNil(e.id) || e.id == '' || e.id.substr(0, 8) == 'palette:') + return false; + var x = ui.numpos(e.style.left) - 2500; + if (x < 0 || ui.numpos(e.style.top) < 0) + return false; + return true; + }, nodeList(pagediv.childNodes)); + + map(function(e) { + pagediv.removeChild(e); + }, fnodes); + + // Append new page nodes to editor + map(function(e) { + pagediv.appendChild(e); + if (!isNil(e.style)) + e.style.left = ui.pixpos(ui.numpos(e.style.left) + 2500); + page.initwidget(e); + return e; + }, nodeList(buffer.childNodes[0].childNodes)); + + savedpagexhtml = pagexhtml(pagediv); + + // Enable author to edit the page + author = elementValue(namedElementChild("'author", pageentry)); + editable = author == username; + wadd.disabled = !editable; + showStatus(editable? onlineStatus() : 'Read only'); + + return true; + }); +} + +/** + * Handle add widget button click event. + */ +wadd.onclick = function(e) { + // Show the widget palette + pagediv.style.left = ui.pixpos(0); +}; + +/** + * Return the current page XHTML content. + */ +function pagexhtml(pagediv) { + + // Copy page DOM to hidden buffer + var buffer = $('buffer'); + buffer.innerHTML = '<div id="page"></div>' + var div = buffer.childNodes[0]; + + // Capture the nodes inside the page div + div.innerHTML = pagediv.innerHTML; + var nodes = nodeList(div.childNodes); + map(function(e) { + div.removeChild(e); + return e; + }, nodes); + + // Filter out palette and editor artifacts, which are not + // part of the page, as well as nodes positioned out the + // editing area + var fnodes = filter(function(e) { + if (isNil(e.id) || e.id == '' || e.id.substr(0, 8) == 'palette:') + return false; + var x = ui.numpos(e.style.left) - 2500; + if (x < 0 || ui.numpos(e.style.top) < 0) + return false; + return true; + }, nodes); + + // Reposition and cleanup nodes + map(function(e) { + var x = ui.numpos(e.style.left) - 2500; + e.style.left = ui.pixpos(x); + page.cleanupwidget(e); + return e; + }, fnodes); + + // Sort them by position + var snodes = fnodes.sort(function(a, b) { + var ay = ui.numpos(a.style.top); + var by = ui.numpos(b.style.top); + if (ay < by) return -1; + if (ay > by) return 1; + var ax = ui.numpos(a.style.left); + var bx = ui.numpos(b.style.left); + if (ax < bx) return -1; + if (ax > bx) return 1; + return 0; + }); + + // Append the sorted nodes back to the div in order + map(function(e) { + div.appendChild(e); + return e; + }, snodes); + + // Convert the page to XHTML + var lxhtml = readXHTMLElement(div); + var xhtml = writeStrings(writeXML(lxhtml, false)); + return xhtml; +} + +/** + * Save the current page. + */ +function save(newxml) { + showStatus('Saving'); + + // Get the current page XHTML content + savedpagexhtml = newxml; + + // Update the page ATOM entry + var entry = '<?xml version="1.0" encoding="UTF-8"?>\n' + '<entry xmlns="http://www.w3.org/2005/Atom">' + + '<title type="text">' + appname + '</title><id>' + appname + '</id><author><email>' + author + '</email></author>' + + '<content type="application/xml">' + newxml + '</content></entry>'; + + pages.put(appname, entry, function(e) { + if (e) { + showStatus('Local copy'); + return false; + } + showStatus('Saved'); + return false; + }); + return true; +}; + +/** + * Handle a page change event + */ +function onpagechange(prop) { + if (!editable) + return false; + + var newxml = pagexhtml(pagediv); + if (savedpagexhtml == newxml) + return false; + showStatus('Modified'); + + // Save property changes right away + if (prop) + return save(newxml); + + // Autosave other changes after 1 second + setTimeout(function() { + if (savedpagexhtml == newxml) { + showStatus('Saved'); + return false; + } + return save(newxml); + }, 1000); + return true; +} + +/** + * Handle a widget select event. + */ +function onselectwidget(w) { + if (w == widget) + return true; + widget = w; + return true; +} + +/** + * Play page in a frame. + */ +function playpage() { + if (!evisible) + return true; + page.selectwidget(widget, false, atitle, wvalue, wcopy, wdelete); + page.selected = null; + pplay.value = '<'; + evisible = false; + pdiv.style.visibility = 'visible'; + pdiv.innerHTML = ''; + pdiv.innerHTML = '<iframe id="playappframe" style="position: relative; height: 5000px; width: 2500px; border: 0px;" scrolling="no" frameborder="0" src="/' + + appname + '"></iframe>'; + setTimeout(function() { + pagediv.style.visibility = 'hidden' + }, 0); + return true; +} + +/** + * Show the page editor. + */ +function showedit() { + if (evisible) + return true; + pplay.value = '>'; + pagediv.style.visibility = 'visible' + evisible = true; + page.selectwidget(widget, true, atitle, wvalue, wcopy, wdelete); + page.selected = widget; + setTimeout(function() { + pdiv.style.visibility = 'hidden'; + pdiv.innerHTML = ''; + }, 0); + return true; +} + +/** + * Handle play page button event. + */ +pplay.onclick = function() { + if (!evisible) + return showedit(); + return playpage(); +} + +/** + * Initialize the page editor. + */ +page.mkedit(pagediv, atitle, wvalue, wadd, wcopy, wdelete, onpagechange, onselectwidget); + +/** + * Get and display the current app page. + */ +getpage(appname, pagediv); + +})(); +</script> + +</div> |