Skip to content

Instantly share code, notes, and snippets.

@sebmarkbage
Created August 8, 2010 00:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sebmarkbage/513373 to your computer and use it in GitHub Desktop.
Save sebmarkbage/513373 to your computer and use it in GitHub Desktop.
Old Lightbox implementation by Leon Radley and Sebastian Markbåge at Calyptus Life AB
.Lightbox
{
position: absolute;
background: #fff;
border: 10px solid #fff;
width: 200px;
height: 200px;
top: 50%;
left: 50%;
margin: -100px;
overflow: hidden;
z-index: 2;
visibility: hidden;
}
.LightboxLoading
{
background-image: url(loading.gif);
background-position: center;
background-repeat: no-repeat;
}
.Lightbox .Content
{
position: relative;
overflow: hidden;
}
.Lightbox .Content .Image
{
position: relative;
}
.Lightbox .Content .Image .Next,
.Lightbox .Content .Image .Previous
{
display: block;
top: 0;
width: 49%;
height: 100%;
outline: 0;
}
.Lightbox .Content .Image .Next
{
float: right;
}
.Lightbox .Content .Image .Next:hover
{
background: transparent url(next.gif) no-repeat 100% 15%;
}
.Lightbox .Content .Image .Previous
{
float: left;
}
.Lightbox .Content .Image .Previous:hover
{
background: transparent url(previous.gif) no-repeat 0% 15%;
}
.Lightbox .Content .Bottom
{
position: relative;
width: 100%;
overflow: hidden;
}
.Lightbox .Content .Bottom .Title
{
margin: .3em;
}
.Lightbox .Content .Bottom .Close
{
display: inline;
float: right;
width: 32px;
height: 32px;
background: transparent url(close.gif) no-repeat center;
margin: 10px 0 10px 10px;
}
addEvent('domready', function(){
var overlay = new Popup.Overlay({
styles: {
position: 'absolute',
width: '100%',
height: '100%',
top: '0',
left: '0',
backgroundColor: '#7E7E7E'
}
});
var lightbox = new Popup.Lightbox(false, { holder: overlay });
$$('a[rel^=Lightbox]').each(function(a){
lightbox.add(a.href, a.title);
a.addEvent('click', function(e){ e.preventDefault(); lightbox.show(this.href, this.title); });
});
});
var Popup = new Class({
Implements: [Options, Events],
options: {
/*
onLoad
onShow: $empty,
onHide: $empty,
onTransition: $empty,
onCancel: $empty,
multipleChildren: false,
hideWhenEmpty: false,
*/
chainChildren: true
},
/*
visible: false,
*/
children: [],
initialize: function(element, options){
this.element = $(element);
if (options && options.holder){
options.holder.addChild(this);
delete options.holder;
}
this.setOptions(options);
},
addChild: function(child){
child.holder = this;
this.children.include(child);
},
show: function(){
if (this.holder)
if (!this.holder.shown)
this.holder.show();
else if (!this.holder.options.multipleChildren) {
var th = this;
this.holder.children.each(function(c){if(c != th) c._hide();});
}
if (this.visible) {
this.call(this.onTransition.bind(this, arguments));
} else {
this.visible = true;
this.call(this.onShow.bind(this, arguments));
}
},
hide: function(){
if (this.holder && this.holder.visible && this.holder.options.hideWhenEmpty){
var cs = this.holder.children;
for(var i=0;i<cs.length;i++)
if (cs[i].visible && cs[i] != this){
this._hide();
return;
}
this.holder.hide();
return;
}
this._hide();
},
_hide: function(){
if (this.visible){
this.children.each(function(c){ c._hide(); });
this.visible = false;
this.call(this.onHide);
}
},
$next: $empty,
requestQueue: function(p){
if (this.holder)
this.holder.requestQueue(p);
else if (this.running){
(this.$queue = (this.$queue || []).erase(p)).push(p);
} else {
this.running = true;
p.callNext();
}
},
nextInQueue: function(){
if (this.holder)
this.holder.nextInQueue();
else if (this.$queue && this.$queue.length > 0)
this.$queue.shift().callNext();
else
this.running = false;
},
call: function(f){
//this.cancel();
this.$next = f;
this.requestQueue(this);
},
callNext: function(){
this.running = true;
this.$next.apply(this);
this.$next = $empty;
},
cancel: function(){
if (this.running){
this.running = false;
this.$next = false;
if (this.$queue) this.$queue.empty();
this.children.each(function(c){c.cancel();});
}
},
complete: function(){
this.running = false;
this.nextInQueue();
},
onShow: function(){ return this.fireEvent('onShow', arguments); },
onHide: function(){ return this.fireEvent('onHide', arguments); },
onTransition: function(){ return this.fireEvent('onTransition', arguments); },
onCancel: function(){ return this.fireEvent('onCancel', arguments); }
});
Popup.Lightbox = new Class({
Extends: Popup,
options: {
elementFx: { duration: 300 },
contentFx: { duration: 500 }
},
/*
content: $empty,
image: $empty,
title: $empty,
*/
images: [],
titles: new Hash(),
current: $empty,
initialize: function(element, options){
if($type(element) == 'object') options = element;
var e = this.element = $(element) || new Element('div', { 'class': 'Lightbox', html: '<div class="Content"><div class="Image"><a class="Next" href="javascript:void(0);"></a><a class="Previous" href="javascript:void(0);"></a></div><div class="Bottom"><a class="Close" href="javascript:void(0);"></a><div class="Title"></div></div></div>' });
if(options){
if (options.elementFx) this.options.elementFx = options.elementFx;
if (options.contentFx) this.options.contentFx = options.contentFx;
this.setOptions(options);
}
e.set('tabindex', -1);
this.elementFx = new Fx.Morph(e, $merge(this.options.elementFx, {link: 'cancel'}));
this.elementFx.set({'opacity': 0});
var s = e.setStyle;
e.setStyle = function() { s.apply(this, arguments); var z = this.getSize(); s.apply(s.apply(this, ['marginTop', -(z.y/2)]), ['marginLeft', -(z.x/2)]); };
this.content = e.getElement('.Content');
this.contentFx = new Fx.Morph(this.content, $merge(this.options.contentFx, {link: 'cancel'}));
this.contentFx.set({'opacity': 0});
this.image = e.getElement('.Image');
var actions = new Hash({'.Next': this.next, '.Previous': this.previous, '.Close': this.hide})
var t = this;
actions.each(function(fn, k){
var a = e.getElement(k);
if(a) a.addEvent('click', function(e) { e.preventDefault(); fn.apply(t, arguments); });
});
this.title = e.getElement('.Title');
this.element.addEvent('keyup', this.keyboardListener.bindWithEvent(this));
arguments.callee.parent(this.element, options);
},
onShow: function(url, title){
if(this.holder)
this.holder.element.adopt(this.element);
else
this.element.inject(document.body);
this.element.addClass('LightboxLoading');
this.current = url;
if($defined(title)) this.titles.set(url, title);
var loaded = false;
var img = new Asset.image(url, {onload: function(){ this.element.removeClass('LightboxLoading'); if(this.elementFx.timer || this.contentFx.timer) loaded = true; else this.animation(img); }.bind(this)});
this.elementFx.start({'opacity': 1}).chain(function(){
if(loaded)
this.animation(img);
}.bind(this));
},
onHide: function(){
this.elementFx.start({'opacity': 0}).chain(function(){
this.contentFx.set({'opacity': 0});
this.element.dispose();
this.complete();
}.bind(this));
},
onTransition: function(url){
this.contentFx.start({'opacity': 0}).chain(
this.onShow.bind(this, arguments)
);
},
onCancel: function(){
this.elementFx.cancel();
this.contentFx.cancel();
},
animation: function(img){
this.image.setStyles({'backgroundImage': 'url(' + img.src + ')', width: img.width, height: img.height});
if (this.title) this.title.set('html', this.titles.get(img.src));
var w = img.width;
this.elementFx.start({'width': w}).chain(function(){
var h = this.content.getScrollHeight();
this.elementFx.start({'height': h}).chain(function(){
this.contentFx.start({'opacity': 1}).chain(function(){
this.element.focus();
this.complete();
}.bind(this));
}.bind(this));
}.bind(this));
},
add: function(url, title){
this.images.include(url);
this.titles.set(url, title);
return this;
},
next: function(){
var i = this.images.indexOf(this.current);
i = (i >= this.images.length-1) ? 0 : i+1;
return this.show(this.current = this.images[i]);
},
previous: function(){
var i = this.images.indexOf(this.current);
i = (i <= 0) ? this.images.length-1 : i-1;
return this.show(this.current = this.images[i]);
},
keyboardListener: function(e){
switch (e.key){
case 'esc': case 'backspace': case 'delete': this.hide(); break;
case 'left': case 'down': this.previous(); break;
case 'right': case 'up': this.next();
}
}
});
Popup.Overlay = new Class({
Extends: Popup,
options: {
/*
parentElement: false,
className: null,
fx: { },
*/
styles: {
position: 'absolute',
width: '100%',
height: '100%',
top: '0',
left: '0',
backgroundColor: '#000000'
},
showStyle: {opacity: .8},
hideStyle: {opacity: 0},
hideWhenEmpty: true
},
initialize: function(options){
if (options){
if (options.showStyle) this.options.showStyle = options.showStyle;
if (options.hideStyle) this.options.hideStyle = options.hideStyle;
this.setOptions(options);
}
var fix = Browser.Engine.trident5 || Browser.Engine.gecko || Browser.Engine.webkit || Browser.Engine.presto;
var pe = $(this.options.parentElement) || $(document.body);
var element = new Element('div', {
'styles': {
position: fix ? 'fixed' : 'absolute',
display: 'none',
visibility: 'visible',
width: '100%',
height: '100%',
overflow: 'hidden',
top: 0,
left: 0,
margin: 0,
padding: 0,
border: 0,
zIndex: 1000
}
}).inject(pe);
this.bg = new Element('div', {
'class': this.options.className,
'styles': this.options.styles,
'events': { click: this.hide.bind(this) }
}).inject(element);
this.morph = new Fx.Morph(this.bg, $merge(this.options.fx, { link: 'cancel', onComplete: this.complete.bind(this) }));
this.morph.set(this.options.hideStyle);
arguments.callee.parent(element, options);
if (!fix){
(pe.get('tag') == 'body' ? window : pe).addEvent('scroll', this.posFix.bind(this, pe)).addEvent('resize', this.posFix.bind(this, pe));
this.posFix(pe);
}
},
posFix: function(pe){
var p = pe.getScroll(), s = pe.getSize();
this.element.set('styles', {top: p.y, left: p.x, height: s.y + 'px', width: s.x + 'px'});
},
onShow: function(){
this.element.setStyle('display', 'block');
this.morph.start(this.options.showStyle);
arguments.callee.parent.apply(this, arguments);
},
onHide: function(){
this.morph.start(this.options.hideStyle).chain(function(){
this.element.setStyle('display', 'none');
}.bind(this));
arguments.callee.parent.apply(this, arguments);
},
onTransition: function(){
this.complete();
arguments.callee.parent.apply(this, arguments);
},
onCancel: function(){
this.morph.cancel();
arguments.callee.parent.apply(this, arguments);
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment