/** * ReMooz - Zoomer * Inspired by so many boxes and zooms * * @version		1.0 * @modified	Mar 11, 2008 * * @license		MIT-style license * @author		Harald Kirschner <mail [at] digitarald.de>, Alvis Tang <alvis.sty [at] gmail.com> * @copyright	Author */var ReMooz = new Class({	Implements: [Events, Options, Chain],	options: {		caption: true, /* Enable caption */		centered: true, /* Center the box */		className: null, /* Extra class applied to ReMooz box */		closer: true, /* Display closer icon on the box (Note: No transition applies on IE since it has problem on handling opacity) */		closeOnClick: true, /* Close box by click */		closeOnDblClick: false, /* Close box by double click */		container: null, /* Box container */		dragging: true, /* Enable box dragging */		size: false, /* Size of the box e.g. {x: 640, y: 640} */		hideSource: true, /* Hide source element after opening the box */		loadingOpacity: 0.7, /* Opacity applied on source element */		margin: 20, /* Margin of the box */		openOnClick: true, /* Enable click to open */		openOnDblClick: false, /* Enable click to open */		resize: true, /* Shrink oversize picture */		resizeFactor: 0.9, /* Fraction of the screen for displaying the box */		resizeLimit: false, /* Maximum size of the box e.g. {x: 640, y: 640}*/		resizeOptions: {			transition: Fx.Transitions.Back.easeOut		}, /* Options applied during resize */		shadow: false, /* Enable shadow */		type: 'image', /* Type of the box. (element/flash/iframe/image) */		title: false, /* Caption title */		content: false, /* Caption content */		source: false, /* Source of which the box would load (Usually set in 'rel' or by default from 'src' or 'href' of parent) */		onLoad: $empty,		onOpen: $empty,		onOpenEnd: $empty,		onClose: $empty,		onCloseEnd: $empty,		onError: $empty,		generateCaption: function(el){			if (!$defined(el)) return;						var title = this.options.title || el.getProperty('alt') || el.getProperty('title');			var content = this.options.content;			if (!title && !content) return false;			var head = new Element('h6', {				'text': title			});			return (content) ? [head, new Element('p', {				'text': content			})] : head;		},		generateElement: $empty	},	initialize: function(element, options){		this.elements = $(element) || $$(element);		if ($type((this.elements)) == 'element') this.elements = [this.elements];		this.setOptions(options);		this.defaultOptions = this.options;		this.container = $(this.options.container) || document;				if (this.options.openOnClick) this.elements.each((function(element){			var open = (function(e){				this.open.delay(1, this, element);				return false;			}).bind(this);						element.addClass('remooz-element')						if (this.options.openOnClick && this.options.type == 'image') element.addClass('remooz-box-zoom-in');			if (this.options.openOnClick) element.addEvent('click', open);			if (this.options.openOnDblClick) element.addEvent('dblclick', open);		}).bind(this));	},	open: function(element, options){		if (this.loading) return;				if (this.opened) {			this.close();			this.chain(this.open.pass(element, this));			this.loading = true;						return;		}				this.element = element;		this.options = this.defaultOptions;		try {			var elOptions = JSON.decode(this.element.get('rel'));		} catch (e) {			var elOptions = {};		}		this.setOptions(elOptions);		this.setOptions(options);				if (!['image', 'iframe', 'flash', 'element'].contains(this.options.type)) {			this.fireEvent('onError', 'Type not defined');			return;		}		this.loading = true;		this.fireEvent('onLoad');				if (!this.box) this.build();		var classes = ['remooz-box', 'remooz-type-' + this.options.type, 'remooz-engine-' + Browser.Engine.name, 'remooz-engine-' + Browser.Engine.name + Browser.Engine.version];		if (this.options.className) classes.push(this.options.className);		this.styles = $merge(this.getElementCoordinates(), {			opacity: this.options.loadingOpacity		});		this.box.set({			'class': classes.join(' '),			styles: $merge(this.styles, {				display: ''			})		}).addClass('remooz-loading');		this.body.empty();		this['open' + this.options.type.capitalize()]();				window.addEvent('keydown', (function(e){			if (e.key == 'esc') this.close();		}).bind(this));				return this;	},	close: function(){		if (this.loading) this.box.set('styles', {			display: 'none'		});		this.fireEvent('onClose');		window.removeEvents('keydown');		this.box.removeEvents('click');		this.box.removeEvents('dblclick');		if (this.content) this.content.removeClass('remooz-box-zoom-out');		if (this.drag) this.drag.detach();				var fadeCloser = this.options.closer ? (function(){			if (!Browser.Engine.trident) {				this.closer.set('tween', {					duration: 'short',					onComplete: this.callChain.bind(this)				}).fade('out');			} else {				this.closer.fade('hide');				this.callChain();			}		}).bind(this) : this.callChain;		var fadeCaption = this.options.caption ? (function(){			this.caption.set('tween', {				duration: 'short',				onComplete: this.callChain.bind(this)			}).fade('out');		}).bind(this) : this.callChain;		var fadeBox = (function(){			if (!this.options.type.test('image|flash') && this.content) {				this.content.destroy();				this.content = null;			}			this.caption.getElement('.remooz-caption-content').empty();			this.box.set('morph', {				onComplete: this.callChain.bind(this)			}).morph(this.styles);			if (this.shadow) this.shadow.fade('out');		}).bind(this)		var hideBox = (function(){			this.box.set('styles', {				display: 'none'			});			if (this.content){				this.content.destroy();				this.content = null;			}			if (this.element) this.element.fade('show');			this.callChain();		}).bind(this)		var onCloseEnd = (function(){			this.fireEvent('onCloseEnd');			this.loading = false;			this.opened = false;			this.callChain();		}).bind(this)				var emptyChain = this.$chain ? !this.$chain.length : true;		this.chain(fadeCloser, fadeCaption, fadeBox, hideBox, onCloseEnd);		if (emptyChain) this.callChain();				return this;	},	openElement: function(){		this.content = this.options.generateElement(this.element) || $(this.options.source) || $E(this.options.source);		if (!this.content) {			this.fireEvent('onError', 'Element not defined').close();			return;		}		this.content.getElements('*').addEvent('click', function(){			this.focus();		});		this.content.inject(this.body);		this.zoomRelative();	},	openFlash: function(){		try {			this.options.source = this.options.source || this.element.get('href');		} catch (e) {			this.fireEvent('onError', 'Source not defined').close();			return;		}				var inject = (function(){			var size = this.body.getSize();			this.content.set({				height: size.y,				width: size.x			}).inject(this.body);			this.callChain();		}).bind(this);		this.content = new Element('object', {			data: this.options.source,			type: 'application/x-shockwave-flash'		}).adopt(new Element('param', {			name: 'wmode',			value: 'transparent'		}));				this.zoomRelative();		this.chain(inject);	},	openIframe: function(){		try {			this.options.source = this.options.source || this.element.get('href');		} catch (e) {			this.fireEvent('onError', 'Source not defined').close();			return;		}				var inject = (function(){			this.content.inject(this.body);			this.callChain();		}).bind(this);		this.content = new IFrame({			src: this.options.source,			height: '100%',			width: '100%'		});				this.zoomRelative();		this.chain(inject);	},	openImage: function(){		var prefetch = new Image();				prefetch.onload = (function(fast){			prefetch.onload = prefetch.onabort = prefetch.onerror = null;			var size = {				x: prefetch.width,				y: prefetch.height			};			this.content = $(prefetch).inject(this.body);			this[(this.options.resize) ? 'zoomRelative' : 'zoom'](size);		}).bind(this);				prefetch.onabort = prefetch.onerror = (function(){			prefetch.onload = prefetch.onabort = prefetch.onerror = null;			this.fireEvent('onError', 'File unreachable').close();		}).bind(this)				try {			prefetch.src = this.options.source || this.element.getParent().get('href') || this.element.get('href') || this.element.get('src');		} catch (e) {			this.fireEvent('onError', 'Source not defined').close();		}				if (prefetch && prefetch.complete && prefetch.onload) prefetch.onload(true);	},	zoomRelative: function(size){		size = size || this.container.getSize();		var scale = this.options.resizeLimit;		if (!scale) {			scale = this.container.getSize();			scale = {				x: (scale.x * this.options.resizeFactor).toInt(),				y: (scale.y * this.options.resizeFactor).toInt()			}		}				var oversize = scale && (size.x > scale.x || size.y > scale.y)		var xDominant = scale && size.x / size.y > scale.x / scale.y;				if (oversize) {			size = xDominant ? {				x: scale.x,				y: (size.y * scale.x / size.x).toInt()			} : {				x: (size.x * scale.y / size.y).toInt(),				y: scale.y			}		}				return this.zoom(size);	},	zoom: function(size){		size = this.options.size || size;		var container = this.container.getSize(), scroll = this.container.getScroll();		var position = (this.options.centered) ? {			x: scroll.x + ((container.x - size.x) / 2).toInt(),			y: scroll.y + ((container.y - size.y) / 2).toInt()		} : {			x: (this.styles.left + (this.styles.width / 2) - size.x / 2).toInt().limit(scroll.x + this.options.margin, scroll.x + container.x - this.options.margin - size.x),			y: (this.styles.top + (this.styles.height / 2) - size.y / 2).toInt().limit(scroll.y + this.options.margin, scroll.y + container.y - this.options.margin - size.y)		};		var to = {			left: position.x,			top: position.y,			width: size.x,			height: size.y,			opacity: 1		};				this.fireEvent('onOpen');		if (this.options.closeOnClick) this.box.addEvent('click', this.close.bind(this));		if (this.options.closeOnDblClick) this.box.addEvent('dblclick', this.close.bind(this));		if (this.options.hideSource && this.element) this.element.fade('hide');		if (this.options.closeOnClick && this.options.type == 'image') this.content.addClass('remooz-box-zoom-out');		if (this.element && this.element.getTag() != 'img') this.box.set('opacity', 0);		this.box.removeClass('remooz-loading');				if (this.shadow && this.options.shadow) this.shadow.fade('in');				if (this.options.dragging) {			this.drag = this.drag ? this.drag.attach() : new Drag.Move(this.box, {				onStart: (function(el){					this.box.removeEvents('click');				}).bind(this),				onSnap: (function(){					this.box.addClass('remooz-box-dragging');				}).bind(this),				onComplete: (function(){					this.box.removeClass('remooz-box-dragging');					if (this.options.closeOnClick) this.box.addEvent.delay(100, this.box, ['click', this.close.bind(this)]);				}).bind(this)			});		}				var fadeBox = (function(){			this.box.set('morph', $merge(this.options.resizeOptions, {				onComplete: this.callChain.bind(this)			})).morph(to);		}).bind(this)		var fadeCloser = this.options.closer ? (function(){			if (!Browser.Engine.trident) {				this.closer.set('tween', {					duration: 'short',					onComplete: this.callChain.bind(this)				}).fade('in');			} else {				this.closer.fade('show');				this.callChain();			}		}).bind(this) : this.callChain;		var fadeCaption = this.options.caption && this.options.type == 'image' ? (function(){			var caption = this.options.generateCaption.apply(this, [this.element]);			if (caption) {				this.caption.getElement('.remooz-caption-content').adopt(caption);				this.caption.set('tween', {					duration: 'short',					onComplete: this.callChain.bind(this)				}).fade('in');			} else this.callChain();		}).bind(this) : this.callChain;		var onOpenEnd = (function(){			this.fireEvent('onOpenEnd');			this.loading = false;			this.opened = true;			this.callChain();		}).bind(this);				var emptyChain = this.$chain ? !this.$chain.length : true;		this.chain(fadeBox, fadeCloser, fadeCaption, onOpenEnd);		if (emptyChain) this.callChain();	},	build: function(){		this.box = new Element('div', {			styles: {				display: 'none'			}		}).inject(document.body);		;				this.caption = new Element('div', {			'class': 'remooz-caption',			opacity: 0		}).adopt(new Element('div', {			'class': 'remooz-caption-bg',			opacity: 0.75		}), new Element('div', {			'class': 'remooz-caption-content'		})).inject(this.box);				this.closer = new Element('a', {			'class': 'remooz-btn-close',			opacity: 0,			events: {				click: this.close.bind(this)			}		}).inject(this.box);				if (!Browser.Engine.trident || Browser.Engine.trident5) {			this.shadow = new Element('div', {				'class': 'remooz-bg-wrap',				opacity: 0			}).inject(this.box);			['n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw'].each(function(direction){				new Element('div', {					'class': 'remooz-bg remooz-bg-' + direction				}).inject(this.shadow);			}, this);		}				this.body = new Element('div', {			'class': 'remooz-body'		}).inject(this.box);	},	getElementCoordinates: function(){		if (this.element) {			var coords = this.element.getCoordinates();			delete coords.right;			delete coords.bottom;		} else {			var container = this.container.getSize(), scroll = this.container.getScroll();			var coords = {				x: scroll.x + (container.x / 2).toInt(),				y: scroll.y + (container.y / 2).toInt(),				height: 0,				width: 0			};		}				return coords;	}});