[80] | 1 | /* |
---|
| 2 | This file is part of JonDesign's SmoothGallery v1.0.1. |
---|
| 3 | |
---|
| 4 | JonDesign's SmoothGallery is free software; you can redistribute it and/or modify |
---|
| 5 | it under the terms of the GNU General Public License as published by |
---|
| 6 | the Free Software Foundation; either version 2 of the License, or |
---|
| 7 | (at your option) any later version. |
---|
| 8 | |
---|
| 9 | JonDesign's SmoothGallery is distributed in the hope that it will be useful, |
---|
| 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
| 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
| 12 | GNU General Public License for more details. |
---|
| 13 | |
---|
| 14 | You should have received a copy of the GNU General Public License |
---|
| 15 | along with JonDesign's SmoothGallery; if not, write to the Free Software |
---|
| 16 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
---|
| 17 | |
---|
| 18 | Main Developer: Jonathan Schemoul (JonDesign: http://www.jondesign.net/) |
---|
| 19 | Contributed code by: |
---|
| 20 | - Christian Ehret (bugfix) |
---|
| 21 | - Nitrix (bugfix) |
---|
| 22 | - Valerio from Mad4Milk for his great help with the carousel scrolling and many other things. |
---|
| 23 | - Archie Cowan for helping me find a bugfix on carousel inner width problem. |
---|
| 24 | Many thanks to: |
---|
| 25 | - The mootools team for the great mootools lib, and it's help and support throughout the project. |
---|
| 26 | */ |
---|
| 27 | |
---|
| 28 | |
---|
| 29 | var $removeEvents = function (object, type) |
---|
| 30 | { |
---|
| 31 | if (!object.events) return object; |
---|
| 32 | if (type){ |
---|
| 33 | if (!object.events[type]) return object; |
---|
| 34 | for (var fn in object.events[type]) object.removeEvent(type, fn); |
---|
| 35 | object.events[type] = null; |
---|
| 36 | } else { |
---|
| 37 | for (var evType in object.events) object.removeEvents(evType); |
---|
| 38 | object.events = null; |
---|
| 39 | } |
---|
| 40 | return object; |
---|
| 41 | }; |
---|
| 42 | |
---|
| 43 | |
---|
| 44 | // declaring the class |
---|
| 45 | var gallery = new Class({ |
---|
| 46 | initialize: function(element, options) { |
---|
| 47 | this.setOptions({ |
---|
| 48 | showArrows: true, |
---|
| 49 | showCarousel: true, |
---|
| 50 | showInfopane: true, |
---|
| 51 | thumbHeight: 75, |
---|
| 52 | thumbWidth: 100, |
---|
| 53 | thumbSpacing: 10, |
---|
| 54 | embedLinks: true, |
---|
| 55 | fadeDuration: 500, |
---|
| 56 | timed: false, |
---|
| 57 | delay: 9000, |
---|
| 58 | preloader: true, |
---|
| 59 | manualData: [], |
---|
| 60 | populateData: true, |
---|
| 61 | elementSelector: "div.imageElement", |
---|
| 62 | titleSelector: "h3", |
---|
| 63 | subtitleSelector: "p", |
---|
| 64 | linkSelector: "a.open", |
---|
| 65 | imageSelector: "img.full", |
---|
| 66 | thumbnailSelector: "img.thumbnail", |
---|
| 67 | slideInfoZoneOpacity: 0.7, |
---|
| 68 | carouselMinimizedOpacity: 0.4, |
---|
| 69 | carouselMinimizedHeight: 20, |
---|
| 70 | carouselMaximizedOpacity: 0.7, |
---|
| 71 | destroyAfterPopulate: true, |
---|
| 72 | baseClass: 'jdGallery', |
---|
| 73 | withArrowsClass: 'withArrows', |
---|
| 74 | textShowCarousel: 'Pictures', |
---|
| 75 | useThumbGenerator: false, |
---|
| 76 | thumbGenerator: 'resizer.php' |
---|
| 77 | }, options); |
---|
| 78 | this.fireEvent('onInit'); |
---|
| 79 | this.currentIter = 0; |
---|
| 80 | this.lastIter = 0; |
---|
| 81 | this.maxIter = 0; |
---|
| 82 | this.galleryElement = element; |
---|
| 83 | this.galleryData = this.options.manualData; |
---|
| 84 | this.galleryInit = 1; |
---|
| 85 | this.galleryElements = Array(); |
---|
| 86 | this.thumbnailElements = Array(); |
---|
| 87 | this.galleryElement.addClass(this.options.baseClass); |
---|
| 88 | if (this.options.populateData) |
---|
| 89 | this.populateData(); |
---|
| 90 | element.style.display="block"; |
---|
| 91 | |
---|
| 92 | if (this.options.embedLinks) |
---|
| 93 | { |
---|
| 94 | this.currentLink = new Element('a').addClass('open').setProperties({ |
---|
| 95 | href: '#', |
---|
| 96 | title: '' |
---|
| 97 | }).injectInside(element); |
---|
| 98 | if ((!this.options.showArrows) && (!this.options.showCarousel)) |
---|
| 99 | this.galleryElement = element = this.currentLink; |
---|
| 100 | else |
---|
| 101 | this.currentLink.setStyle('display', 'none'); |
---|
| 102 | } |
---|
| 103 | |
---|
| 104 | this.constructElements(); |
---|
| 105 | if ((data.length>1)&&(this.options.showArrows)) |
---|
| 106 | { |
---|
| 107 | var leftArrow = new Element('a').addClass('left').addEvent( |
---|
| 108 | 'click', |
---|
| 109 | this.prevItem.bind(this) |
---|
| 110 | ).injectInside(element); |
---|
| 111 | var rightArrow = new Element('a').addClass('right').addEvent( |
---|
| 112 | 'click', |
---|
| 113 | this.nextItem.bind(this) |
---|
| 114 | ).injectInside(element); |
---|
| 115 | this.galleryElement.addClass(this.options.withArrowsClass); |
---|
| 116 | } |
---|
| 117 | this.loadingElement = new Element('div').addClass('loadingElement').injectInside(element); |
---|
| 118 | if (this.options.showInfopane) this.initInfoSlideshow(); |
---|
| 119 | if (this.options.showCarousel) this.initCarousel(); |
---|
| 120 | this.doSlideShow(1); |
---|
| 121 | }, |
---|
| 122 | populateData: function() { |
---|
| 123 | currentArrayPlace = this.galleryData.length; |
---|
| 124 | options = this.options; |
---|
| 125 | data = this.galleryData; |
---|
| 126 | this.galleryElement.getElements(options.elementSelector).each(function(el) { |
---|
| 127 | elementDict = { |
---|
| 128 | image: el.getElement(options.imageSelector).getProperty('src'), |
---|
| 129 | number: currentArrayPlace |
---|
| 130 | }; |
---|
| 131 | if ((options.showInfopane) | (options.showCarousel)) |
---|
| 132 | Object.extend(elementDict, { |
---|
| 133 | title: el.getElement(options.titleSelector).innerHTML, |
---|
| 134 | description: el.getElement(options.subtitleSelector).innerHTML |
---|
| 135 | }); |
---|
| 136 | if (options.embedLinks) |
---|
| 137 | Object.extend(elementDict, { |
---|
| 138 | link: el.getElement(options.linkSelector).href||false, |
---|
| 139 | linkTitle: el.getElement(options.linkSelector).title||false |
---|
| 140 | }); |
---|
| 141 | if ((!options.useThumbGenerator) && (options.showCarousel)) |
---|
| 142 | Object.extend(elementDict, { |
---|
| 143 | thumbnail: el.getElement(options.thumbnailSelector).src |
---|
| 144 | }); |
---|
| 145 | else if (options.useThumbGenerator) |
---|
| 146 | Object.extend(elementDict, { |
---|
| 147 | thumbnail: 'resizer.php?imgfile=' + elementDict.image + '&max_width=' + options.thumbWidth + '&max_height=' + options.thumbHeight |
---|
| 148 | }); |
---|
| 149 | |
---|
| 150 | data[currentArrayPlace] = elementDict; |
---|
| 151 | currentArrayPlace++; |
---|
| 152 | if (this.options.destroyAfterPopulate) |
---|
| 153 | el.remove(); |
---|
| 154 | }); |
---|
| 155 | this.galleryData = data; |
---|
| 156 | this.fireEvent('onPopulated'); |
---|
| 157 | }, |
---|
| 158 | constructElements: function() { |
---|
| 159 | el = this.galleryElement; |
---|
| 160 | this.maxIter = this.galleryData.length; |
---|
| 161 | var currentImg; |
---|
| 162 | for(i=0;i<this.galleryData.length;i++) |
---|
| 163 | { |
---|
| 164 | var currentImg = new Fx.Style( |
---|
| 165 | new Element('div').addClass('slideElement').setStyles({ |
---|
| 166 | 'position':'absolute', |
---|
| 167 | 'left':'0px', |
---|
| 168 | 'right':'0px', |
---|
| 169 | 'margin':'0px', |
---|
| 170 | 'padding':'0px', |
---|
| 171 | 'backgroundImage':"url('" + this.galleryData[i].image + "')", |
---|
| 172 | 'backgroundPosition':"center center", |
---|
| 173 | 'opacity':'0' |
---|
| 174 | }).injectInside(el), |
---|
| 175 | 'opacity', |
---|
| 176 | {duration: this.options.fadeDuration} |
---|
| 177 | ); |
---|
| 178 | this.galleryElements[parseInt(i)] = currentImg; |
---|
| 179 | } |
---|
| 180 | }, |
---|
| 181 | destroySlideShow: function(element) { |
---|
| 182 | var myClassName = element.className; |
---|
| 183 | var newElement = new Element('div').addClass('myClassName'); |
---|
| 184 | element.parentNode.replaceChild(newElement, element); |
---|
| 185 | }, |
---|
| 186 | startSlideShow: function() { |
---|
| 187 | this.fireEvent('onStart'); |
---|
| 188 | this.loadingElement.style.display = "none"; |
---|
| 189 | this.lastIter = this.maxIter - 1; |
---|
| 190 | this.currentIter = 0; |
---|
| 191 | this.galleryInit = 0; |
---|
| 192 | this.galleryElements[parseInt(this.currentIter)].set(1); |
---|
| 193 | if (this.options.showInfopane) |
---|
| 194 | this.showInfoSlideShow.delay(1000, this); |
---|
| 195 | this.prepareTimer(); |
---|
| 196 | if (this.options.embedLinks) |
---|
| 197 | this.makeLink(this.currentIter); |
---|
| 198 | }, |
---|
| 199 | nextItem: function() { |
---|
| 200 | this.fireEvent('onNextCalled'); |
---|
| 201 | this.nextIter = this.currentIter+1; |
---|
| 202 | if (this.nextIter >= this.maxIter) |
---|
| 203 | this.nextIter = 0; |
---|
| 204 | this.galleryInit = 0; |
---|
| 205 | this.goTo(this.nextIter); |
---|
| 206 | }, |
---|
| 207 | prevItem: function() { |
---|
| 208 | this.fireEvent('onPreviousCalled'); |
---|
| 209 | this.nextIter = this.currentIter-1; |
---|
| 210 | if (this.nextIter <= -1) |
---|
| 211 | this.nextIter = this.maxIter - 1; |
---|
| 212 | this.galleryInit = 0; |
---|
| 213 | this.goTo(this.nextIter); |
---|
| 214 | }, |
---|
| 215 | goTo: function(num) { |
---|
| 216 | this.clearTimer(); |
---|
| 217 | if (this.options.embedLinks) |
---|
| 218 | this.clearLink(); |
---|
| 219 | if (this.options.showInfopane) |
---|
| 220 | { |
---|
| 221 | this.slideInfoZone.clearChain(); |
---|
| 222 | this.hideInfoSlideShow().chain(this.changeItem.pass(num, this)); |
---|
| 223 | } else |
---|
| 224 | this.changeItem.delay(500, this, num); |
---|
| 225 | if (this.options.embedLinks) |
---|
| 226 | this.makeLink(num); |
---|
| 227 | this.prepareTimer(); |
---|
| 228 | /*if (this.options.showCarousel) |
---|
| 229 | this.clearThumbnailsHighlights();*/ |
---|
| 230 | }, |
---|
| 231 | changeItem: function(num) { |
---|
| 232 | this.fireEvent('onStartChanging'); |
---|
| 233 | this.galleryInit = 0; |
---|
| 234 | if (this.currentIter != num) |
---|
| 235 | { |
---|
| 236 | for(i=0;i<this.maxIter;i++) |
---|
| 237 | { |
---|
| 238 | if ((i != this.currentIter)) this.galleryElements[i].set(0); |
---|
| 239 | } |
---|
| 240 | if (num > this.currentIter) this.galleryElements[num].custom(1); |
---|
| 241 | else |
---|
| 242 | { |
---|
| 243 | this.galleryElements[num].set(1); |
---|
| 244 | this.galleryElements[this.currentIter].custom(0); |
---|
| 245 | } |
---|
| 246 | this.currentIter = num; |
---|
| 247 | } |
---|
| 248 | this.doSlideShow.bind(this)(); |
---|
| 249 | this.fireEvent('onChanged'); |
---|
| 250 | }, |
---|
| 251 | clearTimer: function() { |
---|
| 252 | if (this.options.timed) |
---|
| 253 | $clear(this.timer); |
---|
| 254 | }, |
---|
| 255 | prepareTimer: function() { |
---|
| 256 | if (this.options.timed) |
---|
| 257 | this.timer = this.nextItem.delay(this.options.delay, this); |
---|
| 258 | }, |
---|
| 259 | doSlideShow: function(position) { |
---|
| 260 | if (this.galleryInit == 1) |
---|
| 261 | { |
---|
| 262 | imgPreloader = new Image(); |
---|
| 263 | imgPreloader.onload=function(){ |
---|
| 264 | this.startSlideShow.delay(10, this); |
---|
| 265 | }.bind(this); |
---|
| 266 | imgPreloader.src = this.galleryData[0].image; |
---|
| 267 | } else { |
---|
| 268 | if (this.options.showInfopane) |
---|
| 269 | { |
---|
| 270 | if (this.options.showInfopane) |
---|
| 271 | { |
---|
| 272 | this.showInfoSlideShow.delay((500 + this.options.fadeDuration), this); |
---|
| 273 | } else |
---|
| 274 | if (this.options.showCarousel) |
---|
| 275 | this.centerCarouselOn(position); |
---|
| 276 | } |
---|
| 277 | } |
---|
| 278 | }, |
---|
| 279 | initCarousel: function () { |
---|
| 280 | var carouselContainerElement = new Element('div').addClass('carouselContainer').injectInside(this.galleryElement); |
---|
| 281 | this.carouselContainer = new Fx.Styles(carouselContainerElement, {transition: Fx.Transitions.expoOut}); |
---|
| 282 | this.carouselContainer.normalHeight = carouselContainerElement.offsetHeight; |
---|
| 283 | this.carouselContainer.set({'opacity': this.options.carouselMinimizedOpacity, 'top': (this.options.carouselMinimizedHeight - this.carouselContainer.normalHeight)}); |
---|
| 284 | |
---|
| 285 | this.carouselBtn = new Element('a').addClass('carouselBtn').setProperties({ |
---|
| 286 | title: this.options.textShowCarousel |
---|
| 287 | }).setHTML(this.options.textShowCarousel).injectInside(carouselContainerElement); |
---|
| 288 | |
---|
| 289 | this.carouselBtn.addEvent( |
---|
| 290 | 'click', |
---|
| 291 | function () { |
---|
| 292 | this.carouselContainer.clearTimer(); |
---|
| 293 | this.toggleCarousel(); |
---|
| 294 | }.bind(this) |
---|
| 295 | ); |
---|
| 296 | this.carouselActive = false; |
---|
| 297 | |
---|
| 298 | var carouselElement = new Element('div').addClass('carousel').injectInside(carouselContainerElement); |
---|
| 299 | this.carousel = new Fx.Styles(carouselElement); |
---|
| 300 | |
---|
| 301 | this.carouselLabel = new Element('p').addClass('label').injectInside(this.carousel.element); |
---|
| 302 | this.carouselWrapper = new Element('div').addClass('carouselWrapper').injectInside(this.carousel.element); |
---|
| 303 | this.carouselInner = new Element('div').addClass('carouselInner').injectInside(this.carouselWrapper); |
---|
| 304 | |
---|
| 305 | this.carouselWrapper.scroller = new Scroller(this.carouselWrapper, { |
---|
| 306 | area: 100, |
---|
| 307 | velocity: 0.2 |
---|
| 308 | }) |
---|
| 309 | |
---|
| 310 | this.carouselWrapper.elementScroller = new Fx.Scroll(this.carouselWrapper, { |
---|
| 311 | duration: 400, |
---|
| 312 | onStart: this.carouselWrapper.scroller.stop.bind(this.carouselWrapper.scroller), |
---|
| 313 | onComplete: this.carouselWrapper.scroller.start.bind(this.carouselWrapper.scroller) |
---|
| 314 | }); |
---|
| 315 | |
---|
| 316 | this.constructThumbnails(); |
---|
| 317 | |
---|
| 318 | this.carouselInner.style.width = ((this.maxIter * (this.options.thumbWidth + this.options.thumbSpacing)) - this.options.thumbSpacing + this.options.thumbWidth) + "px"; |
---|
| 319 | }, |
---|
| 320 | toggleCarousel: function() { |
---|
| 321 | if (this.carouselActive) |
---|
| 322 | this.hideCarousel(); |
---|
| 323 | else |
---|
| 324 | this.showCarousel(); |
---|
| 325 | }, |
---|
| 326 | showCarousel: function () { |
---|
| 327 | this.fireEvent('onShowCarousel'); |
---|
| 328 | this.carouselContainer.custom({ |
---|
| 329 | 'opacity': this.options.carouselMaximizedOpacity, |
---|
| 330 | 'top': 0 |
---|
| 331 | }).addEvent('onComplete', function() { this.carouselActive = true; this.carouselWrapper.scroller.start(); }.bind(this)); |
---|
| 332 | }, |
---|
| 333 | hideCarousel: function () { |
---|
| 334 | this.fireEvent('onHideCarousel'); |
---|
| 335 | this.carouselContainer.custom({ |
---|
| 336 | 'opacity': this.options.carouselMinimizedOpacity, |
---|
| 337 | 'top': (this.options.carouselMinimizedHeight - this.carouselContainer.normalHeight) |
---|
| 338 | }).addEvent('onComplete', function() { this.carouselActive = false; this.carouselWrapper.scroller.stop(); }.bind(this)); |
---|
| 339 | }, |
---|
| 340 | constructThumbnails: function () { |
---|
| 341 | element = this.carouselInner; |
---|
| 342 | for(i=0;i<this.galleryData.length;i++) |
---|
| 343 | { |
---|
| 344 | var currentImg = new Fx.Style(new Element ('div').addClass("thumbnail").setStyles({ |
---|
| 345 | backgroundImage: "url('" + this.galleryData[i].thumbnail + "')", |
---|
| 346 | backgroundPosition: "center center", |
---|
| 347 | backgroundRepeat: 'no-repeat', |
---|
| 348 | marginLeft: this.options.thumbSpacing + "px", |
---|
| 349 | width: this.options.thumbWidth + "px", |
---|
| 350 | height: this.options.thumbHeight + "px" |
---|
| 351 | }).injectInside(element), "opacity", {duration: 200}).set(0.2); |
---|
| 352 | currentImg.element.addEvents({ |
---|
| 353 | 'mouseover': function (myself) { |
---|
| 354 | myself.clearTimer(); |
---|
| 355 | myself.custom(0.99); |
---|
| 356 | $(this.carouselLabel).setHTML('<span class="number">' + (myself.relatedImage.number + 1) + "/" + this.maxIter + ":</span> " + myself.relatedImage.title); |
---|
| 357 | }.pass(currentImg, this), |
---|
| 358 | 'mouseout': function (myself) { |
---|
| 359 | myself.clearTimer(); |
---|
| 360 | myself.custom(0.2); |
---|
| 361 | }.pass(currentImg, this), |
---|
| 362 | 'click': function (myself) { |
---|
| 363 | this.goTo(myself.relatedImage.number); |
---|
| 364 | }.pass(currentImg, this) |
---|
| 365 | }); |
---|
| 366 | |
---|
| 367 | currentImg.relatedImage = this.galleryData[i]; |
---|
| 368 | this.thumbnailElements[parseInt(i)] = currentImg; |
---|
| 369 | } |
---|
| 370 | }, |
---|
| 371 | clearThumbnailsHighlights: function() |
---|
| 372 | { |
---|
| 373 | for(i=0;i<this.galleryData.length;i++) |
---|
| 374 | { |
---|
| 375 | this.thumbnailElements[i].clearTimer(); |
---|
| 376 | this.thumbnailElements[i].custom(0.2); |
---|
| 377 | } |
---|
| 378 | }, |
---|
| 379 | centerCarouselOn: function(num) { |
---|
| 380 | var carouselElement = this.thumbnailElements[num]; |
---|
| 381 | var position = carouselElement.element.offsetLeft + (carouselElement.element.offsetWidth / 2); |
---|
| 382 | var carouselWidth = this.carouselWrapper.offsetWidth; |
---|
| 383 | var carouselInnerWidth = this.carouselInner.offsetWidth; |
---|
| 384 | var diffWidth = carouselWidth / 2; |
---|
| 385 | var scrollPos = position-diffWidth; |
---|
| 386 | this.carouselWrapper.elementScroller.scrollTo(scrollPos,0); |
---|
| 387 | }, |
---|
| 388 | initInfoSlideshow: function() { |
---|
| 389 | /*if (this.slideInfoZone.element) |
---|
| 390 | this.slideInfoZone.element.remove();*/ |
---|
| 391 | this.slideInfoZone = new Fx.Styles(new Element('div').addClass('slideInfoZone').injectInside($(this.galleryElement))).set({'opacity':0}); |
---|
| 392 | var slideInfoZoneTitle = new Element('h2').injectInside(this.slideInfoZone.element); |
---|
| 393 | var slideInfoZoneDescription = new Element('p').injectInside(this.slideInfoZone.element); |
---|
| 394 | this.slideInfoZone.normalHeight = this.slideInfoZone.element.offsetHeight; |
---|
| 395 | this.slideInfoZone.element.setStyle('opacity',0); |
---|
| 396 | }, |
---|
| 397 | changeInfoSlideShow: function() |
---|
| 398 | { |
---|
| 399 | this.hideInfoSlideShow.delay(10, this); |
---|
| 400 | this.showInfoSlideShow.delay(500, this); |
---|
| 401 | }, |
---|
| 402 | showInfoSlideShow: function() { |
---|
| 403 | this.fireEvent('onShowInfopane'); |
---|
| 404 | this.slideInfoZone.clearTimer(); |
---|
| 405 | element = this.slideInfoZone.element; |
---|
| 406 | element.getElement('h2').setHTML(this.galleryData[this.currentIter].title); |
---|
| 407 | element.getElement('p').setHTML(this.galleryData[this.currentIter].description); |
---|
| 408 | this.slideInfoZone.custom({'opacity': [0, this.options.slideInfoZoneOpacity], 'height': [0, this.slideInfoZone.normalHeight]}); |
---|
| 409 | if (this.options.showCarousel) |
---|
| 410 | this.slideInfoZone.chain(this.centerCarouselOn.pass(this.currentIter, this)); |
---|
| 411 | return this.slideInfoZone; |
---|
| 412 | }, |
---|
| 413 | hideInfoSlideShow: function() { |
---|
| 414 | this.fireEvent('onHideInfopane'); |
---|
| 415 | this.slideInfoZone.clearTimer(); |
---|
| 416 | this.slideInfoZone.custom({'opacity': 0, 'height': 0}); |
---|
| 417 | return this.slideInfoZone; |
---|
| 418 | }, |
---|
| 419 | makeLink: function(num) { |
---|
| 420 | this.currentLink.setProperties({ |
---|
| 421 | href: this.galleryData[num].link, |
---|
| 422 | title: this.galleryData[num].linkTitle |
---|
| 423 | }) |
---|
| 424 | if (!((this.options.embedLinks) && (!this.options.showArrows) && (!this.options.showCarousel))) |
---|
| 425 | this.currentLink.setStyle('display', 'block'); |
---|
| 426 | }, |
---|
| 427 | clearLink: function() { |
---|
| 428 | this.currentLink.setProperties({href: '', title: ''}); |
---|
| 429 | if (!((this.options.embedLinks) && (!this.options.showArrows) && (!this.options.showCarousel))) |
---|
| 430 | this.currentLink.setStyle('display', 'none'); |
---|
| 431 | } |
---|
| 432 | }); |
---|
| 433 | gallery.implement(new Events); |
---|
| 434 | gallery.implement(new Options); |
---|
| 435 | |
---|
| 436 | /* All code copyright 2006 Jonathan Schemoul */ |
---|