1/* 2 3 GalleryView - jQuery Content Gallery Plugin 4 Author: Jack Anderson 5 Version: 3.0 DEVELOPMENT 6 7 See README.txt for instructions on how to markup your HTML 8*/ 9 10// Make sure Object.create is available in the browser (for our prototypal inheritance) 11// Courtesy of Douglas Crockford 12if (typeof Object.create !== 'function') { 13 Object.create = function (o) { 14 function F() {} 15 F.prototype = o; 16 return new F(); 17 }; 18} 19 20(function ($) { 21 // custom image object 22 var gvImage = function (img) { 23 24 this.src = { 25 panel: img.attr('src'), 26 frame: img.data('frame') || img.attr('src') 27 }; 28 this.scale = { 29 panel: null, 30 frame: null 31 }; 32 this.height = 0; 33 this.width = 0; 34 this.attrs = { 35 title: img.attr('title') || img.attr('alt'), 36 description: img.data('description') 37 }; 38 this.href = null; 39 this.dom_obj = null; 40 41 return this; 42 }, 43 44 // utility function wrapper 45 gv = { 46 getInt: function(i) { 47 i = parseInt(i, 10); 48 return isNaN(i) ? 0 : i; 49 }, 50 innerWidth: function(elem) { 51 return this.getInt(elem.css('width')) || 0; 52 }, 53 outerWidth: function(elem) { 54 return this.innerWidth(elem) + 55 this.extraWidth(elem); 56 }, 57 extraWidth: function(elem) { 58 return this.getInt(elem.css('paddingLeft')) + 59 this.getInt(elem.css('paddingRight')) + 60 this.getInt(elem.css('borderLeftWidth')) + 61 this.getInt(elem.css('borderRightWidth')); 62 }, 63 innerHeight: function(elem) { 64 return this.getInt(elem.css('height'))|| 0; 65 }, 66 outerHeight: function(elem) { 67 return this.innerHeight(elem) + 68 this.extraHeight(elem); 69 }, 70 extraHeight: function(elem) { 71 return this.getInt(elem.css('paddingTop')) + 72 this.getInt(elem.css('paddingBottom')) + 73 this.getInt(elem.css('borderTopWidth')) + 74 this.getInt(elem.css('borderBottomWidth')); 75 } 76 }, 77 78 /* 79 GalleryView - Object 80 The main gallery class 81 */ 82 GalleryView = { 83 // array of dom elements 84 elems: [ 85 '.gv_galleryWrap', '.gv_gallery', '.gv_panelWrap', '.gv_panel', 86 'img.gv_image', '.gv_infobar', '.gv_filmstripWrap', '.gv_filmstrip', 87 '.gv_frame', '.gv_thumbnail', '.gv_caption', 'img.gv_thumb', 88 '.gv_navWrap', '.gv_navNext', '.gv_navPrev', '.gv_navPlay', 89 '.gv_panelNavNext', '.gv_panelNavPrev', '.gv_overlay', '.gv_showOverlay', 90 '.gv_imageStore' 91 ], 92 93 // create a jQuery element and apply attributes 94 createElem: function(attrs,elem) { 95 elem = document.createElement(elem); 96 var $elem = $(elem); 97 return $elem.attr(attrs); 98 }, 99 100 // get the position of an element with respect 101 // to the gallery wrapper 102 getPos: function (el) { 103 var self = this, 104 dom = this.dom, 105 el = el[0], 106 el_id = el.id, 107 left = 0, 108 top = 0, 109 gPos, gLeft, gTop; 110 111 if (!el) { return { top: 0, left: 0 }; } 112 113 if (el.offsetParent) { 114 do { 115 left += el.offsetLeft; 116 top += el.offsetTop; 117 } while (el = el.offsetParent); 118 } 119 120 //If we want the position of the gallery itself, return it 121 if (el_id === self.id) { return { left: left, top: top }; } 122 123 //Otherwise, get position of element relative to gallery 124 else { 125 gPos = self.getPos(dom.galleryWrap); 126 gLeft = gPos.left; 127 gTop = gPos.top; 128 return { left: left - gLeft, top: top - gTop }; 129 } 130 }, 131 132 // determine if mouse is within the boundary of the gallery wrapper 133 mouseIsOverGallery: function (x, y) { 134 var self = this, 135 dom = this.dom, 136 pos = this.getPos(dom.gv_galleryWrap), 137 top = pos.top, 138 left = pos.left; 139 140 return x > left && x < left + gv.outerWidth(dom.gv_galleryWrap) && y > top && y < top + gv.outerHeight(dom.gv_galleryWrap); 141 }, 142 143 // determine if mouse is within the boundary of the panel 144 mouseIsOverPanel: function (x, y) { 145 var self = this, 146 dom = this.dom, 147 pos = this.getPos(dom.gv_panelWrap), 148 gPos = this.getPos(dom.gv_galleryWrap), 149 top = pos.top + gPos.top, 150 left = pos.left + gPos.left; 151 152 return x > left && x < left + gv.outerWidth(dom.gv_panelWrap) && y > top && y < top + gv.outerHeight(dom.gv_panelWrap); 153 }, 154 155 // create gvImage objects for each image in gallery 156 storeImages: function() { 157 var self = this; 158 this.sourceImgs = $('li>img',this.$el); 159 this.numImages = this.sourceImgs.length; 160 this.gvImages = []; 161 this.sourceImgs.each(function(i,img) { 162 self.gvImages[i] = new gvImage($(img)); 163 }); 164 }, 165 166 setDimensions: function() { 167 var self = this, 168 dom = this.dom, 169 widths = { 170 prev: gv.innerWidth(dom.gv_navPrev), 171 play: gv.innerWidth(dom.gv_navPlay), 172 next: gv.innerWidth(dom.gv_navNext), 173 filmstrip: this.opts.frame_width, 174 fsMax: 0, 175 fsFull: 0 176 }, 177 heights = {
178 prev: gv.innerHeight(dom.gv_navPrev), 179 play: gv.innerHeight(dom.gv_navPlay), 180 next: gv.innerHeight(dom.gv_navNext), 181 filmstrip: this.opts.frame_height + (this.opts.show_captions ? gv.outerHeight(dom.gv_caption) : 0), 182 fsMax: 0, 183 fsFull: 0 184 }, 185 panels = []; 186 187 // nav 188 if(this.filmstripOrientation === 'horizontal') { 189 dom.gv_navWrap.css({ 190 width: widths.prev + widths.play + widths.next, 191 height: Math.max(heights.prev,heights.play,heights.next) 192 }); 193 } else { 194 if(this.opts.filmstrip_style === 'scroll' && this.opts.frame_width < (widths.prev + widths.play + widths.next)) { 195 dom.gv_navWrap.css({ 196 width: Math.max(widths.prev, widths.play, widths.next), 197 height: heights.prev + heights.play + heights.next 198 }); 199 } else { 200 dom.gv_navWrap.css({ 201 width: widths.prev + widths.play + widths.next, 202 height: Math.max(heights.prev,heights.play,heights.next) 203 }); 204 } 205 } 206 207 if(this.filmstripOrientation === 'vertical' && widths.filmstrip < (widths.prev + widths.play + widths.next)) { 208 dom.gv_navWrap.css({ 209 width: Math.max(widths.prev, widths.play, widths.next), 210 height: heights.prev + heights.play + heights.next 211 }); 212 } else { 213 dom.gv_navWrap.css({ 214 width: widths.prev + widths.play + widths.next, 215 height: Math.max(heights.prev,heights.play,heights.next) 216 }); 217 } 218 219 // panels 220 dom.gv_panel.css({ 221 width: this.opts.panel_width, 222 height: this.opts.panel_height 223 }); 224 dom.gv_panelWrap.css({ 225 width: gv.outerWidth(dom.gv_panel), 226 height: gv.outerHeight(dom.gv_panel) 227 }); 228 dom.gv_overlay.css({ 229 width: this.opts.panel_width 230 }); 231 232 233 234 $.each(this.gvImages,function(i,img) { 235 dom.gv_panelWrap.append(dom.gv_panel.clone(true)); 236 }); 237 238 dom.gv_panels = dom.gv_panelWrap.find('.gv_panel'); 239 dom.gv_panels.remove(); 240 241 // filmstrip 242 dom.gv_thumbnail.css({ 243 width: this.opts.frame_width, 244 height: this.opts.frame_height 245 }); 246 dom.gv_frame.css({ 247 width: gv.outerWidth(dom.gv_thumbnail), 248 height: gv.outerHeight(dom.gv_thumbnail) + (this.opts.show_captions ? gv.outerHeight(dom.gv_caption) : 0), 249 marginRight: this.opts.frame_gap, 250 marginBottom: this.opts.frame_gap 251 }); 252 253 254 if(this.filmstripOrientation === 'horizontal') { 255 this.filmstripSize = Math.floor((gv.outerWidth(dom.gv_panelWrap) - gv.outerWidth(dom.gv_navWrap)) / (gv.outerWidth(dom.gv_frame) + this.opts.frame_gap)); 256 widths.fsMax = this.filmstripSize * (gv.outerWidth(dom.gv_frame) + this.opts.frame_gap); 257 widths.fsFull = this.gvImages.length * (gv.outerWidth(dom.gv_frame) + this.opts.frame_gap); 258 widths.filmstrip = Math.min(widths.fsMax,widths.fsFull); 259 if(this.opts.filmstrip_style !== 'scroll') { 260 heights.filmstrip = (Math.ceil(this.gvImages.length / this.filmstripSize) * (gv.outerHeight(dom.gv_frame) + this.opts.frame_gap)) - this.opts.frame_gap; 261 } 262 } else { 263 this.filmstripSize = Math.floor((gv.outerHeight(dom.gv_panelWrap) - gv.outerHeight(dom.gv_navWrap)) / (gv.outerHeight(dom.gv_frame) + this.opts.frame_gap)); 264 heights.fsMax = this.filmstripSize * (gv.outerHeight(dom.gv_frame) + this.opts.frame_gap); 265 heights.fsFull = this.gvImages.length * (gv.outerHeight(dom.gv_frame) + this.opts.frame_gap); 266 heights.filmstrip = Math.min(heights.fsMax,heights.fsFull); 267 if(this.opts.filmstrip_style !== 'scroll') { 268 widths.filmstrip = (Math.ceil(this.gvImages.length / this.filmstripSize) * (gv.outerWidth(dom.gv_frame) + this.opts.frame_gap)) - this.opts.frame_gap; 269 } 270 } 271 dom.gv_filmstripWrap.css({ 272 width: widths.filmstrip, 273 height: heights.filmstrip 274 }); 275 276 // gallery 277 if(this.opts.show_filmstrip) { 278 if(this.filmstripOrientation === 'horizontal') { 279 dom.gv_gallery.css({ 280 width: gv.outerWidth(dom.gv_panelWrap), 281 height: gv.outerHeight(dom.gv_panelWrap) + this.opts.frame_gap + (this.opts.show_filmstrip ? Math.max(gv.outerHeight(dom.gv_filmstripWrap),gv.outerHeight(dom.gv_navWrap)) : gv.outerHeight(dom.gv_filmstripWrap)) 282 }); 283 } else { 284 dom.gv_gallery.css({ 285 width: gv.outerWidth(dom.gv_panelWrap) + this.opts.frame_gap + (this.opts.show_filmstrip ? Math.max(gv.outerWidth(dom.gv_filmstripWrap),gv.outerWidth(dom.gv_navWrap)) : gv.outerWidth(dom.gv_filmstripWrap)), 286 height: gv.outerHeight(dom.gv_panelWrap) 287 }); 288 } 289 } else { 290 dom.gv_gallery.css({ 291 width: gv.outerWidth(dom.gv_panelWrap), 292 height: gv.outerHeight(dom.gv_panelWrap) 293 }); 294 } 295 296 dom.gv_galleryWrap.css({ 297 width: gv.outerWidth(dom.gv_gallery), 298 height: gv.outerHeight(dom.gv_gallery), 299 padding: this.opts.frame_gap 300 }); 301 }, 302 303 setPositions: function() { 304 var self = this, 305 dom = this.dom, 306 navVert = 0, fsVert = 0, 307 navHorz = 0, fsHorz = 0, 308 vert, horz; 309 310 // determine vertical or horizontal offset 311 // if negative, apply to filmstrip, otherwise apply to navbar 312 if(this.filmstripOrientation === 'horizontal') { 313 vert = Math.round((gv.outerHeight(dom.gv_filmstripWrap) - gv.outerHeight(dom.gv_navWrap)) / 2); 314 if(vert < 0) { fsVert = -1 * vert; } 315 else { navVert = vert; } 316 } else { 317 horz = Math.round((gv.outerWidth(dom.gv_filmstripWrap) - gv.outerWidth(dom.gv_navWrap)) / 2); 318 if(horz < 0) { fsHorz = -1 * horz; } 319 else { navHorz = horz; } 320 } 321 322 // for horizontal filmstrips w/o navigation, center the filmstrip under the panel 323 if(!this.opts.show_filmstrip_nav && this.filmstripOrientation === 'horizontal') { 324 fsHorz = Math.floor((gv.outerWidth(dom.gv_panelWrap) - gv.outerWidth(dom.gv_filmstripWrap)) / 2); 325 } 326 327 dom.gv_panelNavNext.css({ top: (gv.outerHeight(dom.gv_panel) - gv.outerHeight(dom.gv_panelNavNext)) / 2, right: 10 }); 328 dom.gv_panelNavPrev.css({ top: (gv.outerHeight(dom.gv_panel) - gv.outerHeight(dom.gv_panelNavPrev)) / 2, left: 10 }); 329 330 // pin elements to gallery corners according to filmstrip position 331 switch(this.opts.filmstrip_position) { 332 case 'top': 333 dom.gv_navWrap.css({ top: navVert, right: navHorz }); 334 dom.gv_panelWrap.css({ bottom: 0, left: 0 }); 335 dom.gv_filmstripWrap.css({ top: fsVert, left: fsHorz }); 336 break; 337 338 case 'right': 339 dom.gv_navWrap.css({ bottom: navVert, right: navHorz }); 340 dom.gv_panelWrap.css({ top: 0, left: 0 }); 341 dom.gv_filmstripWrap.css({ top: fsVert, right: fsHorz }); 342 break; 343 344 case 'left': 345 dom.gv_navWrap.css({ bottom: navVert, left: navHorz }); 346 dom.gv_panelWrap.css({ top: 0, right: 0 }); 347 dom.gv_filmstripWrap.css({ top: fsVert, left: fsHorz }); 348 break; 349 350 default: 351 dom.gv_navWrap.css({ bottom: navVert, right: navHorz }); 352 dom.gv_panelWrap.css({ top: 0, left: 0 }); 353 dom.gv_filmstripWrap.css({ bottom: fsVert, left: fsHorz }); 354 break; 355 } 356 357 if(this.opts.overlay_position === 'top') { 358 dom.gv_overlay.css({ top: 0, left: -99999 }); 359 dom.gv_showOverlay.css({ top: 0, left: 0 }); 360 } else { 361 dom.gv_overlay.css({ bottom: 0, left: -99999 }); 362 dom.gv_showOverlay.css({ bottom: 0, left: 0 }); 363 } 364 365 if(!this.opts.show_filmstrip_nav) { 366 dom.gv_navWrap.remove(); 367 } 368 }, 369 370 buildFilmstrip: function() { 371 var self = this, 372 dom = this.dom, 373 framesLength = this.gvImages.length * ((this.filmstripOrientation === 'horizontal' ? this.opts.frame_width : this.opts.frame_height) + this.opts.frame_gap); 374 375 dom.gv_frame.append(dom.gv_thumbnail); 376 if(this.opts.show_captions) { 377 dom.gv_frame.append(dom.gv_caption); 378 } 379 dom.gv_thumbnail.css('opacity',this.opts.frame_opacity); 380 381 dom.gv_thumbnail.bind({ 382 mouseover: function() { 383 if(!$(this).hasClass('current')) { 384 $(this).stop().animate({opacity:1},250); 385 } 386 }, 387 mouseout: function() { 388 if(!$(this).hasClass('current')) { 389 $(this).stop().animate({opacity:self.opts.frame_opacity},250); 390 } 391 } 392 }); 393 394 // Drop a clone of the frame element into the filmstrip for each source image 395 $.each(this.gvImages,function(i,img) { 396 dom.gv_frame.clone(true).prependTo(dom.gv_filmstrip); 397 }); 398 399 dom.gv_filmstrip.css({ 400 width: gv.outerWidth(dom.gv_frame), 401 height: gv.outerHeight(dom.gv_frame) 402 }); 403 404 // If we are scrolling the filmstrip, and we can't show all frames at once, 405 // make two additional copies of each frame 406 if(this.opts.filmstrip_style === 'scroll') { 407 if(this.filmstripOrientation === 'horizontal') { 408 if(framesLength > gv.innerWidth(dom.gv_filmstripWrap)) { 409 dom.gv_filmstrip.find('.gv_frame').clone(true).appendTo(dom.gv_filmstrip).clone(true).appendTo(dom.gv_filmstrip); 410 dom.gv_filmstrip.css('width',framesLength * 3); 411 this.scrolling = true; 412 } else { 413 dom.gv_filmstrip.css('width',framesLength); 414 } 415 } else { 416 if(framesLength >
416 gv.innerHeight(dom.gv_filmstripWrap)) { 417 dom.gv_filmstrip.find('.gv_frame').clone(true).appendTo(dom.gv_filmstrip).clone(true).appendTo(dom.gv_filmstrip); 418 dom.gv_filmstrip.css('height',framesLength * 3); 419 this.scrolling = true; 420 } else { 421 dom.gv_filmstrip.css('height',framesLength); 422 } 423 } 424 } else { 425 dom.gv_filmstrip.css({ 426 width: parseInt(dom.gv_filmstripWrap.css('width'),10)+this.opts.frame_gap, 427 height: parseInt(dom.gv_filmstripWrap.css('height'),10)+this.opts.frame_gap 428 }); 429 } 430 dom.gv_frames = dom.gv_filmstrip.find('.gv_frame'); 431 $.each(dom.gv_frames,function(i,frame) { 432 $(frame).data('frameIndex',i); 433 }); 434 dom.gv_thumbnails = dom.gv_filmstrip.find('div.gv_thumbnail'); 435 }, 436 437 buildGallery: function() { 438 var self = this, 439 dom = this.dom; 440 441 this.setDimensions(); 442 this.setPositions(); 443 444 if(this.opts.show_filmstrip) { 445 this.buildFilmstrip(); 446 } 447 }, 448 449 showInfoBar: function() { 450 if(!this.opts.show_infobar) { return; } 451 var self = this, 452 dom = this.dom; 453 454 dom.gv_infobar.stop().stopTime('hideInfoBar_' + self.id).html((this.iterator+1) + ' of ' + this.numImages).show().css('opacity',this.opts.infobar_opacity); 455 456 dom.gv_infobar.oneTime(2000 + this.opts.transition_speed,'hideInfoBar_' + self.id,function() { 457 dom.gv_infobar.fadeOut(1000); 458 }); 459 }, 460 461 initImages: function() { 462 var self = this, 463 dom = this.dom; 464 $.each(this.gvImages,function(i,gvImage) { 465 var img = $('<img/>'); 466 img.css('visibility','hidden').data('index',i); 467 img.bind('load.galleryview',function() { 468 var _img = $(this), 469 index = _img.data('index'), 470 width = this.width, 471 height = this.height, 472 parent = dom[(_img.data('parent')).type].eq((_img.data('parent')).index), 473 widthFactor = gv.innerWidth(parent) / width, 474 heightFactor = gv.innerHeight(parent) / height, 475 parentType = parent.hasClass('gv_panel') ? 'panel' : 'frame', 476 heightOffset = 0, widthOffset = 0; 477 478 gvImage.scale[parentType] = self.opts[parentType+'_scale'] === 'fit' ? Math.min(widthFactor,heightFactor) : Math.max(widthFactor,heightFactor); 479 480 widthOffset = Math.round((gv.innerWidth(parent) - (width * gvImage.scale[parentType])) / 2); 481 heightOffset = Math.round((gv.innerHeight(parent) - (height * gvImage.scale[parentType])) / 2); 482 483 _img.css({ 484 width: width * gvImage.scale[parentType], 485 height: height * gvImage.scale[parentType], 486 top: heightOffset, 487 left: widthOffset 488 }); 489 _img.hide().css('visibility','visible'); 490 _img.remove().appendTo(parent); 491 492 if(parentType === 'frame') { 493 _img.fadeIn(); 494 parent.parent().removeClass('gv_frame-loading'); 495 parent.parent().find('.gv_caption').html(gvImage.attrs.title); 496 } else if(index === self.opts.start_frame - 1) { 497 parent.prependTo(dom.gv_panelWrap); 498 parent.removeClass('gv_panel-loading'); 499 _img.fadeIn(); 500 self.showInfoBar(); 501 } else { 502 parent.removeClass('gv_panel-loading'); 503 _img.show(); 504 } 505 }); 506 507 // store eventual image container as data property 508 // append to temporary storage element and set src 509 if(self.opts.show_panels) { 510 img.clone(true) 511 .data('parent',{type:'gv_panels',index:i}) 512 .appendTo(dom.gv_imageStore) 513 .attr('src',gvImage.src.panel); 514 } 515 516 if(self.opts.show_filmstrip) { 517 img.clone(true) 518 .data('parent',{type:'gv_thumbnails',index:i}) 519 .appendTo(dom.gv_imageStore) 520 .attr('src',gvImage.src.frame); 521 522 if(dom.gv_frames.length > dom.gv_panels.length) { 523 img.clone(true) 524 .data('parent',{type:'gv_thumbnails',index:i+self.numImages}) 525 .appendTo(dom.gv_imageStore) 526 .attr('src',gvImage.src.frame); 527 528 img.clone(true) 529 .data('parent',{type:'gv_thumbnails',index:i+self.numImages+self.numImages}) 530 .appendTo(dom.gv_imageStore) 531 .attr('src',gvImage.src.frame); 532 } 533 } 534 }); 535 }, 536 537 showNext: function() { 538 this.navAction = 'next'; 539 this.showItem(this.frameIterator+1); 540 }, 541 542 showPrev: function() { 543 this.navAction = 'prev'; 544 this.showItem(this.frameIterator-1); 545 }, 546 547 showItem: function(i) { 548 if(isNaN(i)) { return; } 549 if(!this.opts.show_filmstrip) { i = i % this.numImages; } 550 551 var self = this, 552 dom = this.dom, 553 frame_i = i, 554 newPanelStart, 555 oldPanelEnd, 556 oldIterator, 557 panel, 558 playing = false;
559 560 // don't go out of bounds 561 if(i >= this.numImages) { 562 i = i % this.numImages; 563 } else if(i < 0) { 564 i = this.numImages - 1; 565 if(dom.gv_frames != undefined) { 566 frame_i = dom.gv_frames.length - 1; 567 } else { 568 frame_i = dom.gv_panels.length - 1; 569 } 570 } 571 572 panel = dom.gv_panels.eq(i); 573 574 playing = this.playing; 575 576 if(playing) { 577 this.stopSlideshow(false); 578 } 579 580 this.unbindActions(); 581 582 dom.gv_gallery.oneTime(this.opts.transition_speed,'bindActions_' + self.id,function(){ if(playing) { self.startSlideshow(false); } self.bindActions(); }); 583 584 switch(this.opts.panel_animation) { 585 case 'crossfade': 586 dom.gv_panels.eq(this.iterator).fadeOut(this.opts.transition_speed,function(){$(this).remove();}); 587 panel.hide().prependTo(dom.gv_panelWrap).fadeIn(this.opts.transition_speed); 588 break; 589 case 'fade': 590 dom.gv_panels.eq(this.iterator).remove(); 591 panel.hide().prependTo(dom.gv_panelWrap).fadeIn(this.opts.transition_speed); 592 break; 593 case 'slide': 594 if(this.navAction === 'next' || (this.navAction === 'frame' && frame_i > this.iterator)) { 595 newPanelStart = gv.outerWidth(dom.gv_panel); 596 oldPanelEnd = -1 * gv.outerWidth(dom.gv_panel); 597 } else { 598 newPanelStart = -1 * gv.outerWidth(dom.gv_panel); 599 oldPanelEnd = gv.outerWidth(dom.gv_panel); 600 } 601 602 panel.css({ left:newPanelStart }).appendTo(dom.gv_panelWrap).animate( 603 { left:0 }, 604 { duration: this.opts.transition_speed,easing: this.opts.easing } 605 ); 606 607 dom.gv_panels.eq(this.iterator).animate( 608 { left: oldPanelEnd }, 609 { duration: this.opts.transition_speed, easing: this.opts.easing, complete: function(){ $(this).remove(); } } 610 ); 611 break; 612 default: 613 dom.gv_panels.eq(this.iterator).remove(); 614 panel.prependTo(dom.gv_panelWrap); 615 break; 616 } 617 618 this.updateOverlay(i); 619 620 this.iterator = i; 621 this.updateFilmstrip(frame_i); 622 this.showInfoBar(); 623 624 625 }, 626 627 updateOverlay: function(i) { 628 var self = this, 629 dom = this.dom; 630 631 if(this.overlayVisible) { 632 this.hideOverlay(null,function(){ 633 dom.gv_overlay.html('<h4>'+self.gvImages[i].attrs.title+'</h4><p>'+self.gvImages[i].attrs.description+'</p>'); 634 self.showOverlay(); 635 }); 636 } else { 637 dom.gv_overlay.html('<h4>'+self.gvImages[i].attrs.title+'</h4><p>'+self.gvImages[i].attrs.description+'</p>'); 638 dom.gv_overlay.css(this.opts.overlay_position,-1 * dom.gv_overlay.outerHeight()); 639 } 640 641 }, 642 643 hideOverlay: function(s,callback) { 644 var self = this, 645 dom = this.dom, 646 endOverlay = {}, 647 endButton = {}, 648 speed = s || self.opts.transition_speed / 2; 649 650 callback = callback || function(){}; 651 652 endOverlay[this.opts.overlay_position] = -1 * dom.gv_overlay.outerHeight(); 653 endButton[this.opts.overlay_position] = 0; 654 655 dom.gv_overlay.animate(endOverlay,{ 656 duration: speed, 657 easing: 'swing', 658 complete: callback 659 }); 660 dom.gv_showOverlay.animate(endButton,{ 661 duration: speed, 662 easing: 'swing' 663 }); 664 665 this.overlayVisible = false; 666 }, 667 668 showOverlay: function(s) { 669 var self = this, 670 dom = this.dom, 671 startOverlay = {}, 672 endOverlay = {}, 673 endButton = {}, 674 speed = s || self.opts.transition_speed / 2; 675 676 startOverlay[this.opts.overlay_position] = -1 * dom.gv_overlay.outerHeight(); 677 startOverlay.left = 0; 678 679 endOverlay[this.opts.overlay_position] = 0; 680 681 endButton[this.opts.overlay_position] = dom.gv_overlay.outerHeight(); 682 683 dom.gv_overlay.css(startOverlay); 684 dom.gv_overlay.animate(endOverlay,{ duration: speed, easing: 'swing' }); 685 dom.gv_showOverlay.animate(endButton,{ duration: speed, easing: 'swing' }); 686 687 this.overlayVisible = true; 688 }, 689 690 updateFilmstrip: function(to) { 691 if(!this.opts.show_filmstrip) { this.frameIterator = to; return; } 692 var self = this, 693 dom = this.dom, 694 targetThumbs = dom.gv_thumbnails.eq(this.iterator), 695 filmstripIterator, 696 distance; 697 698 if(this.scrolling) { 699 targetThumbs = targetThumbs. 700 add(dom.gv_thumbnails.eq(this.iterator + this.numImages)). 701 add(dom.gv_thumbnails.eq(this.iterator + (2 * this.numImages))); 702 } 703 704 dom.gv_thumbnails.removeClass('current').animate({ opacity: this.opts.frame_opacity }); 705 targetThumbs.stop().addClass('current').animate({ opacity: 1 },500); 706 707 708 if(this.scrolling) { 709 if(this.filmstripOrientation === 'horizontal') { 710 distance = (gv.outerWidth(dom.gv_frame) + this.opts.frame_gap) * (this.frameIterator - to); 711 712 if(distance > 0) { 713 distance = '+=' + Math.abs(distance); 714 } else { 715 distance = '-=' + Math.abs(distance); 716 } 717 dom.gv_filmstrip.animate({ 718 left: distance 719 },{ 720 duration: this.opts.transition_speed, 721 easing: this.opts.easing, 722 complete: function(){ 723 if(to < self.numImages) { 724 dom.gv_filmstrip.css('left',gv.getInt(dom.gv_filmstrip.css('left'))-(self.numImages*(gv.outerWidth(dom.gv_frame)+self.opts.frame_gap))); 725 } else if(to >= (self.numImages * 2)) { 726 dom.gv_filmstrip.css('left',gv.getInt(dom.gv_filmstrip.css('left'))+(self.numImages*(gv.outerWidth(dom.gv_frame)+self.opts.frame_gap))); 727 } 728 self.frameIterator = (to % self.numImages) + self.numImages; 729 } 730 }); 731 } else { 732 distance = (gv.outerHeight(dom.gv_frame) + this.opts.frame_gap) * (this.frameIterator - to); 733 734 if(distance > 0) { 735 distance = '+=' + Math.abs(distance); 736 } else { 737 distance = '-=' + Math.abs(distance); 738 } 739 dom.gv_filmstrip.animate({ 740 top: distance 741 },{ 742 duration: this.opts.transition_speed, 743 easing: this.opts.easing, 744 complete: function(){ 745 // adjust filmstrip position to ensure that there is always at least one frame behind 746 // and (2 * filmstripSize) ahead 747 if(to === 0) { 748 dom.gv_filmstrip.css('top',gv.getInt(dom.gv_filmstrip.css('top'))-(self.numImages*(gv.outerHeight(dom.gv_frame)+self.opts.frame_gap))); 749 self.frameIterator = self.numImages; 750 } else if(to > ((self.numImages * 3) - (self.filmstripSize * 2))) { 751 dom.gv_filmstrip.css('top',gv.getInt(dom.gv_filmstrip.css('top'))+(self.numImages*(gv.outerHeight(dom.gv_frame)+self.opts.frame_gap))); 752 self.frameIterator = to - self.numImages; 753 } else { 754 self.frameIterator = to; 755 } 756 } 757 }); 758 } 759 760 } else { 761 this.frameIterator = to; 762 } 763 }, 764
765 startSlideshow: function(changeIcon) { 766 var self = this, 767 dom = this.dom; 768 769 if(!self.opts.enable_slideshow) { return; } 770 771 if(changeIcon) { 772 dom.gv_navPlay.removeClass('gv_navPlay').addClass('gv_navPause'); 773 } 774 this.playing = true; 775 dom.gv_galleryWrap.everyTime(this.opts.transition_interval,'slideshow_'+this.id,function(){ self.showNext(); }); 776 }, 777 778 stopSlideshow: function(changeIcon) { 779 var self = this, 780 dom = this.dom; 781 782 if(changeIcon) { 783 dom.gv_navPlay.removeClass('gv_navPause').addClass('gv_navPlay'); 784 } 785 this.playing = false; 786 dom.gv_galleryWrap.stopTime('slideshow_'+this.id); 787 }, 788 789 enablePanning: function() { 790 var self = this, 791 dom = this.dom; 792 793 if(!self.opts.enable_slideshow) { return; } 794 795 dom.gv_panel.css('cursor','url(http://www.google.com/intl/en_ALL/mapfiles/openhand.cur), n-resize'); 796 if(this.opts.pan_style === 'drag') { 797 dom.gv_panelWrap.delegate('.gv_panel img','mousedown.galleryview',function(e) { 798 self.isMouseDown = true; 799 $(this).css('cursor','url(http://www.google.com/intl/en_ALL/mapfiles/closedhand.cur), n-resize'); 800 }).delegate('.gv_panel img','mouseup.galleryview',function(e) { 801 self.isMouseDown = false; 802 $(this).css('cursor','url(http://www.google.com/intl/en_ALL/mapfiles/openhand.cur), n-resize'); 803 }).delegate('.gv_panel img','mousemove.galleryview',function(e) { 804 var distY, distX, 805 image = $(this), 806 new_top, new_left; 807 808 if(self.isMouseDown) { 809 distY = e.pageY - self.mouse.y; 810 distX = e.pageX - self.mouse.x; 811 new_top = gv.getInt(image.css('top')) + distY; 812 new_left = gv.getInt(image.css('left')) + distX; 813 814 image.css('cursor','url(http://www.google.com/intl/en_ALL/mapfiles/closedhand.cur), n-resize'); 815 816 if(new_top > 0) new_top = 0; 817 if(new_left > 0) new_left = 0; 818 819 if(new_top < (-1 * (gv.outerHeight(image) - gv.innerHeight(dom.gv_panel)))) { new_top = -1 * (gv.outerHeight(image) - gv.innerHeight(dom.gv_panel)); } 820 if(new_left < (-1 * (gv.outerWidth(image) - gv.innerWidth(dom.gv_panel)))) { new_left = -1 * (gv.outerWidth(image) - gv.innerWidth(dom.gv_panel)); } 821 822 image.css('top',new_top); 823 image.css('left',new_left); 824 } else { 825 image.css('cursor','url(http://www.google.com/intl/en_ALL/mapfiles/openhand.cur), n-resize'); 826 } 827 }); 828 } else { 829 830 } 831 }, 832 833 bindActions: function() { 834 var self = this, 835 dom = this.dom; 836 837 dom.gv_showOverlay.bind('click.galleryview',function(){ 838 if(self.overlayVisible) { 839 self.hideOverlay(250); 840 } else { 841 self.showOverlay(250); 842 } 843 }); 844 845 dom.gv_navWrap.delegate('div','click.galleryview',function(){ 846 var el = $(this); 847 if(el.hasClass('gv_navNext')) { 848 self.showNext(); 849 } else if(el.hasClass('gv_navPrev')) { 850 self.showPrev(); 851 } else if(el.hasClass('gv_navPlay')) { 852 self.startSlideshow(true); 853 } else if(el.hasClass('gv_navPause')) { 854 self.stopSlideshow(true); 855 } 856 return false; 857 }); 858 859 dom.gv_panelNavNext.bind('click.galleryview',function(){ 860 self.showNext(); 861 return false; 862 }); 863 dom.gv_panelNavPrev.bind('click.galleryview',function(){ 864 self.showPrev(); 865 return false; 866 }); 867 868 dom.gv_filmstripWrap.delegate('.gv_frame','click.galleryview',function(){ 869 var el = $(this), 870 i = el.data('frameIndex'); 871 872 this.navAction = 'frame'; 873 self.showItem(i); 874 return false; 875 }); 876 877 dom.gv_panelWrap.bind('mouseover.galleryview',function(){ 878 self.showPanelNav(); 879 }).bind('mouseout.galleryview',function(){ 880 self.hidePanelNav(); 881 }); 882 }, 883 884 unbindActions: function() { 885 var self = this, 886 dom = this.dom; 887 888 dom.gv_showOverlay.unbind('click.galleryview'); 889 dom.gv_panelNavNext.unbind('click.galleryview'); 890 dom.gv_panelNavPrev.unbind('click.galleryview'); 891 dom.gv_navWrap.undelegate('div','click.galleryview'); 892 dom.gv_filmstripWrap.undelegate('.gv_frame','click.galleryview'); 893 }, 894 895 showPanelNav: function() { 896 var self = this, 897 dom = this.dom; 898 899 dom.gv_panelNavNext.show(); 900 dom.gv_panelNavPrev.show(); 901 }, 902 903 hidePanelNav: function() { 904 var self = this, 905 dom = this.dom; 906 907 dom.gv_panelNavNext.hide(); 908 dom.gv_panelNavPrev.hide(); 909 }, 910 911 init: function(options,el) { 912 var self = this, 913 dom = this.dom = {}; 914 915 this.opts = $.extend({},$.fn.galleryView.defaults,options); 916 this.el = el; 917 this.$el = $(el); 918 this.id = el.id; 919 this.iterator = this.frameIterator = this.opts.start_frame - 1; 920 this.overlayVisible = false;
921 this.playing = false; 922 this.scrolling = false; 923 this.isMouseDown = false; 924 this.mouse = { x: 0, y: 0 }; 925 this.filmstripOrientation = (this.opts.filmstrip_position === 'top' || this.opts.filmstrip_position === 'bottom') ? 'horizontal' : 'vertical'; 926 927 $(document).bind('mousemove.galleryview',function(e) { 928 self.mouse = {x: e.pageX, y: e.pageY}; 929 }); 930 931 // create all necessary DOM elements 932 $.each(this.elems,function(i,elem) { 933 var elem = elem.split('.'); 934 935 // if there is no tag name, assume <div> 936 if(elem[0] === '') { elem[0] = 'div'; } 937 938 // add jQuery element to dom object 939 dom[elem[1]] = self.createElem({'class':elem[1]},elem[0]); 940 }); 941 942 dom.gv_imageStore.appendTo($('body')); 943 944 dom.gv_galleryWrap.delegate('img','mousedown.galleryview',function(e){ if(e.preventDefault) { e.preventDefault(); } }); 945 946 dom.gv_panel.addClass('gv_panel-loading'); 947 dom.gv_frame.addClass('gv_frame-loading'); 948 949 // nest DOM elements 950 dom.gv_galleryWrap.hide().append(dom.gv_gallery); 951 952 if(this.opts.show_panels) { 953 dom.gv_gallery.append(dom.gv_panelWrap); 954 if(this.opts.show_panel_nav) { 955 dom.gv_panelWrap.append(dom.gv_panelNavNext,dom.gv_panelNavPrev); 956 } 957 if(this.opts.show_infobar) { 958 dom.gv_panelWrap.append(dom.gv_infobar); 959 } 960 } 961 962 if(this.opts.show_filmstrip) { 963 dom.gv_gallery.append( 964 dom.gv_filmstripWrap.append( 965 dom.gv_filmstrip 966 ) 967 ); 968 969 if(this.opts.show_filmstrip_nav) { 970 dom.gv_gallery.append( 971 dom.gv_navWrap.append( 972 dom.gv_navPrev, 973 (this.opts.enable_slideshow?dom.gv_navPlay:$('<span></span>')), 974 dom.gv_navNext 975 ) 976 ); 977 } 978 } 979 980 if(this.opts.enable_overlays) { 981 dom.gv_panelWrap.append(dom.gv_overlay,dom.gv_showOverlay); 982 } 983 984 if(this.opts.show_captions) { 985 dom.gv_frame.append(dom.gv_caption).appendTo(dom.gv_gallery); 986 } 987 988 //swap out source element with gallery 989 this.$el.replaceWith(dom.gv_galleryWrap); 990 991 if(this.opts.pan_images) { 992 this.enablePanning(); 993 } 994 995 // convert source images into gvImage objects 996 this.storeImages(); 997 998 // block out dimensions/positions of gallery elements 999 this.buildGallery(); 1000 1001 // begin loading images into gallery 1002 this.initImages(); 1003 1004 // set up transitions, buttons 1005 this.bindActions(); 1006 1007 // remove temporary frame element 1008 dom.gv_frame.remove(); 1009 1010 // show gallery 1011 dom.gv_galleryWrap.show(); 1012 1013 if(this.opts.autoplay) { 1014 this.startSlideshow(true); 1015 } 1016 1017 this.updateOverlay(this.iterator); 1018 this.updateFilmstrip(this.frameIterator); 1019 } 1020 1021 }; // END GalleryView 1022 1023 /* 1024 MAIN PLUGIN CODE 1025 */ 1026 $.fn.galleryView = function (options) { 1027 if (this.length) { 1028 return this.each(function () { 1029 var gallery = Object.create(GalleryView); 1030 gallery.init(options,this); 1031 }); 1032 } 1033 }; 1034 1035 /* 1036 Default Options 1037 Object literal storing default plugin options 1038 */ 1039 $.fn.galleryView.defaults = { 1040 1041 // General Options 1042 transition_speed: 1000, //INT - duration of panel/frame transition (in milliseconds) 1043 transition_interval: 5000, //INT - delay between panel/frame transitions (in milliseconds) 1044 easing: 'swing', //STRING - easing method to use for animations (jQuery provides 'swing' or 'linear', more available with jQuery UI or Easing plugin) 1045 1046 // Panel Options 1047 show_panels: true, //BOOLEAN - flag to show or hide panel portion of gallery 1048 show_panel_nav: true, //BOOLEAN - flag to show or hide panel navigation buttons 1049 enable_overlays: false, //BOOLEAN - flag to show or hide panel overlays 1050 panel_width: 800, //INT - width of gallery panel (in pixels) 1051 panel_height: 400, //INT - height of gallery panel (in pixels) 1052 panel_animation: 'fade', //STRING - animation method for panel transitions (crossfade,fade,slide,none) 1053 panel_scale: 'crop', //STRING - cropping option for panel images (crop = scale image and fit to aspect ratio determined by panel_width and panel_height, fit = scale image and preserve original aspect ratio) 1054 overlay_position: 'bottom', //STRING - position of panel overlay (bottom, top) 1055 pan_images: false, //BOOLEAN - flag to allow user to grab/drag oversized images within gallery 1056 pan_style: 'drag', //STRING - panning method (drag = user clicks and drags image to pan, track = image automatically pans based on mouse position 1057 pan_smoothness: 15, //INT - determines smoothness of tracking pan animation (higher number = smoother) 1058 1059 // Filmstrip Options 1060 start_frame: 1, //INT - index of panel/frame to show first when gallery loads 1061 show_filmstrip: true, //BOOLEAN - flag to show or hide filmstrip portion of gallery 1062 show_filmstrip_nav: true, //BOOLEAN - flag indicating whether to display navigation buttons 1063 enable_slideshow: true, //BOOLEAN - flag indicating whether to display slideshow play/pause button 1064 autoplay: false, //BOOLEAN - flag to start slideshow on gallery load 1065 show_captions: false, //BOOLEAN - flag to show or hide frame captions 1066 filmstrip_size: 3, //INT - number of frames to show in filmstrip-only gallery 1067 filmstrip_style: 'scroll', //STRING - type of filmstrip to use (scroll = display one line of frames, scroll filmstrip if necessary, showall = display multiple rows of frames if necessary) 1068 filmstrip_position: 'bottom', //STRING - position of filmstrip within gallery (bottom, top, left, right) 1069 frame_width: 80, //INT - width of filmstrip frames (in pixels) 1070 frame_height: 40, //INT - width of filmstrip frames (in pixels) 1071 frame_opacity: 0.4, //FLOAT - transparency of non-active frames (1.0 = opaque, 0.0 = transparent) 1072 frame_scale: 'crop', //STRING - cropping option for filmstrip images (same as above) 1073 frame_gap: 5, //INT - spacing between frames within filmstrip (in pixels) 1074 1075 // Info Bar Options 1076 show_infobar: true, //BOOLEAN - flag to show or hide infobar 1077 infobar_opacity: 1 //FLOAT - transparency for info bar 1078 }; 1079})(jQuery);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.