/*
* 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.
*/
/**
* Page editing functions.
*/
var page = {};
/**
* Default positions and sizes.
*/
var palcx = 2500;
var trashcx = 2480;
/**
* Init a page editor. Works with all browsers except IE.
*/
page.edit = function(elem, wname, wtext, wadd, wdelete, onchange, onselect) {
// Track element dragging and selection
page.dragging = null;
page.selected = null;
wname.disabled = true;
wtext.disabled = true;
wdelete.disabled = true;
// Trigger widget select and page change events
page.onpagechange = onchange;
page.onwidgetselect = onselect;
/**
* Handle a mouse down event.
*/
elem.onmousedown = function(e) {
// Find a draggable element
page.dragging = page.draggable(e.target, elem);
page.selected = page.dragging;
if (page.dragging == null) {
// Reset current selection
wname.value = '';
wname.disabled = true;
wtext.value = '';
wtext.disabled = true;
wdelete.disabled = true;
// Trigger widget select event
page.onwidgetselect('');
return true;
}
// Clone element dragged from palette
if (page.dragging.id.substring(0, 8) == 'palette:') {
page.dragging = page.clone(page.dragging);
page.selected = page.dragging;
// Move into the editing area and hide the palette
page.selected.style.left = ui.pixpos(ui.numpos(page.selected.style.left) + palcx);
elem.style.left = ui.pixpos(palcx * -1);
// Bring it to the top
page.bringtotop(page.dragging);
// Trigger page change event
page.onpagechange(true);
} else {
// Bring it to the top
page.bringtotop(page.dragging);
}
// Remember mouse position
var pos = typeof e.touches != "undefined" ? e.touches[0] : e;
page.dragX = pos.screenX;
page.dragY = pos.screenY;
// Update the widget name and text fields
wname.value = page.selected.id;
wname.disabled = false;
wtext.value = page.text(page.selected);
wtext.disabled = !page.hastext(page.selected);
wdelete.disabled = false;
// Trigger widget select event
page.onwidgetselect(page.selected.id);
if (e.preventDefault)
e.preventDefault();
else
e.returnValue = false;
return true;
};
// Support touch devices
elem.ontouchstart = elem.onmousedown;
/**
* Handle a mouse up event.
*/
elem.onmouseup = function(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);
page.dragging.cover.style.left = ui.pixpos(newX);
page.dragging.cover.style.top = ui.pixpos(newY);
// Fixup widget style
page.fixupwidget(page.dragging);
// Discard element dragged out of page area
if (ui.numpos(page.dragging.style.left) < palcx && page.dragging.id.substring(0, 8) != 'palette:') {
if (ui.numpos(page.dragging.style.left) >= trashcx) {
// Unless it's close enough to page area, then move it there
page.dragging.style.left = ui.pixpos(palcx);
page.dragging.cover.style.left = ui.pixpos(palcx);
} else {
page.dragging.parentNode.removeChild(page.dragging);
// Reset current selection
page.selected = null;
wname.value = '';
wname.disabled = true;
wtext.value = '';
wtext.disabled = true;
wdelete.disabled = true;
// Trigger widget select event
page.onwidgetselect('');
}
}
// Forget dragged element
page.dragging = null;
// Trigger page change event
page.onpagechange(false);
return true;
};
// Support touch devices
elem.ontouchend = elem.onmouseup;
/**
* Handle a mouse move event.
*/
window.onmousemove = function(e) {
if (page.dragging == null)
return true;
// Compute position of dragged element
var curX = ui.numpos(page.dragging.style.left);
var curY = ui.numpos(page.dragging.style.top);
var pos = typeof e.touches != "undefined" ? e.touches[0] : e;
var newX = curX + (pos.screenX - page.dragX);
var newY = curY + (pos.screenY - page.dragY);
if (newX >= 0)
page.dragX = pos.screenX;
else
newX = 0;
if (newY >= 0)
page.dragY = pos.screenY;
else
newY = 0;
// Move the dragged element
page.dragging.style.left = ui.pixpos(newX);
page.dragging.style.top = ui.pixpos(newY);
page.dragging.cover.style.left = ui.pixpos(newX);
page.dragging.cover.style.top = ui.pixpos(newY);
return true;
};
// Support touch devices
elem.ontouchmove = window.onmousemove;
/**
* Handle a mouse click event.
*/
elem.onclick = function(e) {
if (page.dragging == null) {
// Dismiss the palette
if (ui.numpos(elem.style.left) != (palcx * -1))
elem.style.left = ui.pixpos(palcx * -1);
}
return true;
};
/**
* Handle field on change events.
*/
wname.onchange = wname.onblur = function() {
if (page.selected == null)
return false;
page.selected.id = wname.value;
// Trigger page change event
page.onpagechange(true);
return false;
};
wtext.onchange = wtext.onblur = function() {
if (page.selected == null)
return false;
page.settext(page.selected, wtext.value);
// Trigger page change event
page.onpagechange(true);
return false;
};
// Handle add widget event.
wadd.onclick = function() {
// Show the palette
elem.style.left = ui.pixpos(0);
return false;
};
// Handle delete event.
wdelete.onclick = function() {
if (page.selected == null)
return false;
// Remove selected widget
page.selected.parentNode.removeChild(page.selected);
// Reset current selection
page.selected = null;
wname.value = '';
wname.disabled = true;
wtext.value = '';
wtext.disabled = true;
wdelete.disabled = true;
// Trigger widget select event
page.onwidgetselect('');
// 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));
return elem;
};
/**
* Return the text of a widget.
*/
page.text = function(e) {
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')
return '';
return '';
};
/**
* 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) {
if (e.className == 'h1' || e.className == 'h2' || e.className == 'text' || e.className == 'section') {
car(childElements(e)).innerHTML = t;
return t;
}
if (e.className == 'button' || e.className == 'entry' || e.className == 'password') {
car(childElements(e)).defaultValue = t;
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));
return t;
}
if (e.className == 'select') {
var ce = car(childElements(car(childElements(e))));
ce.value = t;
ce.innerHTML = t;
return t;
}
if (e.className == 'list') {
return '';
}
if (e.className == 'table') {
return '';
}
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);
return t;
}
if (e.className == 'img') {
car(childElements(e)).src = t;
return t;
}
if (e.className == 'iframe') {
car(childElements(e)).href = t;
return t;
}
return '';
};
/**
* Initial fixup of a widget.
*/
page.fixupwidget = function(e) {
if (e.className == 'iframe') {
var f = car(childElements(e));
//e.innerHTML = '';
return e;
}
if (e.className == 'section') {
e.style.width = '100%';
return e;
}
if (e.className == 'list') {
car(childElements(e)).style.width = '100%';
return e;
}
if (e.className == 'table') {
car(childElements(e)).style.width = '100%';
return e;
}
return e;
}
/**
* Find a draggable element in a hierarchy of elements.
*/
page.draggable = function(n, e) {
if (n == e)
return null;
if (n.id != '')
return n;
if (n.covered)
return n.covered;
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);
n.cover.parentNode.appendChild(n.cover);
}
/**
* Cover a page element with a element to prevent
* any input events to reach it.
*/
page.cover = function(e) {
if (e.id == '' || isNil(e.style))
return e;
var cover = document.createElement('span');
cover.style.position = 'absolute';
cover.style.left = ui.pixpos(ui.numpos(e.style.left) - 5);
cover.style.top = ui.pixpos(ui.numpos(e.style.top) - 5);
cover.style.width = e.clientWidth + 10;
cover.style.height = e.clientHeight + 10;
cover.style.visibility = 'visible';
cover.covered = e;
e.cover = cover;
e.parentNode.appendChild(cover);
return e;
}
/**
* 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 = e.id.substr(8);
// Copy the class and HTML content
ne.className = e.className;
ne.innerHTML = e.innerHTML;
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);
page.cover(ne);
return ne;
}
return posclone(mkclone(e), e);
};