lightbox.js
上传用户:netsea168
上传日期:2022-07-22
资源大小:4652k
文件大小:18k
源码类别:

Ajax

开发平台:

Others

  1. // -----------------------------------------------------------------------------------
  2. //
  3. // Lightbox v2.04
  4. // by Lokesh Dhakar - http://www.lokeshdhakar.com
  5. // Last Modification: 2/9/08
  6. //
  7. // For more information, visit:
  8. // http://lokeshdhakar.com/projects/lightbox2/
  9. //
  10. // Licensed under the Creative Commons Attribution 2.5 License - http://creativecommons.org/licenses/by/2.5/
  11. //   - Free for use in both personal and commercial projects
  12. // - Attribution requires leaving author name, author link, and the license info intact.
  13. //
  14. //  Thanks: Scott Upton(uptonic.com), Peter-Paul Koch(quirksmode.com), and Thomas Fuchs(mir.aculo.us) for ideas, libs, and snippets.
  15. //   Artemy Tregubenko (arty.name) for cleanup and help in updating to latest ver of proto-aculous.
  16. //
  17. // -----------------------------------------------------------------------------------
  18. /*
  19.     Table of Contents
  20.     -----------------
  21.     Configuration
  22.     Lightbox Class Declaration
  23.     - initialize()
  24.     - updateImageList()
  25.     - start()
  26.     - changeImage()
  27.     - resizeImageContainer()
  28.     - showImage()
  29.     - updateDetails()
  30.     - updateNav()
  31.     - enableKeyboardNav()
  32.     - disableKeyboardNav()
  33.     - keyboardAction()
  34.     - preloadNeighborImages()
  35.     - end()
  36.     
  37.     Function Calls
  38.     - document.observe()
  39.    
  40. */
  41. // -----------------------------------------------------------------------------------
  42. //
  43. //  Configurationl
  44. //
  45. LightboxOptions = Object.extend({
  46.     fileLoadingImage:        '/images/loading.gif',     
  47.     fileBottomNavCloseImage: '/images/closelabel.gif',
  48.     overlayOpacity: 0.8,   // controls transparency of shadow overlay
  49.     animate: true,         // toggles resizing animations
  50.     resizeSpeed: 7,        // controls the speed of the image resizing animations (1=slowest and 10=fastest)
  51.     borderSize: 10,         //if you adjust the padding in the CSS, you will need to update this variable
  52. // When grouping images this is used to write: Image # of #.
  53. // Change it for non-english localization
  54. labelImage: "Image",
  55. labelOf: "of"
  56. }, window.LightboxOptions || {});
  57. // -----------------------------------------------------------------------------------
  58. var Lightbox = Class.create();
  59. Lightbox.prototype = {
  60.     imageArray: [],
  61.     activeImage: undefined,
  62.     
  63.     // initialize()
  64.     // Constructor runs on completion of the DOM loading. Calls updateImageList and then
  65.     // the function inserts html at the bottom of the page which is used to display the shadow 
  66.     // overlay and the image container.
  67.     //
  68.     initialize: function() {    
  69.         
  70.         this.updateImageList();
  71.         
  72.         this.keyboardAction = this.keyboardAction.bindAsEventListener(this);
  73.         if (LightboxOptions.resizeSpeed > 10) LightboxOptions.resizeSpeed = 10;
  74.         if (LightboxOptions.resizeSpeed < 1)  LightboxOptions.resizeSpeed = 1;
  75.     this.resizeDuration = LightboxOptions.animate ? ((11 - LightboxOptions.resizeSpeed) * 0.15) : 0;
  76.     this.overlayDuration = LightboxOptions.animate ? 0.2 : 0;  // shadow fade in/out duration
  77.         // When Lightbox starts it will resize itself from 250 by 250 to the current image dimension.
  78.         // If animations are turned off, it will be hidden as to prevent a flicker of a
  79.         // white 250 by 250 box.
  80.         var size = (LightboxOptions.animate ? 250 : 1) + 'px';
  81.         
  82.         // Code inserts html at the bottom of the page that looks similar to this:
  83.         //
  84.         //  <div id="overlay"></div>
  85.         //  <div id="lightbox">
  86.         //      <div id="outerImageContainer">
  87.         //          <div id="imageContainer">
  88.         //              <img id="lightboxImage">
  89.         //              <div style="" id="hoverNav">
  90.         //                  <a href="#" id="prevLink"></a>
  91.         //                  <a href="#" id="nextLink"></a>
  92.         //              </div>
  93.         //              <div id="loading">
  94.         //                  <a href="#" id="loadingLink">
  95.         //                      <img src="images/loading.gif">
  96.         //                  </a>
  97.         //              </div>
  98.         //          </div>
  99.         //      </div>
  100.         //      <div id="imageDataContainer">
  101.         //          <div id="imageData">
  102.         //              <div id="imageDetails">
  103.         //                  <span id="caption"></span>
  104.         //                  <span id="numberDisplay"></span>
  105.         //              </div>
  106.         //              <div id="bottomNav">
  107.         //                  <a href="#" id="bottomNavClose">
  108.         //                      <img src="images/close.gif">
  109.         //                  </a>
  110.         //              </div>
  111.         //          </div>
  112.         //      </div>
  113.         //  </div>
  114.         var objBody = $$('body')[0];
  115. objBody.appendChild(Builder.node('div',{id:'overlay'}));
  116.         objBody.appendChild(Builder.node('div',{id:'lightbox'}, [
  117.             Builder.node('div',{id:'outerImageContainer'}, 
  118.                 Builder.node('div',{id:'imageContainer'}, [
  119.                     Builder.node('img',{id:'lightboxImage'}), 
  120.                     Builder.node('div',{id:'hoverNav'}, [
  121.                         Builder.node('a',{id:'prevLink', href: '#' }),
  122.                         Builder.node('a',{id:'nextLink', href: '#' })
  123.                     ]),
  124.                     Builder.node('div',{id:'loading'}, 
  125.                         Builder.node('a',{id:'loadingLink', href: '#' }, 
  126.                             Builder.node('img', {src: LightboxOptions.fileLoadingImage})
  127.                         )
  128.                     )
  129.                 ])
  130.             ),
  131.             Builder.node('div', {id:'imageDataContainer'},
  132.                 Builder.node('div',{id:'imageData'}, [
  133.                     Builder.node('div',{id:'imageDetails'}, [
  134.                         Builder.node('span',{id:'caption'}),
  135.                         Builder.node('span',{id:'numberDisplay'})
  136.                     ]),
  137.                     Builder.node('div',{id:'bottomNav'},
  138.                         Builder.node('a',{id:'bottomNavClose', href: '#' },
  139.                             Builder.node('img', { src: LightboxOptions.fileBottomNavCloseImage })
  140.                         )
  141.                     )
  142.                 ])
  143.             )
  144.         ]));
  145. $('overlay').hide().observe('click', (function() { this.end(); }).bind(this));
  146. $('lightbox').hide().observe('click', (function(event) { if (event.element().id == 'lightbox') this.end(); }).bind(this));
  147. $('outerImageContainer').setStyle({ width: size, height: size });
  148. $('prevLink').observe('click', (function(event) { event.stop(); this.changeImage(this.activeImage - 1); }).bindAsEventListener(this));
  149. $('nextLink').observe('click', (function(event) { event.stop(); this.changeImage(this.activeImage + 1); }).bindAsEventListener(this));
  150. $('loadingLink').observe('click', (function(event) { event.stop(); this.end(); }).bind(this));
  151. $('bottomNavClose').observe('click', (function(event) { event.stop(); this.end(); }).bind(this));
  152.         var th = this;
  153.         (function(){
  154.             var ids = 
  155.                 'overlay lightbox outerImageContainer imageContainer lightboxImage hoverNav prevLink nextLink loading loadingLink ' + 
  156.                 'imageDataContainer imageData imageDetails caption numberDisplay bottomNav bottomNavClose';   
  157.             $w(ids).each(function(id){ th[id] = $(id); });
  158.         }).defer();
  159.     },
  160.     //
  161.     // updateImageList()
  162.     // Loops through anchor tags looking for 'lightbox' references and applies onclick
  163.     // events to appropriate links. You can rerun after dynamically adding images w/ajax.
  164.     //
  165.     updateImageList: function() {   
  166.         this.updateImageList = Prototype.emptyFunction;
  167.         document.observe('click', (function(event){
  168.             var target = event.findElement('a[rel^=lightbox]') || event.findElement('area[rel^=lightbox]');
  169.             if (target) {
  170.                 event.stop();
  171.                 this.start(target);
  172.             }
  173.         }).bind(this));
  174.     },
  175.     
  176.     //
  177.     //  start()
  178.     //  Display overlay and lightbox. If image is part of a set, add siblings to imageArray.
  179.     //
  180.     start: function(imageLink) {    
  181.         $$('select', 'object', 'embed').each(function(node){ node.style.visibility = 'hidden' });
  182.         // stretch overlay to fill page and fade in
  183.         var arrayPageSize = this.getPageSize();
  184.         $('overlay').setStyle({ width: arrayPageSize[0] + 'px', height: arrayPageSize[1] + 'px' });
  185.         new Effect.Appear(this.overlay, { duration: this.overlayDuration, from: 0.0, to: LightboxOptions.overlayOpacity });
  186.         this.imageArray = [];
  187.         var imageNum = 0;       
  188.         if ((imageLink.rel == 'lightbox')){
  189.             // if image is NOT part of a set, add single image to imageArray
  190.             this.imageArray.push([imageLink.href, imageLink.title]);         
  191.         } else {
  192.             // if image is part of a set..
  193.             this.imageArray = 
  194.                 $$(imageLink.tagName + '[href][rel="' + imageLink.rel + '"]').
  195.                 collect(function(anchor){ return [anchor.href, anchor.title]; }).
  196.                 uniq();
  197.             
  198.             while (this.imageArray[imageNum][0] != imageLink.href) { imageNum++; }
  199.         }
  200.         // calculate top and left offset for the lightbox 
  201.         var arrayPageScroll = document.viewport.getScrollOffsets();
  202.         var lightboxTop = arrayPageScroll[1] + (document.viewport.getHeight() / 10);
  203.         var lightboxLeft = arrayPageScroll[0];
  204.         this.lightbox.setStyle({ top: lightboxTop + 'px', left: lightboxLeft + 'px' }).show();
  205.         
  206.         this.changeImage(imageNum);
  207.     },
  208.     //
  209.     //  changeImage()
  210.     //  Hide most elements and preload image in preparation for resizing image container.
  211.     //
  212.     changeImage: function(imageNum) {   
  213.         
  214.         this.activeImage = imageNum; // update global var
  215.         // hide elements during transition
  216.         if (LightboxOptions.animate) this.loading.show();
  217.         this.lightboxImage.hide();
  218.         this.hoverNav.hide();
  219.         this.prevLink.hide();
  220.         this.nextLink.hide();
  221. // HACK: Opera9 does not currently support scriptaculous opacity and appear fx
  222.         this.imageDataContainer.setStyle({opacity: .0001});
  223.         this.numberDisplay.hide();      
  224.         
  225.         var imgPreloader = new Image();
  226.         
  227.         // once image is preloaded, resize image container
  228.         imgPreloader.onload = (function(){
  229.             this.lightboxImage.src = this.imageArray[this.activeImage][0];
  230.             this.resizeImageContainer(imgPreloader.width, imgPreloader.height);
  231.         }).bind(this);
  232.         imgPreloader.src = this.imageArray[this.activeImage][0];
  233.     },
  234.     //
  235.     //  resizeImageContainer()
  236.     //
  237.     resizeImageContainer: function(imgWidth, imgHeight) {
  238.         // get current width and height
  239.         var widthCurrent  = this.outerImageContainer.getWidth();
  240.         var heightCurrent = this.outerImageContainer.getHeight();
  241.         // get new width and height
  242.         var widthNew  = (imgWidth  + LightboxOptions.borderSize * 2);
  243.         var heightNew = (imgHeight + LightboxOptions.borderSize * 2);
  244.         // scalars based on change from old to new
  245.         var xScale = (widthNew  / widthCurrent)  * 100;
  246.         var yScale = (heightNew / heightCurrent) * 100;
  247.         // calculate size difference between new and old image, and resize if necessary
  248.         var wDiff = widthCurrent - widthNew;
  249.         var hDiff = heightCurrent - heightNew;
  250.         if (hDiff != 0) new Effect.Scale(this.outerImageContainer, yScale, {scaleX: false, duration: this.resizeDuration, queue: 'front'}); 
  251.         if (wDiff != 0) new Effect.Scale(this.outerImageContainer, xScale, {scaleY: false, duration: this.resizeDuration, delay: this.resizeDuration}); 
  252.         // if new and old image are same size and no scaling transition is necessary, 
  253.         // do a quick pause to prevent image flicker.
  254.         var timeout = 0;
  255.         if ((hDiff == 0) && (wDiff == 0)){
  256.             timeout = 100;
  257.             if (Prototype.Browser.IE) timeout = 250;   
  258.         }
  259.         (function(){
  260.             this.prevLink.setStyle({ height: imgHeight + 'px' });
  261.             this.nextLink.setStyle({ height: imgHeight + 'px' });
  262.             this.imageDataContainer.setStyle({ width: widthNew + 'px' });
  263.             this.showImage();
  264.         }).bind(this).delay(timeout / 1000);
  265.     },
  266.     
  267.     //
  268.     //  showImage()
  269.     //  Display image and begin preloading neighbors.
  270.     //
  271.     showImage: function(){
  272.         this.loading.hide();
  273.         new Effect.Appear(this.lightboxImage, { 
  274.             duration: this.resizeDuration, 
  275.             queue: 'end', 
  276.             afterFinish: (function(){ this.updateDetails(); }).bind(this) 
  277.         });
  278.         this.preloadNeighborImages();
  279.     },
  280.     //
  281.     //  updateDetails()
  282.     //  Display caption, image number, and bottom nav.
  283.     //
  284.     updateDetails: function() {
  285.     
  286.         // if caption is not null
  287.         if (this.imageArray[this.activeImage][1] != ""){
  288.             this.caption.update(this.imageArray[this.activeImage][1]).show();
  289.         }
  290.         
  291.         // if image is part of set display 'Image x of x' 
  292.         if (this.imageArray.length > 1){
  293.             this.numberDisplay.update( LightboxOptions.labelImage + ' ' + (this.activeImage + 1) + ' ' + LightboxOptions.labelOf + '  ' + this.imageArray.length).show();
  294.         }
  295.         new Effect.Parallel(
  296.             [ 
  297.                 new Effect.SlideDown(this.imageDataContainer, { sync: true, duration: this.resizeDuration, from: 0.0, to: 1.0 }), 
  298.                 new Effect.Appear(this.imageDataContainer, { sync: true, duration: this.resizeDuration }) 
  299.             ], 
  300.             { 
  301.                 duration: this.resizeDuration, 
  302.                 afterFinish: (function() {
  303.                 // update overlay size and update nav
  304.                 var arrayPageSize = this.getPageSize();
  305.                 this.overlay.setStyle({ height: arrayPageSize[1] + 'px' });
  306.                 this.updateNav();
  307.                 }).bind(this)
  308.             } 
  309.         );
  310.     },
  311.     //
  312.     //  updateNav()
  313.     //  Display appropriate previous and next hover navigation.
  314.     //
  315.     updateNav: function() {
  316.         this.hoverNav.show();               
  317.         // if not first image in set, display prev image button
  318.         if (this.activeImage > 0) this.prevLink.show();
  319.         // if not last image in set, display next image button
  320.         if (this.activeImage < (this.imageArray.length - 1)) this.nextLink.show();
  321.         
  322.         this.enableKeyboardNav();
  323.     },
  324.     //
  325.     //  enableKeyboardNav()
  326.     //
  327.     enableKeyboardNav: function() {
  328.         document.observe('keydown', this.keyboardAction); 
  329.     },
  330.     //
  331.     //  disableKeyboardNav()
  332.     //
  333.     disableKeyboardNav: function() {
  334.         document.stopObserving('keydown', this.keyboardAction); 
  335.     },
  336.     //
  337.     //  keyboardAction()
  338.     //
  339.     keyboardAction: function(event) {
  340.         var keycode = event.keyCode;
  341.         var escapeKey;
  342.         if (event.DOM_VK_ESCAPE) {  // mozilla
  343.             escapeKey = event.DOM_VK_ESCAPE;
  344.         } else { // ie
  345.             escapeKey = 27;
  346.         }
  347.         var key = String.fromCharCode(keycode).toLowerCase();
  348.         
  349.         if (key.match(/x|o|c/) || (keycode == escapeKey)){ // close lightbox
  350.             this.end();
  351.         } else if ((key == 'p') || (keycode == 37)){ // display previous image
  352.             if (this.activeImage != 0){
  353.                 this.disableKeyboardNav();
  354.                 this.changeImage(this.activeImage - 1);
  355.             }
  356.         } else if ((key == 'n') || (keycode == 39)){ // display next image
  357.             if (this.activeImage != (this.imageArray.length - 1)){
  358.                 this.disableKeyboardNav();
  359.                 this.changeImage(this.activeImage + 1);
  360.             }
  361.         }
  362.     },
  363.     //
  364.     //  preloadNeighborImages()
  365.     //  Preload previous and next images.
  366.     //
  367.     preloadNeighborImages: function(){
  368.         var preloadNextImage, preloadPrevImage;
  369.         if (this.imageArray.length > this.activeImage + 1){
  370.             preloadNextImage = new Image();
  371.             preloadNextImage.src = this.imageArray[this.activeImage + 1][0];
  372.         }
  373.         if (this.activeImage > 0){
  374.             preloadPrevImage = new Image();
  375.             preloadPrevImage.src = this.imageArray[this.activeImage - 1][0];
  376.         }
  377.     
  378.     },
  379.     //
  380.     //  end()
  381.     //
  382.     end: function() {
  383.         this.disableKeyboardNav();
  384.         this.lightbox.hide();
  385.         new Effect.Fade(this.overlay, { duration: this.overlayDuration });
  386.         $$('select', 'object', 'embed').each(function(node){ node.style.visibility = 'visible' });
  387.     },
  388.     //
  389.     //  getPageSize()
  390.     //
  391.     getPageSize: function() {
  392.         
  393.      var xScroll, yScroll;
  394. if (window.innerHeight && window.scrollMaxY) {
  395. xScroll = window.innerWidth + window.scrollMaxX;
  396. yScroll = window.innerHeight + window.scrollMaxY;
  397. } else if (document.body.scrollHeight > document.body.offsetHeight){ // all but Explorer Mac
  398. xScroll = document.body.scrollWidth;
  399. yScroll = document.body.scrollHeight;
  400. } else { // Explorer Mac...would also work in Explorer 6 Strict, Mozilla and Safari
  401. xScroll = document.body.offsetWidth;
  402. yScroll = document.body.offsetHeight;
  403. }
  404. var windowWidth, windowHeight;
  405. if (self.innerHeight) { // all except Explorer
  406. if(document.documentElement.clientWidth){
  407. windowWidth = document.documentElement.clientWidth; 
  408. } else {
  409. windowWidth = self.innerWidth;
  410. }
  411. windowHeight = self.innerHeight;
  412. } else if (document.documentElement && document.documentElement.clientHeight) { // Explorer 6 Strict Mode
  413. windowWidth = document.documentElement.clientWidth;
  414. windowHeight = document.documentElement.clientHeight;
  415. } else if (document.body) { // other Explorers
  416. windowWidth = document.body.clientWidth;
  417. windowHeight = document.body.clientHeight;
  418. }
  419. // for small pages with total height less then height of the viewport
  420. if(yScroll < windowHeight){
  421. pageHeight = windowHeight;
  422. } else { 
  423. pageHeight = yScroll;
  424. }
  425. // for small pages with total width less then width of the viewport
  426. if(xScroll < windowWidth){
  427. pageWidth = xScroll;
  428. } else {
  429. pageWidth = windowWidth;
  430. }
  431. return [pageWidth,pageHeight];
  432. }
  433. }
  434. document.observe('dom:loaded', function () { new Lightbox(); });