var StyleWriter = new Class({
// css classes on the fly, based on by Aaaron Newton's version
createStyle: function(css, id) {
try {
if (document.id(id) && id) return;
var style = new Element('style', {id: id||'',type:'text/css'}).inject($$('head')[0]);
if (Browser.Engine.trident)
style.styleSheet.cssText = css;
else
style.set('text', css);
} catch(e) {C.log("failed:", e);}
}
});
var largerBox = new Class({
author: "Dimitar Christoff",
homepage: "http://fragged.org/",
version: "3.01b",
changed: "18/11/2009 13:33:45",
Implements: [Options,Events,StyleWriter],
options: {
links: [], // pass on array of anchors that contain links to images.
imageStyles: {
border: "1px solid #000", // border style around image,
background: "#fff", // useful to have one for underneath a png or gif with transparency
zIndex: 1000000000, // default z-index for the enlarged images
position: "absolute" // don't change this.
},
imageClass: "largerBox",
imageBorder: 3,
imageEvents: {
mouseenter: $empty(), // function on mouseover.
mouseleave: $empty()
},
shadows: { // enlarged image shadow filters, tweak as needed
enabled: true,
gecko: { // Firefox
"-moz-box-shadow": "1px 1px 2px #000"
},
webkit: { // Chrome and Safari
"-webkit-box-shadow": "1px 1px 2px #000"
},
trident: { // IE
"filter": "progid:DXImageTransform.Microsoft.Shadow(color=#000000,direction=135,strength=2)"
},
presto: { // Opera 10+
"box-shadow": "1px 1px 2px #000"
}
},
modal: { // options to do with modal div.
enabled: true,
background: "#fff", // default colour for modal tint
zIndex: 1000000000 - 1,
opacity: .7,
events: $empty() // for example, onclick you may want to close all.
},
controls: {
enabled: true,
useBase64: true, // look at embeddedStyles at bottom.
opacity: .6
},
closeButton: "/images/button-close.png"
},
cache: [], // store all loaded images.
initialize: function(options) {
this.setOptions(options);
this.container = $(this.options.container) || $(document.body); // could change this, i suppose.
this.elements = this.options.links.length ? this.options.links : [];
// test for base64 support and halt initialize until it's done
this.testImage = new Element("img", {
src: "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==",
events: {
load: function() {
this.reInitialize();
}.bind(this),
error: function() {
this.reInitialize();
}.bind(this)
}
}).inject(this.container);
},
reInitialize: function() {
// initialize, continued after we know of base64 support
$extend(Browser.Features, {
base64: this.testImage.width == 1 && this.testImage.height == 1
});
if (this.testImage)
this.testImage.destroy();
// can we use base64 at all?
if (this.options.controls.useBase64)
this.options.controls.useBase64 = (this.options.controls.useBase64 && Browser.Features.base64) ? true : false;
// kick start it all!
this.attachAllEvents();
// add overflow class to css
this.createStyle(this.options.controls.useBase64 ? this.embeddedStyles[1].join("\n") : this.embeddedStyles[0].join("\n") , "largerBox");
},
attachAllEvents: function() {
// attach all events to this.elements.
// call this if you have loaded new data into the .elements member to re-init
this.elements.each(function(el) {
this.attachEvents(el);
}.bind(this));
},
attachEvents: function(el) {
// attach events to a single image element.
el.addEvents({
mouseenter: function(e) {
// if we want some hover effect like mini-zoom, shake, etc.
this.options.imageEvents.mouseenter(el);
}.bind(this),
mouseleave: function(e) {
this.options.imageEvents.mouseleave(el);
}.bind(this),
click: function(e) {
// stop click on href.
if ($type(e) !== false)
new Event(e).stop();
this.animating = false;
this.openImage(el);
this.titleText = el.get("title") || "";
}.bind(this)
});
},
openImage: function(el) {
// generic wrapper that kick-starts the opening of an image
if (this.modal)
return false;
if (this.options.modal.enabled)
this.toggleModal();
var url = el.get("href"), basename = url.replace(/^.*[\/\\]/g, '');
// using caching system or import fresh
if ($type(this.cache[basename]) === "element") {
this.cache[basename].image.setStyles(this.cache[basename].size);
this.animateBox(this.cache[basename], el);
}
else {
this.loadImage(url, el); // this will load and then run .animateBox();
}
},
loadImage: function(url, el) {
new Asset.image(url, {
onload: function(im) {
var coords = el.getFirst().getCoordinates(), basename = url.replace(/^.*[\/\\]/g, '');
this.cache[basename] = {
size: {
width: im.width,
height: im.height
},
image: im.set({
styles: $merge(this.options.imageStyles, coords),
events: {
click: function() {
// this.closeBox(image, coords);
}.bind(this)
}
})
};
this.animateBox(this.cache[basename], el);
}.bind(this)
});
},
animateBox: function(imageObj, link) {
// gorw the box large!
if (this.animating)
return;
// always works from a cached object, need to preserve .size of original
// because .width of a static image is set to 0 in IE.
this.larger = imageObj.image.clone().inject(this.container);
this.larger.removeEvents().cloneEvents(imageObj.image);
// find appropriate screen position
var centerCoords = this.getCenter(imageObj.size.width, imageObj.size.height);
// save the source coordinates for the close animation
this.larger.store("coords", link.getFirst().getCoordinates());
// create an FX instance and store it into image
this.larger.store("imageEffects", new Fx.Morph(this.larger, {
transition: Fx.Transitions.Sine.easeOut,
duration: 300
}));
// next/previous, record index of image in array
this.currentImage = this.elements.indexOf(link);
// start animation variable
this.animating = true;
// run the morph
this.larger.retrieve("imageEffects").start({
width: centerCoords.width,
height: centerCoords.height,
left: centerCoords.x,
top: centerCoords.y,
borderWidth: this.options.imageBorder
}).chain(function() {
this.larger.addClass(this.options.imageClass);
this.animating = false;
this.addControls(centerCoords);
this.onComplete();
}.bind(this));
},
onComplete: function() {
this.fireEvent("complete");
if ($type(this.options.shadows[Browser.Engine.name]) === "object" && this.options.shadows.enabled === true)
this.larger.setStyles(this.options.shadows[Browser.Engine.name]);
},
addControls: function(coords) {
// draws the close button, title, next and previous.
if (!this.animating)
this.controls = new Element("div", {
id: "boxClose",
"class": "cur",
styles: {
top: coords.y - 12,
left: coords.x + coords.width - 12,
zIndex: this.options.imageStyles.zIndex+2
},
title: "click to close",
events: {
click: function() {
this.closeAuto();
}.bind(this)
}
}).inject(this.container);
// title and left/ right
if (this.options.controls.enabled) {
if (this.titleText.length || this.elements.length) {
this.titleOverlay = new Element("div", {
styles: {
width: coords.width - 4,
height: 30,
padding: 2,
background: "#000",
position: "absolute",
top: coords.y + coords.height - 31,
left: coords.x + 3,
color: "white",
opacity: 0,
zIndex: this.options.imageStyles.zIndex+1
},
html: ""+this.titleText+"
",
events: {
mouseleave: function() {
this.titleOverlay.fade(.000000009);
}.bind(this),
mouseenter: function() {
this.titleOverlay.fade(this.options.controls.opacity);
}.bind(this)
}
}).inject(this.container).fade(0, this.options.controls.opacity);
if (this.elements.length) {
this.goLeft = new Element("div", {
id: "arrowLeft",
"class": "cur",
events: {
click: function() {
this.getPrevious();
}.bind(this)
}
}).inject(this.titleOverlay, "top");
// if (Browser.Engine.trident)
// alert(this.goLeft.getStyle("background-image"));
this.goRight = new Element("div", {
id: "arrowRight",
"class": "cur",
events: {
click: function() {
this.getNext();
}.bind(this)
}
}).inject(this.titleOverlay);
}
}
}
},
closeBox: function() {
// shrink image back to coords stored previously
if (this.animating || !this.larger)
return false;
this.animating = true;
this.modal.removeEvents();
this.larger.retrieve("imageEffects").setOptions({
duration: 130
}).start($merge({
borderWidth: 0,
opacity: .4
}, this.larger.retrieve("coords"))).chain(function() {
this.animating = false;
}.bind(this));
// flash effect
this.larger.fade(0);
(function() {
if (this.options.modal.enabled)
this.toggleModal();
if (this.larger) {
this.larger.destroy();
delete this.larger;
}
this.fireEvent("close");
}).delay(500, this);
},
closeAuto: function() {
// auto clean up controls and opened images
if (this.animating)
return false;
if (this.controls)
this.controls.destroy();
if (this.options.controls.enabled && this.titleOverlay)
this.titleOverlay.destroy();
if (this.larger)
this.closeBox(this.larger);
},
getNext: function() {
// find next image if any
var next = this.currentImage == this.elements.length - 1 ? 0 : this.currentImage + 1;
var closeFunc = function() {
this.removeEvent("close", closeFunc);
(function() {
this.elements[next].fireEvent("click");
}).delay(200, this);
}.bind(this);
if (this.larger) {
this.addEvents({
close: closeFunc
});
this.closeAuto();
}
},
getPrevious: function() {
// find previous image
var previous = this.currentImage == 0 ? this.elements.length - 1 : this.currentImage - 1;
var closeFunc = function() {
this.removeEvent("close", closeFunc);
(function() {
this.elements[previous].fireEvent("click");
}).delay(200, this);
}.bind(this);
if (this.larger) {
this.addEvents({
close: closeFunc
});
this.closeAuto();
}
},
getCenter: function(width, height) {
// returns a coordinates JSON for positioning of a box in the centre of the browser
var winSize = window.getSize(), winScroll = window.getScroll(), windowHeight = window.getScrollHeight()-1, coords = {
y: Math.round(winScroll.y + (winSize.y / 2) - (height / 2)),
x: Math.round(winSize.x / 2 - width / 2),
width: width,
height: height
};
if (coords.y + height + 20 > windowHeight)
coords.y = windowHeight - 20 - height;
if (coords.y <= 0)
coords.y = 20;
return coords;
},
toggleModal: function() {
// modal view for the whole screen
if (this.modal) {
this.container.removeClass("overflowHidden");
if (Browser.Engine.trident)
$(document.html).removeClass("overflowHidden");
this.modal.destroy();
delete this.modal;
return false;
}
this.container.addClass("overflowHidden");
if (Browser.Engine.trident)
$(document.html).addClass("overflowHidden");
this.modal = new Element("div", {
styles: {
position: "absolute",
top: 0,
left: 0,
width: "100%",
height: "100%",
background: this.options.modal.background,
zIndex: this.options.modal.zIndex
},
opacity: this.options.modal.opacity,
events: this.options.modal.events
}).inject(this.container);
return this.modal; // can chain into it.
},
embeddedStyles: [
[ // first set is w/o base64 support, css with real files.
".overflowHidden { overflow: hidden; }",
"#arrowLeft {float:left;width:34px;height:100%;background:url(/images/arrow-left.gif) no-repeat center center;}",
"#arrowRight {float:right;width:34px;height:100%;background:url(/images/arrow-right.gif) no-repeat center center;}",
"#boxClose {position:absolute;width:32px;height:32px;background:url(/images/button-close.png) no-repeat center center}"
],
[ // css for base64 support
".overflowHidden { overflow: hidden; }",
"#arrowLeft {float:left;width:34px;height:100%;background:url(data:image/gif;base64,R0lGODlhIwAhALMAAAAAADQ0NENDQ25ubouLi6ioqLa2ttPT0/Dw8P///wAAAAAAAAAAAAAAAAAAAAAAACwAAAAAIwAhAAAIpQABCBxIsCCAAAYTKlw4cECCAQwjMnSY4KHEiwQpVrSIUaLGjRw7Kvy4EYEAkSNBljyJ0iDJiiZbulQJk6XMhjQTxLyJk+ZOngBe6rTJU+jPojmTKqXZc6nTpAKFPp0qsMDUqyoHWsWKleBWrk8LfgV5AKjYnGXNakWrdi3NtG3HbjTQtmrOAnUByK2It+7eBH3j5iSQVy5cv3PzegWsuCDExmYDAgA7) no-repeat center center;}",
"#arrowRight {float:right;width:34px;height:100%;background:url(data:image/gif;base64,R0lGODlhIwAhALMAAAAAADQ0NENDQ25ubouLi6ioqLa2ttPT0/Dw8P///wAAAAAAAAAAAAAAAAAAAAAAACwAAAAAIwAhAAAIpwABCBxIsODAAAYTKlw4cECCAQwjMnSY4KHEiwQpVrSIUaLGjRw7LhSAAORGiCJHljQZMqVBkixbuiQIkyXKmQVrmryJc6BOkDx7Avh5UijNlTsLxlzK1CbBplCb3oxKNSbKqlg3FhCYFetWrl2jfjV6IOZYoWVZnu2Z1uRanG1Bvp1pwKxRgQXs3s2r9i4Avm79EtDrN26CuULrVkRsNC/ju0H99gwIADs%3D) no-repeat center center;}",
"#boxClose {position:absolute;width:32px;height:32px;background:url(data:image/png;base64,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) no-repeat center center}"
]
]
}); // end largerBox
var C = {
// console wrapper
debug: true, // global debug on|off
quietDismiss: true, // may want to just drop, or alert instead
log: function() {
if (!C.debug) return false;
if (typeof console == 'object' && typeof console.log != "undefined")
try {
console.log.apply(this, arguments); // safari's console.log can't accept scope...
} catch(e) {
// so we loop instead.
for (var i = 0, l = arguments.length; i < l; i++)
console.log(arguments[i]);
}
else
if (!C.quietDismiss) {
var result = "";
for (var i = 0, l = arguments.length; i < l; i++)
result += arguments[i] + " ("+typeof arguments[i]+") ";
alert(result);
}
}
}; // end console wrapper.