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