// Copyright (c) 2006 spinelz.org (http://script.spinelz.org/)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
var Window = Class.create();
Window.className = {
window: 'window',
header: 'window_header',
headerLeft: 'window_headerLeft',
headerMiddle: 'window_headerMiddle',
headerRight: 'window_headerRight',
buttonHolder: 'window_buttonHolder',
closeButton: 'window_closeButton',
maxButton: 'window_maxButton',
minButton: 'window_minButton',
body: 'window_body',
bodyLeft: 'window_bodyLeft',
bodyMiddle: 'window_bodyMiddle',
bodyRight: 'window_bodyRight',
bottom: 'window_bottom',
bottomLeft: 'window_bottomLeft',
bottomMiddle: 'window_bottomMiddle',
bottomRight: 'window_bottomRight'
}
Window.prototype = {
initialize: function(element) {
var options = Object.extend({
className: Window.className.window,
width: 300,
height: 300,
minWidth: 200,
minHeight: 40,
drag: true,
resize: true,
resizeX: true,
resizeY: true,
modal: false,
closeButton: true,
maxButton: true,
minButton: true,
cssPrefix: 'custom_',
restriction: false,
endDrag: Prototype.emptyFunction,
endResize: Prototype.emptyFunction,
addButton: null,
preMaximize: function() {return true},
preMinimize: function() {return true},
preRevertMaximize: function() {return true},
preRevertMinimize: function() {return true},
preClose: function() {return true},
endMaximize: Prototype.emptyFunction,
endMinimize: Prototype.emptyFunction,
endRevertMaximize: Prototype.emptyFunction,
endRevertMinimize: Prototype.emptyFunction,
endClose: Prototype.emptyFunction,
dragOptions: {},
appendToBody: false,
defaultButtonWidth: 16,
displayNone: true,
build: true
}, arguments[1] || {});
this.classNames = CssUtil.getInstance(options.cssPrefix, Window.className).allJoinClassNames();
this.element = $(element);
this.options = options;
Element.setStyle(this.element, {visibility: 'hidden'});
if (UserAgent.isSafari()) Element.setStyle(this.element, {position: 'absolute'});
if (this.options.displayNone) Element.hide(this.element);
this.element.className = this.options.className;
this.elementId = this.element.id;
this.dragHandleId = this.element.id + '_dragHandle';
this.buttonHolderId = this.element.id + '_buttonHolder';
this.bodyMiddleId = this.element.id + '_bodyMiddle';
this.maxZindex = -1;
this.minFlag = false;
this.maxFlag = false;
this.currentPos = [0,0];
this.currentSize = [0,0];
this.ids = {};
this.addButtons = [];
if (this.options.build && !this.element.buildedWindow) {
this.buildWindow();
} else {
this.initHeight();
if (this.options.drag) this.createDraggble();
if (this.options.resize) this.enableResizing();
}
this.cover = new IECover(this.element, {padding: 10});
Element.makePositioned(element);
Element.hide(this.element);
Element.setStyle(this.element, {visibility: 'visible'});
if (this.options.appendToBody) Element.appendToBody.callAfterLoading(this, this.element);
if (this.options.build && !this.element.buildedWindow) $(this.bodyMiddleId).down(0).appendChild(this.content);
this.element.buildedWindow = true;
},
buildWindow: function() {
Element.cleanWhitespace(this.element);
with (this.element.style) {
width = this.options.width + 'px';
height= this.options.height + 'px';
}
var title = this.element.childNodes[0];
var content = this.element.childNodes[1];
this.element.innerHTML = this.buildHeader(title) + this.buildBody(content) + this.buildBottom();
this.initHeight();
this.setEvent();
},
initHeight: function() {
this.header = $(this.getId('header'));
this.windowBody = $(this.getId('bodyContainer'));
this.bottom = $(this.getId('bottom'));
var newStyle = {height: this.options.height};
this.setBodyHeight(newStyle);
},
setEvent: function() {
if (this.options.drag) this.createDraggble();
if (this.options.resize) this.enableResizing();
var width = 0;
var defaultWidth = this.options.defaultButtonWidth;
if (this.ids.closeButton) {
width += defaultWidth;
Event.observe(this.ids.closeButton, 'click', this.close.bindAsEventListener(this));
}
if (this.ids.maxButton) {
width += defaultWidth;
Event.observe(this.ids.maxButton, 'click', this.maximize.bindAsEventListener(this));
}
if (this.ids.minButton) {
width += defaultWidth;
Event.observe(this.ids.minButton, 'click', this.minimize.bindAsEventListener(this));
}
this.addButtons.each(function(button) {
width += button.width || defaultWidth;
Event.observe(button.id, 'click', button.onclick.bindAsEventListener(this));
}.bind(this));
Element.setStyle(this.buttonHolderId, {width: width + 'px'});
},
buildHeader: function(title) {
var handleStyle = (this.options.drag) ? "" : " style='cursor: default;'";
return "
" +
"
" +
"
" +
Element.outerHTML(title) +
"
" +
this.buildButtons() +
"
" +
"
";
},
buildButtons: function() {
var buttons = "";
if (this.options.closeButton) {
this.ids.closeButton = this.getId('closeButton');
buttons += "";
}
if (this.options.maxButton) {
this.ids.maxButton = this.getId('maxButton');
buttons += "";
}
if (this.options.minButton) {
this.ids.minButton = this.getId('minButton');
buttons += "";
}
if (this.options.addButton) {
var addButton = this.options.addButton;
if (addButton.constructor == Function) {
buttons = addButton(buttons);
} else if (addButton.constructor == Array) {
var self = this;
addButton.each(function(b) {
this.addButtons.push(b);
var added = "";
buttons = (b.first) ? buttons + added : added + buttons;
}.bind(this));
}
}
return "" + buttons + "
";
},
buildBody: function(content) {
var holder = document.createDocumentFragment();
holder.appendChild(content);
this.content = content;
return "";
},
buildBottom: function() {
return "";
},
getId: function(suffix) {
return this.element.id.appendSuffix(suffix);
},
createDraggble: function() {
var options = Object.extend({
handle: this.dragHandleId,
starteffect: Prototype.emptyFunction,
endeffect: Prototype.emptyFunction,
endDrag: this.options.endDrag,
scroll: window
}, this.options.dragOptions);
if (this.options.restriction) {
if (this.options.restriction.constructor == String) {
this._setRestriction(options, $(this.options.restriction));
} else {
this._setRestriction(options, this.element.parentNode);
}
} else {
var p = Position.cumulativeOffset(Position.offsetParent(this.element));
options.snap = function(x, y) {
return [
((x + p[0]) >= 0) ? x : 0 - p[0],
((y + p[1]) >= 0) ? y : 0 - p[1]
];
}
}
new DraggableWindowEx(this.element, options);
},
setWindowZindex : function(zIndex) {
zIndex = this.getZindex(zIndex);
this.element.style.zIndex = zIndex;
},
getZindex: function(zIndex) {
return ZindexManager.getIndex(zIndex);
},
open: function(zIndex) {
this.opening = true;
Element.show(this.element);
if (this.options.modal && !UserAgent.isMac()) {
Modal.mask(this.element, {zIndex: zIndex});
} else {
this.setWindowZindex(zIndex);
}
this.cover.resetSize();
this.opening = false;
if (this.shouldClose) {
this.close();
this.shouldClose = false;
}
},
close: function() {
if (this.opening) this.shouldClose = true;
if (!this.options.preClose(this)) return;
this.element.style.zIndex = -1;
this.maxZindex = -1;
try {
Element.hide(this.element);
} catch(e) {}
if (this.options.modal) {
Modal.unmask();
}
this.options.endClose(this);
if (this.opening) this.shouldClose = true;
},
minimize: function(event) {
if (this.minFlag) {
if (!this.options.preRevertMinimize(this)) return;
Element.toggle(this.windowBody);
if (this.maxFlag) {
this.minFlag = false;
this.setMax();
} else {
var newStyle = {height:this.currentSize[1]}
this.setBodyHeight(newStyle);
this.element.style.width = this.currentSize[0];
this.element.style.height = this.currentSize[1];
this.element.style.left = this.currentPos[0];
this.element.style.top = this.currentPos[1];
this.maxFlag = false;
this.minFlag = false;
this.options.endRevertMinimize(this);
}
} else {
if (!this.options.preMinimize(this)) return;
Element.toggle(this.windowBody);
if (!this.maxFlag) {
this.currentPos = [Element.getStyle(this.element, 'left'), Element.getStyle(this.element, 'top')];
this.currentSize = [Element.getStyle(this.element, 'width'), Element.getStyle(this.element, 'height')];
}
this.setMin();
this.minFlag = true;
this.options.endMinimize(this);
}
this.cover.resetSize();
},
maximize: function(event) {
if (this.maxFlag) {
if (this.minFlag) {
Element.toggle(this.windowBody);
this.minFlag = false;
this.setMax();
} else {
if (!this.options.preRevertMaximize(this)) return;
var newStyle = {height:parseInt(this.currentSize[1])}
this.setBodyHeight(newStyle);
this.element.style.width = this.currentSize[0];
this.element.style.height = this.currentSize[1];
this.element.style.left = this.currentPos[0];
this.element.style.top = this.currentPos[1];
this.maxFlag = false;
this.minFlag = false;
document.body.style.overflow = '';
this.element.style.position = this.position;
for(var i = 0; i < this.nodeArray.length; i++) {
this.parent.appendChild(this.nodeArray[i]);
}
this.options.endRevertMaximize(this);
}
} else {
if (!this.options.preMaximize(this)) return;
if (!this.minFlag) {
this.currentPos = [Element.getStyle(this.element, 'left'), Element.getStyle(this.element, 'top')];
this.currentSize = [Element.getStyle(this.element, 'width'), Element.getStyle(this.element, 'height')];
} else {
Element.toggle(this.windowBody);
this.minFlag = false;
}
this.parent = this.element.parentNode;
this.nodeArray = new Array();
this.setNodePosition();
this.nodeIndex = 0;
this.position = Element.getStyle(this.element, 'position');
document.body.style.overflow = 'hidden';
document.body.appendChild(this.element);
this.element.style.position = 'absolute';
this.setMax();
this.maxFlag = true;
this.options.endMaximize(this);
}
this.cover.resetSize();
},
setNodePosition : function() {
var children = this.parent.childNodes;
for (var i = 0; i < children.length; i++) {
var child = children[i];
if (child.id == this.elementId) {
this.nodeIndex = i;
}
this.nodeArray.push(child);
}
},
setMin : function() {
var minHeight = this.header.offsetHeight + this.bottom.offsetHeight;
var minWidth = this.options.minWidth;
this.element.style.height = minHeight + 'px';
this.element.style.width = minWidth + 'px';
},
setMax : function(zIndex) {
var maxW = Element.getWindowWidth();
var maxH = Element.getWindowHeight();
var newStatus = {height:maxH}
with(this.element.style) {
width = maxW + 'px';
height = maxH + 'px';
left = '0px';
top = '0px';
}
this.setBodyHeight(newStatus);
this.setWindowZindex(zIndex);
},
_getParentWidth: function(parent) {
if (parent && parent.style) {
var width = parent.style.width;
var index = 0;
if (width) {
if ((index = width.indexOf('px', 0)) > 0) {
return parseInt(width);
} else if ((index = width.indexOf('%', 0)) > 0) {
var pw = this._getParentWidth(parent.parentNode);
var par = parseInt(width);
return pw * par / 100;
} else if (!width.isNaN) {
return parseInt(width);
}
} else if (parent == document.body){
return Element.getWindowWidth();
}
}
},
setHeight: function(height) {
height = {height: height};
Element.setStyle(this.element, height);
this.setBodyHeight(height);
},
setBodyHeight: function(newStyle) {
var height = parseInt(newStyle.height, 10);
if (height > this.options.minHeight) {
var newHeight = null;
if (this.options.displayNone) {
newHeight = (height - parseInt(Element.getStyle(this.header, 'height'), 10) -
parseInt(Element.getStyle(this.bottom, 'height'), 10)) + 'px';
} else {
newHeight = (height - this.header.offsetHeight - this.bottom.offsetHeight) + 'px';
}
var childNodes = Element.getTagNodes(this.windowBody);
childNodes[0].style.height = newHeight;
childNodes[1].style.height = newHeight;
childNodes[2].style.height = newHeight;
this.windowBody.style.height = newHeight;
}
if (this.cover) this.cover.resetSize();
},
center: function() {
var w = parseInt(Element.getStyle(this.element, 'width'));
var h = parseInt(Element.getStyle(this.element, 'height'));
var offsetParent = Position.offsetParent(this.element);
var pOffset = Position.cumulativeOffset(offsetParent);
var left = (Element.getWindowWidth() - w) / 2;
var top = (Element.getWindowHeight() - h) / 2;
var realOffset = Position.realOffset(offsetParent);
var scrollTop = realOffset.last();
var scrollLeft = realOffset.first();
top += scrollTop - pOffset[1];
left += scrollLeft - pOffset[0];
top = ((top + pOffset[1]) >= 0) ? top : 0 - pOffset[1];
left = ((left + pOffset[0]) >= 0) ? left : 0 - pOffset[0];
Element.setStyle(this.element, {left: left + 'px', top: top + 'px'});
},
moveTo: function(position) {
var style = {};
if (position.left) {
style.left = (position.left.constructor != String) ? (position.left + 'px') : position.left;
}
if (position.top) {
style.top = (position.top.constructor != String) ? (position.top + 'px') : position.top;
}
Element.setStyle(this.element, style);
},
moveBy: function(position) {
var style = {};
if (position.left) {
style.left = (parseInt(Element.getStyle(this.element, 'left'), 10) + position.left) + 'px';
}
if (position.top) {
style.top = (parseInt(Element.getStyle(this.element, 'top'), 10) + position.top) + 'px';
}
Element.setStyle(this.element, style);
},
enableResizing: function() {
var resTop = this.options.resizeY ? 6 : 0;
var resBottom = this.options.resizeY ? 6 : 0;
var resLeft = this.options.resizeX ? 6 : 0;
var resRight = this.options.resizeX ? 6 : 0;
this.resizeable = new ResizeableWindowEx(this.element, {
top: resTop,
bottom: resBottom,
left: resLeft,
right: resRight,
minWidth: this.options.minWidth,
minHeight: this.options.minHeight,
draw: this.setBodyHeight.bind(this),
resize: this.options.endResize,
restriction: this.options.restriction,
zindex: 2000
});
},
disableResizing: function() {
this.resizeable.destroy();
},
_setRestriction: function(options, restrictionNode) {
options.snap = function(x, y) {
function constrain(n, lower, upper) {
if (n > upper) return upper;
else if (n < lower) return lower;
else return n;
}
var eDimensions = Element.getDimensions(this.element);
var pDimensions = Element.getDimensions(restrictionNode);
if (Element.getStyle(restrictionNode, 'position') == 'static') {
var offset = Position.positionedOffset(restrictionNode);
var parentLeft = offset[0];
var parentTop = offset[1];
return [
constrain(x, parentLeft, parentLeft + pDimensions.width - eDimensions.width),
constrain(y, parentTop, parentTop + pDimensions.height - eDimensions.height)
];
} else {
var offsetTop = 0
var offsetLeft = 0
if (restrictionNode != this.element.parentNode) {
var restOffset = Position.cumulativeOffset(restrictionNode);
var parentOffset = Position.cumulativeOffset(Position.offsetParent(this.element));
offsetLeft = restOffset[0] - parentOffset[0];
offsetTop = restOffset[1] - parentOffset[1];
}
return [
constrain(x, offsetLeft, (pDimensions.width - eDimensions.width) + offsetLeft),
constrain(y, offsetTop, (pDimensions.height - eDimensions.height) + offsetTop)
];
}
}.bind(this)
}
}
// Copyright (c) 2005 spinelz.org (http://script.spinelz.org/)
//
// This code is substantially based on code from script.aculo.us which has the
// following copyright and permission notice
//
// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
var DraggableWindowEx = Class.create();
Object.extend(DraggableWindowEx.prototype, Draggable.prototype);
Object.extend(DraggableWindowEx.prototype, {
initDrag: function(event) {
if(Event.isLeftClick(event)) {
// abort on form elements, fixes a Firefox issue
var src = Event.element(event);
if(src.tagName && (
src.tagName=='INPUT' ||
src.tagName=='SELECT' ||
src.tagName=='OPTION' ||
src.tagName=='BUTTON' ||
src.tagName=='TEXTAREA')) return;
if(this.element._revert) {
this.element._revert.cancel();
this.element._revert = null;
}
var pointer = [Event.pointerX(event), Event.pointerY(event)];
var pos = Position.cumulativeOffset(this.element);
this.offset = [0,1].map( function(i) { return (pointer[i] - pos[i]) });
var zIndex = ZindexManager.getIndex();
this.originalZ = zIndex;
this.options.zindex = zIndex;
Element.setStyle(this.element, {zIndex: zIndex});
Draggables.activate(this);
Event.stop(event);
}
},
endDrag: function(event) {
if(!this.dragging) return;
this.stopScrolling();
this.finishDrag(event, true);
this.options.endDrag();
Event.stop(event);
}
});