Files
wisemapping-open-source/wise-webapp/src/main/webapp/js/windoo.js
2011-07-28 13:06:15 -03:00

1761 lines
62 KiB
JavaScript

//Windoo: Mootools window class <http://code.google.com/p/windoo>. Copyright (c) 2007 Yevgen Gorshkov, MIT Style License.
/*
Class: Ajax
An Ajax class, For all your asynchronous needs.
Inherits methods, properties, options and events from <XHR>.
Arguments:
url - the url pointing to the server-side script.
options - optional, an object containing options.
Options:
data - you can write parameters here. Can be a querystring, an object or a Form element.
update - $(element) to insert the response text of the XHR into, upon completion of the request.
evalScripts - boolean; default is false. Execute scripts in the response text onComplete. When the response is javascript the whole response is evaluated.
evalResponse - boolean; default is false. Force global evalulation of the whole response, no matter what content-type it is.
Events:
onComplete - function to execute when the ajax request completes.
Example:
>var myAjax = new Ajax(url, {method: 'get'}).request();
*/
var Ajax = new Class({
// Extends: XHR,
options: {
data: null,
update: null,
onComplete: Class.empty,
evalScripts: false,
evalResponse: false
},
initialize: function(url, options) {
this.addEvent('onSuccess', this.onComplete);
this.setOptions(options);
/*compatibility*/
this.options.data = this.options.data || this.options.postBody;
/*end compatibility*/
if (!['post', 'get'].contains(this.options.method)) {
this._method = '_method=' + this.options.method;
this.options.method = 'post';
}
this.parent();
this.setHeader('X-Requested-With', 'XMLHttpRequest');
this.setHeader('Accept', 'text/javascript, text/html, application/xml, text/xml, */*');
this.url = url;
},
onComplete: function() {
if (this.options.update)
$(this.options.update).empty().innerHTML = this.response.text;
if (this.options.evalScripts || this.options.evalResponse)
this.evalScripts();
this.fireEvent('onComplete', [this.response.text, this.response.xml], 20);
},
/*
Property: request
Executes the ajax request.
Example:
>var myAjax = new Ajax(url, {method: 'get'});
>myAjax.request();
OR
>new Ajax(url, {method: 'get'}).request();
*/
request: function(data) {
data = data || this.options.data;
switch ($type(data)) {
case 'element': data = $(data).toQueryString(); break;
case 'object': data = Object.toQueryString(data);
}
if (this._method) data = (data) ? [this._method, data].join('&') : this._method;
return this.send(this.url, data);
},
/*
Property: evalScripts
Executes scripts in the response text
*/
evalScripts: function() {
var script, scripts;
if (this.options.evalResponse || (/(ecma|java)script/).test(this.getHeader('Content-type'))) scripts = this.response.text;
else {
scripts = [];
var regexp = /<script[^>]*>([\s\S]*?)<\/script>/gi;
while ((script = regexp.exec(this.response.text))) scripts.push(script[1]);
scripts = scripts.join('\n');
}
if (scripts) (window.execScript) ? window.execScript(scripts) : window.setTimeout(scripts, 0);
},
/*
Property: getHeader
Returns the given response header or null
*/
getHeader: function(name) {
try {
return this.transport.getResponseHeader(name);
} catch(e) {
}
;
return null;
}
});
/*
Script: XHR.js
Contains the basic XMLHttpRequest Class Wrapper.
License:
MIT-style license.
*/
/*
Class: XHR
Basic XMLHttpRequest Wrapper.
Arguments:
options - an object with options names as keys. See options below.
Options:
method - 'post' or 'get' - the protocol for the request; optional, defaults to 'post'.
async - boolean: asynchronous option; true uses asynchronous requests. Defaults to true.
encoding - the encoding, defaults to utf-8.
autoCancel - cancels the already running request if another one is sent. defaults to false.
headers - accepts an object, that will be set to request headers.
Events:
onRequest - function to execute when the XHR request is fired.
onSuccess - function to execute when the XHR request completes.
onStateChange - function to execute when the state of the XMLHttpRequest changes.
onFailure - function to execute when the state of the XMLHttpRequest changes.
Properties:
running - true if the request is running.
response - object, text and xml as keys. You can access this property in the onSuccess event.
Example:
>var myXHR = new XHR({method: 'get'}).send('http://site.com/requestHandler.php', 'name=john&lastname=dorian');
*/
var XHR = new Class({
options: {
method: 'post',
async: true,
onRequest: Class.empty,
onSuccess: Class.empty,
onFailure: Class.empty,
urlEncoded: true,
encoding: 'utf-8',
autoCancel: false,
headers: {}
},
setTransport: function() {
this.transport = (window.XMLHttpRequest) ? new XMLHttpRequest() : (window.ie ? new ActiveXObject('Microsoft.XMLHTTP') : false);
return this;
},
initialize: function(options) {
this.setTransport().setOptions(options);
this.options.isSuccess = this.options.isSuccess || this.isSuccess;
this.headers = {};
if (this.options.urlEncoded && this.options.method == 'post') {
var encoding = (this.options.encoding) ? '; charset=' + this.options.encoding : '';
this.setHeader('Content-type', 'application/x-www-form-urlencoded' + encoding);
}
if (this.options.initialize) this.options.initialize.call(this);
},
onStateChange: function() {
if (this.transport.readyState != 4 || !this.running) return;
this.running = false;
var status = 0;
try {
status = this.transport.status;
} catch(e) {
}
;
if (this.options.isSuccess.call(this, status)) this.onSuccess();
else this.onFailure();
this.transport.onreadystatechange = Class.empty;
},
isSuccess: function(status) {
return ((status >= 200) && (status < 300));
},
onSuccess: function() {
this.response = {
'text': this.transport.responseText,
'xml': this.transport.responseXML
};
this.fireEvent('onSuccess', [this.response.text, this.response.xml]);
this.callChain();
},
onFailure: function() {
this.fireEvent('onFailure', this.transport);
},
/*
Property: setHeader
Add/modify an header for the request. It will not override headers from the options.
Example:
>var myXhr = new XHR(url, {method: 'get', headers: {'X-Request': 'JSON'}});
>myXhr.setHeader('Last-Modified','Sat, 1 Jan 2005 05:00:00 GMT');
*/
setHeader: function(name, value) {
this.headers[name] = value;
return this;
},
/*
Property: send
Opens the XHR connection and sends the data. Data has to be null or a string.
Example:
>var myXhr = new XHR({method: 'post'});
>myXhr.send(url, querystring);
>
>var syncXhr = new XHR({async: false, method: 'post'});
>syncXhr.send(url, null);
>
*/
send: function(url, data) {
if (this.options.autoCancel) this.cancel();
else if (this.running) return this;
this.running = true;
if (data && this.options.method == 'get') {
url = url + (url.contains('?') ? '&' : '?') + data;
data = null;
}
this.transport.open(this.options.method.toUpperCase(), url, this.options.async);
this.transport.onreadystatechange = this.onStateChange.bind(this);
if ((this.options.method == 'post') && this.transport.overrideMimeType) this.setHeader('Connection', 'close');
$extend(this.headers, this.options.headers);
for (var type in this.headers) try {
this.transport.setRequestHeader(type, this.headers[type]);
} catch(e) {
}
;
this.fireEvent('onRequest');
this.transport.send($pick(data, null));
return this;
},
/*
Property: cancel
Cancels the running request. No effect if the request is not running.
Example:
>var myXhr = new XHR({method: 'get'}).send(url);
>myXhr.cancel();
*/
cancel: function() {
if (!this.running) return this;
this.running = false;
this.transport.abort();
this.transport.onreadystatechange = Class.empty;
this.setTransport();
this.fireEvent('onCancel');
return this;
}
});
XHR.implement(new Chain, new Events, new Options);
Fx.Overlay = new Class({
options: {
'styles': {
'position': 'absolute',
'top': 0,
'left': 0
}
},
initialize: function(element, props, tag) {
this.element = $(element);
this.setOptions(props);
if ([window, $(document.body)].contains(this.element)) {
this.padding = Fx.Overlay.windowPadding;
this.container = $(document.body);
this.element = window;
} else {
this.padding = {x: 0, y: 0};
this.container = this.element;
}
this.overlay = new Element($pick(tag, 'div'), {'styles': {'display': 'none'}}).inject(this.container);
this.update();
},
show: function() {
this.overlay.setStyle('display', 'block');
return this;
},
update: function(props) {
this.overlay.set($merge(this.options, {'styles': {
width: this.element.getScrollWidth() - this.padding.x,
height: this.element.getScrollHeight() - this.padding.y
}}, props));
return this;
},
hide: function() {
this.overlay.setStyle('display', 'none');
return this;
},
destroy: function() {
this.overlay.remove(true);
return this;
}
});
Fx.Overlay.implement(new Options);
Fx.Overlay.windowPadding = (window.ie6) ? {x: 21, y: 4} : {x: 0, y: 0};
Element.$overlay = function(hide, deltaZ) {
deltaZ = $pick(deltaZ, 1);
if (!this.fixOverlayElement) this.fixOverlayElement = new Element('iframe', {
'properties': {'frameborder': '0', 'scrolling': 'no', 'src': 'javascript:void(0);'},
'styles': {'position': this.getStyle('position'), 'border': 'none', 'filter': 'progid:DXImageTransform.Microsoft.Alpha(opacity=0)'}}).injectBefore(this);
if (hide) return this.fixOverlayElement.setStyle('display', 'none');
var z = this.getStyle('z-index').toInt() || 0;
if (z < deltaZ) this.setStyle('z-index', '' + (z = deltaZ + 1));
var pos = this.getCoordinates();
return this.fixOverlayElement.setStyles({'display' : '', 'z-index': '' + (z - deltaZ),
'left': pos.left + 'px', 'top': pos.top + 'px',
'width': pos.width + 'px', 'height': pos.height + 'px'});
};
//Element.extend({
//
// fixOverlay: window.ie6 ? Element.$overlay : function() {
// return false;
// },
//
// remove: function(trash) {
// if (this.fixOverlayElement) {
// this.fixOverlayElement.remove();
// if (trash) {
// Garbage.trash([this.fixOverlayElement]);
// }
// }
// this.parentNode.removeChild(this);
// if (trash) {
// Garbage.trash([this.empty()]);
// return false;
// }
// return this;
// }
//
//});
Drag.Transition = {
linear:{
step: function(start, current, direction) {
return direction * current - start;
},
inverse: function(start, current, direction) {
return (start + current) / direction;
}
}
};
// @Todo: Check this. Required for migration to new mootools.
//Drag.Multi = Drag.Base.extend({
Drag.Multi = Drag.extend({
options: {
handle: false,
onStart: Class.empty,
onBeforeStart: Class.empty,
onComplete: Class.empty,
onDrag: Class.empty,
snap: 6
},
elementOptions: {
unit: 'px',
direction: 1,
limit: false,
grid: false,
bind: false,
fn: Drag.Transition.linear
},
initialize: function(options) {
this.setOptions(options);
this.handle = $(this.options.handle);
this.element = [];
this.mouse = {'start': {}, 'now': {}};
this.modifiers = {};
this.bound = {
'start': this.start.bindWithEvent(this),
'check': this.check.bindWithEvent(this),
'drag': this.drag.bindWithEvent(this),
'stop': this.stop.bind(this)
};
this.attach();
if (this.options.initialize) this.options.initialize.call(this);
},
add: function(el, options, bind) {
el = $(el);
if (!$defined(bind)) bind = {};
var result = {};
for (var z in options) {
if ($type(options[z]) != 'object' || !$defined(options[z].style)) continue;
if (!$defined(this.modifiers[z])) this.modifiers[z] = [];
var mod = $merge(this.elementOptions, options[z], {modifier: z, element: el, bind: false, binded: false});
if (bind[z]) {
mod.bind = bind[z];
mod.bind.binded = true;
}
var sign = mod.style.slice(0, 1);
if (sign == '-' || sign == '+') {
mod.direction = (sign + 1).toInt();
mod.style = mod.style.slice(1);
}
this.modifiers[z].push(mod);
result[z] = mod;
}
if (!this.element.contains(el)) this.element.push(el);
return result;
},
remove: function(el) {
el = $(el);
for (var z in this.modifiers) this.modifiers[z] = this.modifiers[z].filter(function(e) {
return el != e.element;
});
this.element.remove(el);
return this;
},
detach: function(mod) {
for (var z in mod) if ($type(mod[z]) == 'object' && !mod[z].binded) this.modifiers[z].remove(mod[z]);
return this;
},
start: function(event) {
this.fireEvent('onBeforeStart', this.element);
this.mouse.start = event.page;
for (var z in this.modifiers) {
var mouse = this.mouse.start[z];
this.modifiers[z].each(function(mod) {
mod.now = mod.element.getStyle(mod.style).toInt();
mod.start = mod.fn.step(mod.now, mouse, mod.direction, true);
mod.$limit = [];
var limit = mod.limit;
if (limit) for (var i = 0; i < 2; i++) {
if ($defined(limit[i])) mod.$limit[i] = ($type(limit[i]) == 'function') ? limit[i](mod) : limit[i];
}
}, this);
}
document.addListener('mousemove', this.bound.check);
document.addListener('mouseup', this.bound.stop);
this.fireEvent('onStart', this.element);
event.stop();
},
modifierUpdate: function(mod) {
var z = mod.modifier, mouse = this.mouse.now[z];
mod.out = false;
mod.now = mod.fn.step(mod.start, mod.bind ? mod.bind.inverse : mouse, mod.direction);
if (mod.$limit && $defined(mod.$limit[1]) && (mod.now > mod.$limit[1])) {
mod.now = mod.$limit[1];
mod.out = true;
} else if (mod.$limit && $defined(mod.$limit[0]) && (mod.now < mod.$limit[0])) {
mod.now = mod.$limit[0];
mod.out = true;
}
if (mod.grid) mod.now -= ((mod.now + mod.grid / 2) % mod.grid) - mod.grid / 2;
if (mod.binded) mod.inverse = mod.fn.inverse(mod.start, mod.now, mod.direction);
mod.element.setStyle(mod.style, mod.now + mod.unit);
},
drag: function(event) {
this.mouse.now = event.page;
for (var z in this.modifiers) this.modifiers[z].each(this.modifierUpdate, this);
this.fireEvent('onDrag', this.element);
event.stop();
}
});
Drag.Multi.$direction = {
east: { 'x':1 },
west: { 'x':-1 },
north: { 'y':-1 },
south: { 'y':1 },
nw: { 'x':-1, 'y':-1 },
ne: { 'x':1, 'y':-1 },
sw: { 'x':-1, 'y':1 },
se: { 'x':1, 'y':1 }
};
Drag.Resize = new Class({
options:{
zIndex: 10000,
moveLimit: false,
resizeLimit: {'x': [0], 'y': [0]},
grid: false,
modifiers: {'x': 'left', 'y': 'top', 'width': 'width', 'height': 'height'},
container: null, preserveRatio: false,
ghost: false,
snap: 6,
direction: Drag.Multi.$direction,
limiter:{
'x': {'-1': ['left', 'right'], '1': ['right', 'left']},
'y': {'-1': ['top', 'bottom'], '1': ['bottom', 'top']}
},
moveLimiter:{
'x': ['left', 'right'],
'y': ['top', 'bottom']
},
ghostClass: 'ghost-sizer sizer-visible',
classPrefix: 'sizer sizer-',
hoverClass: 'sizer-visible',
shadeBackground: 'transparent url(s.gif)',
onBuild: Class.empty,
onBeforeStart: Class.empty,
onStart: Class.empty,
onSnap: Class.empty,
onResize: Class.empty,
onComplete: Class.empty
},
initialize: function(el, options) {
var self = this;
this.element = this.el = $(el);
this.fx = {};
this.binds = {};
this.bound = {};
this.setOptions(options);
this.options.container = this.options.container === null ? this.el.getParent() : $(this.options.container);
if ($type(this.options.direction) == 'string') {
if (dir == 'all') {
this.options.direction = Drag.Multi.$direction;
} else {
var dir = this.options.direction.split(/\s+/);
this.options.direction = {};
dir.each(function(d) {
this[d] = Drag.Multi.$direction[d];
}, this.options.direction);
}
}
var ce = this.el.getCoordinates(), positionStyle = this.el.getStyle('position');
this.el.setStyles({'width': ce.width, 'height': ce.height});
if (this.options.container) {
if (!(['relative', 'fixed'].contains(positionStyle))) {
var cc = this.options.container.getCoordinates();
this.el.setStyles({'left': ce.left - cc.left, 'top': ce.top - cc.top});
}
this.options.moveLimit = $merge({'x': [0], 'y': [0]}, this.options.moveLimit);
}
if (this.options.preserveRatio) {
var R = ce.width / ce.height;
var rlim = self.options.resizeLimit;
var fix = function(z1, z2, op, no, coeff) {
if (rlim && rlim[z1] && rlim[z2] && rlim[z1][no] && rlim[z2][no])
rlim[z1][no] = Math[op](rlim[z1][no], coeff * rlim[z2][no]);
};
fix('x', 'y', 'max', 0, R);
fix('y', 'x', 'max', 0, 1 / R);
fix('x', 'y', 'min', 1, R);
fix('y', 'x', 'min', 1, 1 / R);
this.aspectStep = {
x: {step: function(s, c, d) {
return d * c / R - s;
}},
y: {step: function(s, c, d) {
return d * c * R - s;
}}
};
this.options.direction = $merge(this.options.direction);
['nw','ne','sw','se'].each(function(z) {
delete this[z];
}, this.options.direction);
}
if (this.options.ghost) {
this.ghost = new Element('div', {'class': this.options.ghostClass, 'styles': {'display': 'none'}}).injectAfter(this.el);
for (var d in this.options.direction) this.ghost.adopt(new Element('div', {'class': this.options.classPrefix + d}));
}
var rOpts = {
snap: this.options.snap,
onBeforeStart: function() {
self.fireEvent('onBeforeStart', this);
self.started = true;
this.shade = new Fx.Overlay(window, {'styles': {
'position': positionStyle,
'cursor': this.options.handle.getStyle('cursor'),
'background': self.options.shadeBackground,
'z-index': self.options.zIndex + 1
}}).show();
if (self.ghost) {
var ce = self.el.getCoordinates();
self.ghost.setStyles({
'display': 'block',
'z-index': self.options.zIndex,
'left': self.el.getStyle('left'),
'top': self.el.getStyle('top'),
'width': ce.width,
'height': ce.height
});
for (var z in this.modifiers)
this.modifiers[z].each(function(mod) {
if (mod.element === self.ghost)
mod.element.setStyle(mod.style, self.el.getStyle(mod.style));
});
if (self.options.hoverClass) self.el.removeClass(self.options.hoverClass);
}
},
onSnap: function() {
self.fireEvent('onSnap', this);
},
onStart: function() {
self.fireEvent('onStart', this);
},
onDrag: function() {
self.fireEvent('onResize', this);
},
onComplete: function() {
self.started = false;
if (self.options.hoverClass) self.el.removeClass(self.options.hoverClass);
this.shade.destroy();
if (self.ghost) {
for (var z in this.modifiers) {
this.modifiers[z].each(function(mod) {
if (mod.element === self.ghost) self.el.setStyle(mod.style, mod.now + mod.unit);
});
}
self.ghost.setStyle('display', 'none');
}
self.fireEvent('onComplete', this);
}
};
var rlimitFcn = function(sign, props, limit) {
if (!self.options.container) return limit;
if (!limit) limit = [0];
var generator = function(lim) {
return function(mod) {
var cc = self.options.container.getCoordinates(),
ec = mod.element.getCoordinates();
var value = sign * (cc[props[0]] - ec[props[1]]);
switch ($type(lim)) {
case 'number':
return Math.min(value, lim);
case 'function':
return Math.min(value, lim(mod));
default:
return value;
}
};
};
return [limit[0], generator(limit[1])];
};
var mlimitFcn = function(props, limit, rlimit) {
var container = self.options.container;
var generator = function(lim, rlim, op, rdef) {
if (!$type(rlim)) rlim = rdef;
var lim_type = $type(lim);
if (rlim === null) return lim_type == 'function' ? lim : function() {
return lim;
};
return function(mod) {
var cc = container.getCoordinates(),
ec = mod.element.getCoordinates();
var value = ec[props[1]] - cc[props[0]] - rlim;
switch (lim_type) {
case 'number':
return Math[op](value, lim);
case 'function':
return Math[op](value, lim(mod));
default:
return value;
}
};
};
if (!container) {
if (!limit) limit = false;
container = self.el.getParent();
} else if (!limit) limit = [0];
return [generator(limit[0], rlimit[1], 'max', null), generator(limit[1], rlimit[0], 'min', limit[1])];
};
var opt = this.options, el = this.ghost ? this.ghost : this.el;
if ($type(opt.grid) == 'number') opt.grid = {'x': opt.grid, 'y': opt.grid};
for (var d in opt.direction) {
var mod = opt.direction[d];
rOpts.handle = new Element('div', {'class': opt.classPrefix + d});
var drag = this.fx[d] = new Drag.Multi(rOpts);
var resizeLimit = {
'x': rlimitFcn(mod.x, opt.limiter.x['' + mod.x], opt.resizeLimit.x),
'y': rlimitFcn(mod.y, opt.limiter.y['' + mod.y], opt.resizeLimit.y)
};
var moveOpts = {};
for (var z in mod) {
if (mod[z] < 0) {
moveOpts[z] = {
limit: mlimitFcn(opt.moveLimiter[z], opt.moveLimit[z], opt.resizeLimit[z]),
style: opt.modifiers[z],
grid: opt.grid.x
};
}
}
var binds = {move: drag.add(el, moveOpts)}, resize = {opts: {}, bind: {}};
this.binds[d] = binds;
if ($defined(mod.x)) {
resize.opts.x = {
limit: mod.x < 0 ? false : resizeLimit.x,
grid: mod.x < 0 ? false : opt.grid.x,
style: opt.modifiers.width,
direction: mod.x
};
if (mod.x < 0) resize.bind.x = binds.move.x;
}
if ($defined(mod.y)) {
resize.opts.y = {
limit: mod.y < 0 ? false : resizeLimit.y,
grid: mod.y < 0 ? false : opt.grid.y,
style: opt.modifiers.height,
direction: mod.y
};
if (mod.y < 0) resize.bind.y = binds.move.y;
}
binds.resize = drag.add(el, resize.opts, resize.bind);
if (opt.preserveRatio) {
var aspect = {
'x': {
fn: this.aspectStep.x,
style: ($defined(mod.x)) ? opt.modifiers.height : null,
direction: mod.x
},
'y': {
fn: this.aspectStep.y,
style: ($defined(mod.y)) ? opt.modifiers.width : null,
direction: mod.y
}
};
binds.aspect = drag.add(el, aspect, binds.resize);
}
this.fireEvent('onBuild', [d, binds]);
}
this.bound = (!this.options.hoverClass) ? {} : {
'mouseenter': function(ev) {
this.addClass(self.options.hoverClass);
},
'mouseleave': function(ev) {
if (!self.started) this.removeClass(self.options.hoverClass);
}
};
this.attach();
if (this.options.initialize) this.options.initialize();
},
add: function(callback) {
for (var d in this.options.direction)
callback.call(this, d, this.binds[d]);
},
attach: function() {
$each(this.bound, function(fn, ev) {
this.addEvent(ev, fn)
}, this.el);
for (var z in this.fx) this.element.adopt(this.fx[z].handle);
return this;
},
detach: function() {
$each(this.bound, function(fn, ev) {
this.removeEvent(ev, fn)
}, this.el);
for (var z in this.fx) this.fx[z].handle.remove();
return this;
},
stop: function() {
this.detach();
var garbage = [this.ghost];
for (var z in this.fx) garbage.push(this.fx[z].handle);
Garbage.trash(garbage);
this.fx = this.bound = this.binds = {};
}
});
Drag.Resize.implement(new Events, new Options);
Element.extend({
makeResizable: function(options) {
options = options || {};
if (options.handle)
return new Drag(this, $merge({modifiers: {'x': 'width', 'y': 'height'}}, options));
return new Drag.Resize(this, options);
}
});
Drag.ResizeImage = new Class({
initialize: function(el, options) {
this.image = $(el);
this.styles = this.image.getStyles('position', 'top', 'left', 'right', 'bottom', 'z-index', 'margin');
if (!['absolute', 'fixed', 'relative'].contains(this.styles.position)) this.styles.position = 'relative';
this.wrapper = new Element('div', {'styles': $merge(this.styles, {
'width': this.image.offsetWidth,
'height': this.image.offsetHeight
})}).injectBefore(this.image).adopt(
this.image.remove().setStyles({'position': 'absolute', 'top':'0', 'left':'0', 'margin':'0', 'width': '100%', 'height': '100%', 'zIndex': '0'})
);
this.fx = new Drag.Resize(this.wrapper, $merge({'preserveRatio': true}, options));
},
stop: function() {
this.image.setStyles($merge(this.styles, {'width': this.wrapper.getStyle('width'), 'height': this.wrapper.getStyle('height')})).remove().injectBefore(this.wrapper);
this.fx = null;
this.wrapper.remove(true);
}
});
var Windoo = new Class({
Extends: Options,
Implements: Events,
options: {
type: 'dom',
url: false,
title: 'Windoo!',
width: 300,
height: 200,
position: 'center',
top: 0,
left: 0,
resizable: true,
draggable: true,
positionStyle: 'absolute',
resizeLimit: {'x': [0], 'y': [0]},
padding: {'top': 0, 'right': 0, 'bottom': 0, 'left': 0},
ghost: {'resize': false, 'move': false},
snap: {'resize': 6, 'move': 6},
destroyOnClose: true,
container: null,
restrict: true,
theme: 'alphacube',
shadow: true,
modal: false,
buttons: {
menu: false,
close: true,
minimize: true,
roll: false,
maximize: true
},
'class': '',
wm: false,
effects: {
show: {
options: {'duration': 600},
styles: {'opacity': [0, 1]}
},
close: {
options: {'duration': 600},
styles: {'opacity': [1, 0]}
},
hide: {
options: {'duration': 600},
styles: {'opacity': [1, 0]}
}
},
onFocus: Class.empty,
onBlur: Class.empty,
onClose: Class.empty,
onDestroy: Class.empty,
onHide: Class.empty,
onShow: Class.empty,
onMaximize: Class.empty,
onMinimize: Class.empty,
onRestore: Class.empty,
onBeforeDrag: Class.empty,
onStartDrag: Class.empty,
onDrag: Class.empty,
onDragComplete: Class.empty,
onBeforeResize: Class.empty,
onStartResize: Class.empty,
onResize: Class.empty,
onResizeComplete: Class.empty
},
makeResizable: Class.empty,
makeDraggable: Class.empty,
initialize: function(options) {
var self = this;
this.fx = {};
this.bound = {};
this.padding = {};
this.panels = [];
this.zIndex = 0;
this.visible = false;
this.options.id = 'windoo-' + (new Date().getTime());
this.setOptions(options);
var theme = this.theme = $type(this.options.theme) == 'string' ? Windoo.Themes[this.options.theme] : this.options.theme;
this.options.container = $(this.options.container || document.body);
for (var side in theme.padding) this.padding[side] = theme.padding[side] + this.options.padding[side];
['x', 'y'].each(function(z) {
var lim = this.options.resizeLimit;
if ($type(lim[z][0]) == 'number') lim[z][0] = Math.max(lim[z][0], theme.resizeLimit[z][0])
}, this);
this.buildDOM()
.setSize(this.options.width, this.options.height)
.setTitle(this.options.title)
.fix();
if (this.options.position == 'center') this.positionAtCenter();
this.minimized = false;
if (this.options.draggable) this.makeDraggable();
if (this.options.resizable) this.makeResizable();
this.wm = this.options.wm || Windoo.$wm;
this.wm.register(this);
},
buildDOM: function() {
var theme = this.theme, _p = theme.classPrefix;
this.el = new Element('div', {
'id': this.options.id,
'class': theme.className,
'styles': {
'position': this.options.positionStyle,
'overflow': 'hidden',
'visibility': 'hidden',
'top': this.options.top,
'left': this.options.left
},
'events': {
'mousedown': this.focus.bind(this)
}
});
if (this.options['class']) this.el.addClass(this.options['class']);
var $row = function(prefix, contentClass) {
return '<div class="' + prefix + '-left ' + _p + '-drag"><div class="' + prefix + '-right"><div class="' + contentClass + '"></div></div></div>';
};
var iefix = window.ie && this.options.type != 'iframe';
this.el.innerHTML = '<div class="' + _p + '-frame">' + $row("top", "title") + $row("bot", "strut") + '</div><div class="' + _p + '-body">' + (iefix ? Windoo.ieTableCell : '') + '</div>';
this.el.inject(this.options.container);
if (window.ie) this.el.addClass(_p + '-' + theme.name + '-ie');
var frame = this.el.getFirst(),
body = this.el.getLast(),
title = frame.getElement('.title'),
titleText = new Element('div', {'class': 'title-text'}).inject(title);
frame.getElement('.strut').innerHTML = '&nbsp;',
this.dom = {
frame: frame,
body: body,
title: titleText,
strut: frame.getElement('.strut'),
content: iefix ? body.getElement('td') : body
};
this.dom.title.addEvent('dblclick', this.maximize.bind(this));
if (this.options.type == 'iframe') {
this.dom.iframe = new Element('iframe', {
'frameborder': '0',
'class': _p + '-body',
'styles': {'width': '100%', 'height': '100%'}
});
this.dom.body.setStyle('overflow', 'hidden');
this.adopt(this.dom.iframe).setURL(this.options.url);
}
return this.buildShadow().buildButtons();
},
buildButtons: function() {
var self = this, buttons = this.options.buttons, _p = this.theme.classPrefix;
var action = function(name, bind) {
return function(ev) {
new Event(ev).stop();
(bind[name])();
};
};
this.bound.noaction = function(ev) {
new Event(ev).stop();
};
var makeButton = function(opt, name, title, action) {
self.bound[name] = action;
if (opt) {
var klass = _p + '-button ' + _p + '-' + name + ( opt == 'disabled' ? ' ' + _p + '-' + name + '-disabled' : '' );
self.dom[name] = new Element('a', {'class': klass, 'href': '#', 'title': title}).innerHTML = 'x';
self.dom[name].inject(self.el);
self.dom[name].addEvent('click', opt == 'disabled' ? self.bound.noaction : action);
}
};
makeButton(buttons.close, 'close', 'Close', action('close', this));
makeButton(buttons.maximize, 'maximize', 'Maximize', action('maximize', this));
makeButton(buttons.minimize, 'minimize', 'Minimize', action(buttons.roll ? 'roll' : 'minimize', this));
makeButton(buttons.minimize, 'restore', 'Restore', action('minimize', this));
makeButton(buttons.menu, 'menu', 'Menu', action('openmenu', this));
return this;
},
buildShadow: function() {
var theme = this.theme;
if (this.options.modal) this.modalOverlay = new Fx.Overlay(this.el.getParent(), {'class': this.classPrefix('modal-overlay')});
if (!theme.shadow || !this.options.shadow) return this;
this.shadow = new Element('div', {
'styles': {
'position': this.options.positionStyle,
'display': 'none'
},
'class': theme.classPrefix + '-shadow-' + theme.shadow
}).injectAfter(this.el);
if (theme.complexShadow) {
var $row = function(name) {
var els = ['l', 'r', 'm'].map(function(e) {
return new Element('div', {'class': e});
});
var el = new Element('div', {'class': name});
return el.adopt.apply(el, els);
};
this.shadow.adopt($row('top'), this.dom.shm = $row('mid'), $row('bot'));
} else {
this.shadow.adopt(new Element('div', {'class': 'c'}));
}
return this;
},
setHTML: function(content) {
if (!this.dom.iframe) this.dom.content.empty().innerHTML = content;
return this;
},
adopt: function() {
this.dom.content.empty().adopt.apply(this.dom.content, arguments);
return this;
},
wrap: function(el, options) {
var styles = {'margin': '0', 'position': 'static'};
el = $(el);
options = options || {};
var size = el.getSize().size, pos = el.getPosition(), coeff = options.ignorePadding ? 0 : 1, pad = this.padding;
this.setSize(size.x + coeff * (pad.right + pad.left), size.y + coeff * (pad.top + pad.bottom));
if (options.resetWidth) styles.width = 'auto';
if (options.position) this.setPosition(pos.x - coeff * pad.left, pos.y - coeff * pad.top);
this.dom.content.empty().adopt(el.remove().setStyles(styles));
return this;
},
empty: function() {
if (this.dom.iframe) this.dom.iframe.src = 'about:blank';
else this.dom.content.empty();
return this;
},
setURL: function(url) {
if (this.dom.iframe) this.dom.iframe.src = url || 'about:blank';
return this;
},
getContent: function() {
return this.dom.content;
},
setTitle: function(title) {
this.dom.title.innerHTML = title || '&nbsp;';
return this;
},
effect: function(name, noeffect, onComplete) {
opts = {onComplete: onComplete};
if (noeffect) opts.duration = 0;
var fx = this.options.effects[name];
new Fx.Styles(fx.el || this.el, $merge(fx.options, opts)).start(fx.styles);
if (this.shadow) new Fx.Styles(this.shadow, fx.options).start(fx.styles);
return this;
},
hide: function(noeffect) {
if (!this.visible) return this;
this.visible = false;
return this.effect('hide', noeffect, function() {
this.el.setStyle('display', 'none');
if (this.modalOverlay) this.modalOverlay.hide();
this.fix(true).fireEvent('onHide');
}.bind(this));
},
show: function(noeffect) {
if (this.visible) return this;
this.visible = true;
if (this.modalOverlay) this.modalOverlay.show();
this.el.setStyle('display', '');
this.bringTop().fix();
if (this.shadow) this.shadow.setStyle('visibility', 'hidden');
return this.effect('show', noeffect, function() {
this.el.setStyle('visibility', 'visible');
this.fireEvent('onShow').fix();
}.bind(this));
},
fix: function(hide) {
this.el.$overlay(hide || !this.visible);
return this.fixShadow(hide);
},
fixShadow: function(hide) {
if (this.shadow) {
this.shadow[(this.maximized ? 'add' : 'remove') + 'Class']('windoo-shadow-' + this.theme.name + '-maximized');
if (hide || !this.visible) {
this.shadow.setStyle('display', 'none');
} else {
var pos = this.el.getCoordinates(), pad = this.theme.shadowDisplace;
this.shadow.setStyles({'display': '', 'zIndex': this.zIndex - 1,
'left': this.el.offsetLeft + pad.left, 'top': this.el.offsetTop + pad.top,
'width': pos.width + pad.width, 'height': pos.height + pad.height});
if (this.dom.shm) this.dom.shm.setStyle('height', pos.height - pad.delta);
}
}
return this;
},
getState: function() {
var outer = this.el.getCoordinates(), container = this.options.container,
cont = container === $(document.body) ? {'top': 0, 'left': 0} : container.getCoordinates();
outer.top -= cont.top;
outer.right -= cont.left;
outer.bottom -= cont.top;
outer.left -= cont.left;
return {outer: outer, inner: this.dom.content.getSize()};
},
setSize: function(width, height) {
var pad = this.padding;
this.el.setStyles({'width': width, 'height': height});
this.dom.strut.setStyle('height', Math.max(0, height - pad.top));
this.dom.body.setStyle('height', Math.max(0, height - pad.top - pad.bottom));
return this.fix().fireEvent('onResizeComplete', this.fx.resize);
},
positionAtCenter: function(offset) {
offset = $merge({'x': 0, 'y': 0}, offset);
var container = this.options.container;
if (container === document.body) container = window;
var s = container.getSize(), esize = this.el.getSize().size,
fn = function(z) {
return Math.max(0, offset[z] + s.scroll[z] + (s.size[z] - esize[z]) / 2);
};
this.el.setStyles({'left': fn('x'), 'top': fn('y')});
return this.fix();
},
setPosition: function(x, y) {
this.el.setStyles({'left': x, 'top': y});
return this.fix();
},
preventClose: function(prevent) {
this.$preventClose = $defined(prevent) ? prevent : true;
return this;
},
close: function(noeffect) {
this.$preventClose = false;
this.fireEvent('onBeforeClose');
if (this.$preventClose) return this;
if (!this.visible) return this;
this.visible = false;
return this.effect('close', noeffect, function() {
this.el.setStyle('display', 'none');
if (this.modalOverlay) this.modalOverlay.hide();
this.fix(true).fireEvent('onClose');
if (this.options.destroyOnClose) this.destroy();
}.bind(this));
},
destroy: function() {
this.fireEvent('onDestroy');
this.wm.unregister(this);
if (this.modalOverlay) this.modalOverlay.destroy();
if (this.shadow) this.shadow.remove(true);
this.el.remove(true);
for (var z in this) this[z] = null;
this.destroyed = true;
},
classPrefix: function(klass) {
return [this.theme.classPrefix, this.theme.name, klass + ' ' + this.theme.classPrefix, klass].join('-');
},
maximize: function(noeffect) {
if (this.minimized) return this.minimize();
if (this.rolled) this.roll(true);
var bound = function(value, limit) {
if (!limit) return value;
if (value < limit[0]) return limit[0];
if (limit.length > 1 && value > limit[1]) return limit[1];
return value;
};
var klass = this.classPrefix('maximized');
this.maximized = !this.maximized;
this.minimized = false;
if (this.maximized) {
this.$restoreMaxi = this.getState();
var container = this.options.container;
if (container === document.body) container = window;
var s = container.getSize(), limit = this.options.resizeLimit;
if (limit) for (var z in limit) s.size[z] = bound(s.size[z], limit[z]);
this.el.addClass(klass);
this.setSize(s.size.x, s.size.y)
.setPosition(s.scroll.x, s.scroll.y)
.fireEvent('onMaximize');
} else {
this.el.removeClass(klass);
this.restoreState(this.$restoreMaxi).fireEvent('onRestore', 'maximize');
}
return this.fix();
},
minimize: function(noeffect) {
var klass = this.classPrefix('minimized');
this.minimized = !this.minimized;
if (this.minimized) {
this.$restoreMini = this.getState();
var container = this.options.container;
if (container === document.body) container = window;
var s = container.getSize(), height = this.theme.padding.top + this.theme.padding.bottom;
this.el.addClass(klass);
this.setSize('auto', height)
.setPosition(s.scroll.x + 10, s.scroll.y + s.size.y - height - 10)
.fireEvent('onMinimize');
} else {
this.el.removeClass(klass);
this.restoreState(this.$restoreMini).fireEvent('onRestore', 'minimize');
}
return this.fix();
},
restoreState: function(state) {
state = state.outer;
return this.setSize(state.width, state.height).setPosition(state.left, state.top);
},
roll: function(noeffect) {
var klass = this.classPrefix('rolled');
this.rolled = !this.rolled;
if (this.rolled) {
this.$restoreRoll = this.getState().outer;
var pad = this.theme.padding;
this.setSize(this.$restoreRoll.width, pad.top + pad.bottom);
this.el.addClass(klass);
this.fireEvent('onRoll');
} else {
this.el.removeClass(klass);
var state = this.$restoreRoll;
this.setSize(state.width, state.height).fireEvent('onRestore', 'roll');
}
return this.fix();
},
openmenu: function() {
this.fireEvent('onMenu');
return this;
},
setZIndex: function(z) {
this.zIndex = z;
this.el.setStyle('zIndex', z);
if (this.el.fixOverlayElement) this.el.fixOverlayElement.setStyle('zIndex', z - 1);
if (this.shadow) this.shadow.setStyle('zIndex', z - 1);
if (this.fx.resize) this.fx.resize.options.zIndex = z + 1;
if (this.modalOverlay) this.modalOverlay.overlay.setStyle('zIndex', z - 2);
return this;
},
focus: function() {
this.el.removeClass(this.theme.classPrefix + '-blur');
this.wm.focus(this);
return this;
},
blur: function() {
this.el.addClass(this.theme.classPrefix + '-blur');
if (this.wm.blur(this)) this.fireEvent('onBlur');
return this;
},
bringTop: function() {
return this.setZIndex(this.wm.maxZIndex());
}
});
//Windoo.implement(new Events, new Options);
Windoo.ieTableCell = '<table style="position:absolute;top:0;left:0;border:none;border-collapse:collapse;padding:0;"><tr><td style="border:none;overflow:auto;position:relative;padding:0;"></td></tr></table>';
Windoo.Themes = {
cssFirefoxMac: '.windoo-blur * {overflow: hidden !important;}',
alphacube: {
'name': 'alphacube',
'padding': {'top': 22, 'right': 10, 'bottom': 15, 'left': 10},
'resizeLimit': {'x': [275], 'y': [37]},
'className': 'windoo windoo-alphacube',
'sizerClass': 'sizer',
'classPrefix': 'windoo',
'ghostClass': 'windoo-ghost windoo-alphacube-ghost windoo-hover',
'hoverClass': 'windoo-hover',
'shadow': 'simple window-shadow-alphacube-simple',
'shadeBackground': 'transparent url(windoo/s.gif)',
'shadowDisplace': {'left': 3, 'top': 3, 'width': 0, 'height': 0}
}
};
if (window.gecko && navigator.appVersion.indexOf('acintosh') >= 0) window.addEvent('domready', function() {
new Element('style', {'type': 'text/css', 'media': 'all'}).inject(document.head).appendText(Windoo.Themes.cssFirefoxMac);
});
Windoo.Manager = new Class({
Implements: Options,
focused: false,
options: {
zIndex: 100,
onRegister: Class.empty,
onUnregister: Class.empty,
onFocus: Class.empty,
onBlur: Class.empty
},
initialize: function(options) {
this.hash = [];
this.setOptions(options);
},
maxZIndex: function() {
var windows = this.hash;
if (!windows.length) return this.options.zIndex;
var zindex = [];
windows.each(function(item) {
this.push(item.zIndex);
}, zindex);
zindex.sort(function(a, b) {
return a - b;
});
return zindex.getLast() + 3;
},
register: function(win) {
win.setZIndex(this.maxZIndex());
this.hash.push(win);
return this.fireEvent('onRegister', win);
},
unregister: function(win) {
this.hash.remove(win);
if (this.focused === win) this.focused = false;
return this.fireEvent('onUnregister', win);
},
focus: function(win) {
var idx = this.hash.indexOf(win);
if (idx === this.focused) return this;
if (this.focused) this.focused.blur();
this.focused = win;
win.bringTop(this.maxZIndex());
return this.fireEvent('onFocus', win);
},
blur: function(win) {
if (this.focused === win) {
this.focused = false;
this.fireEvent('onBlur', win);
return true;
}
return false;
}
});
Windoo.Manager.implement(new Events, new Options);
Windoo.$wm = new Windoo.Manager();
Windoo.implement({
makeResizable: function() {
var self = this, theme = this.theme, opt = this.options, inbody = opt.container === $(document.body);
this.fx.resize = this.el.makeResizable({
ghostClass: theme.ghostClass,
hoverClass: theme.hoverClass,
classPrefix: theme.classPrefix + '-sizer ' + theme.classPrefix + '-',
shadeBackground: theme.shadeBackground,
container: (opt.restrict && !inbody) ? opt.container : false,
resizeLimit: opt.resizeLimit,
ghost: opt.ghost.resize,
snap: opt.snap.resize,
onBeforeStart: function() {
self.fireEvent('onBeforeResize', this).focus();
},
onStart: function(fx) {
if (self.maximized) {
fx.stop();
} else {
if (!this.ghost && window.gecko) Element.$overlay.call(fx.shade.overlay);
self.fireEvent('onStartResize', this);
}
},
onResize: function() {
self.fireEvent('onResize', this);
},
onComplete: function() {
if (this.ghost) {
var size = self.getState().outer;
self.setSize(size.width, size.height);
} else {
self.fix().fireEvent('onResizeComplete', this);
}
},
onBuild: function(dir, binds) {
if (!this.ghost) {
var fx = this.fx[dir], nolimit = {'x':{'limit': false}, 'y':{'limit': false}};
if (binds.resize.y) ['strut', 'body', 'shm'].each(function(name) {
if (this[name]) fx.add(this[name], {'y': {direction: binds.resize.y.direction, style: 'height'}}, binds.resize);
}, self.dom);
[self.shadow, self.el.fixOverlayElement].each(function(el) {
if (el) {
fx.add(el, $merge(binds.resize, nolimit), binds.resize);
if (binds.move) fx.add(el, $merge(binds.move, nolimit), binds.move);
}
}, self);
}
}
});
},
makeDraggable: function() {
var self = this, fx = this.fx.drag = [], inbody = this.options.container === $(document.body);
var xLimit = function() {
return 2 - self.el.offsetWidth;
};
var opts = {
container: (this.options.restrict && !inbody ? this.options.container : null),
limit: (inbody ? {'x': [xLimit], 'y': [0]} : {}),
snap: this.options.snap.move,
onBeforeStart: function() {
self.focus();
this.shade = new Fx.Overlay(window, {'styles': {
'cursor': this.options.handle.getStyle('cursor'),
'background': self.theme.shadeBackground,
'zIndex': self.zIndex + 3
}}).show();
if (self.ghost) {
var ce = self.el.getSize().size;
this.element.setStyles({
'zIndex': self.zIndex + 3,
'left': self.el.getStyle('left'),
'top': self.el.getStyle('top'),
'width': ce.x,
'height': ce.y
});
} else if (window.gecko) {
Element.$overlay.call(this.shade.overlay, false, 2);
}
self.fireEvent('onBeforeDrag', this);
},
onStart: function() {
if (self.maximized && !self.minimized) this.stop();
else self.fireEvent('onStartDrag', this);
},
onSnap: function() {
if (self.ghost) this.element.setStyle('display', 'block');
},
onDrag: function() {
self.fix().fireEvent('onDrag', this);
},
onComplete: function() {
this.shade.destroy();
if (self.ghost) {
for (var z in this.options.modifiers) {
var style = this.options.modifiers[z];
self.el.setStyle(style, this.element.getStyle(style));
}
this.element.setStyle('display', 'none');
}
self.fix().fireEvent('onDragComplete', this);
}
};
if (this.options.ghost.move) this.ghost = new Element('div', {'class': this.theme.ghostClass, 'styles': {'display': 'none'}}).injectAfter(this.el);
this.el.getElements('.' + this.theme.classPrefix + '-drag').each(function(d) {
opts.handle = d;
d.setStyle('cursor', 'move');
fx.push((this.ghost || this.el).makeDraggable(opts));
}, this);
}
});
Windoo.Themes.aero = {
'name': 'aero',
'padding': {'top': 28, 'right': 10, 'bottom': 15, 'left': 10},
'resizeLimit': {'x': [175], 'y': [58]},
'className': 'windoo windoo-aero',
'sizerClass': 'sizer',
'classPrefix': 'windoo',
'ghostClass': 'windoo-ghost windoo-aero-ghost windoo-hover',
'hoverClass': 'windoo-hover',
'shadow': 'simple window-shadow-aero-simple',
'shadeBackground': 'transparent url(windoo/s.gif)',
'shadowDisplace': {'left': 3, 'top': 3, 'width': 0, 'height': 0}
};
Windoo.Themes.wise = {
'name': 'wise',
'padding': {'top': 28, 'right': 10, 'bottom': 15, 'left': 10},
'resizeLimit': {'x': [175], 'y': [58]},
'className': 'windoo windoo-wise',
'sizerClass': 'sizer',
'classPrefix': 'windoo',
'ghostClass': 'windoo-ghost windoo-wise-ghost windoo-hover',
'hoverClass': 'windoo-hover'
};
Windoo.Themes.aqua = {
'name': 'aqua',
'padding': {'top': 23, 'right': 0, 'bottom': 15, 'left': 0},
'resizeLimit': {'x': [275], 'y': [37]},
'className': 'windoo windoo-aqua',
'sizerClass': 'sizer',
'classPrefix': 'windoo',
'ghostClass': 'windoo-ghost windoo-aqua-ghost windoo-hover',
'hoverClass': 'windoo-hover',
'shadeBackground': 'transparent url(themes/windoo/s.gif)',
'shadow': 'aqua',
'complexShadow': true,
'shadowDisplace': {'left': -13, 'top': -8, 'width': 26, 'height': 31, 'delta': 23}
};
Windoo.Ajax = Ajax.extend({
onComplete: function() {
if (this.options.window) this.options.window.innerHTML = this.response.text;
this.parent();
}
});
Windoo.implement({
addPanel: function(element, position) {
position = $pick(position, 'bottom');
var dim, ndim,
size = this.el.getSize().size,
styles = {'position': 'absolute'},
panel = {'element': $(element), 'position': position, 'fx': []};
switch (position) {
case 'top':
case 'bottom':
dim = 'x';
ndim = 'y';
break;
case 'left':
case 'right':
dim = 'y';
ndim = 'x';
break;
default:
return this;
}
var options = Windoo.panelOptions[dim];
styles[position] = this.padding[position];
styles[options.deltaP] = this.padding[options.deltaP];
element = panel.element.addClass(this.classPrefix('pane')).setStyles(styles).inject(this.el);
panel.padding = element.getSize().size[ndim];
this.padding[position] += panel.padding;
if (this.options.resizable && !this.options.ghost.resize) {
this.fx.resize.add(function(dir, binds) {
if (binds.resize[dim]) {
var fx = this.fx[dir], mod = {};
mod[dim] = $merge(binds.resize[dim]);
mod[dim].limit = null;
panel.fx.push({
'fx': fx,
'bind': fx.add(panel.element, mod, binds.resize)
});
}
});
}
this.addEvent('onResizeComplete', function() {
panel.element.setStyle(options.style, this.el.getSize().size[dim] - this.padding[options.deltaM] - this.padding[options.deltaP] - 1);
});
this.panels.push(panel);
return this.setSize(size.x, size.y);
},
removePanel: function(element) {
var panel, size;
element = $(element);
for (var i = 0, len = this.panels.length; i < len; i++) {
panel = this.panels[i];
if (panel.element === element) {
this.padding[panel.position] -= panel.padding;
panel.element.remove();
panel.fx.each(function(pfx) {
pfx.fx.detach(pfx.bind);
}, this);
this.panels.splice(i, 1);
size = this.el.getSize().size;
this.setSize(size.x, size.y);
break;
}
}
return this;
}
});
Windoo.panelOptions = {
'x': {'style': 'width', 'deltaP': 'left', 'deltaM': 'right'},
'y': {'style': 'height', 'deltaP': 'top', 'deltaM': 'bottom'}
};
Windoo.Dialog = Windoo.extend({
initialize: function(message, options) {
var self = this, dialog = this.dialog = {
dom: {},
buttons: {},
options: $merge(Windoo.Dialog.options, options),
message: message
};
this.parent($merge({
'onShow': function() {
if (dialog.buttons.ok) dialog.buttons.ok.focus();
}
}, dialog.options.window));
dialog.bound = function(ev) {
ev = new Event(ev);
if (['enter', 'esc'].contains(ev.key)) {
dialog.result = (ev.key == 'enter') ? !dialog.cancelFocused : false;
self.close();
ev.stop();
}
};
document.addEvent('keydown', dialog.bound);
this.addEvent('onClose', function() {
document.removeEvent('keydown', dialog.bound);
dialog.options[(dialog.result) ? 'onConfirm' : 'onCancel'].call(this);
});
},
buildDialog: function(klass, buttons) {
var self = this, dialog = this.dialog;
if ('ok' in buttons) dialog.buttons.ok = new Element('input', $merge({
'events': {
'click': function() {
dialog.result = true;
self.close();
}
}
}, dialog.options.buttons.ok));
if ('cancel' in buttons) dialog.buttons.cancel = new Element('input', $merge({
'events': {
'click': function() {
dialog.result = false;
self.close();
}
}
}, dialog.options.buttons.cancel)).addEvents({
'focus': function() {
dialog.cancelFocused = true;
},
'blur': function() {
dialog.cancelFocused = false;
}
});
dialog.dom.panel = new Element('div', $merge({'class': this.classPrefix(klass + '-pane')}, dialog.options.panel));
for (var btn in buttons) if (buttons[btn]) dialog.dom.panel.adopt(dialog.buttons[btn]);
dialog.dom.message = new Element('div', $merge({'class': this.classPrefix(klass + '-message')}, dialog.options.message));
dialog.dom.message.innerHTML = dialog.message;
return this.addPanel(dialog.dom.panel).adopt(dialog.dom.message);
}
});
Windoo.Dialog.options = {
'window': {
'modal': true,
'resizable': false,
'buttons': {
'minimize': false,
'maximize': false
}
},
'buttons': {
'ok': {
'properties': {
'type': 'button',
'value': 'OK'
}
},
'cancel': {
'properties': {
'type': 'button',
'value': 'Cancel'
}
}
},
'panel': null,
'message': null,
'onConfirm': Class.empty,
'onCancel': Class.empty
};
Windoo.Alert = Windoo.Dialog.extend({
initialize: function(message, options) {
this.parent(message, options);
this.buildDialog('alert', {'ok': true}).show();
}
});
Windoo.Confirm = Windoo.Dialog.extend({
initialize: function(message, options) {
this.parent(message, options);
this.buildDialog('confirm', {'ok': true, 'cancel': true}).show();
}
});