1/* 2 * jQuery Orbit Plugin 1.4.0 3 * www.ZURB.com/playground 4 * Copyright 2010, ZURB 5 * Free to use under the MIT license. 6 * http://www.opensource.org/licenses/mit-license.php 7*/ 8 9 10(function ($) { 11 'use strict'; 12 13 $.fn.findFirstImage = function () { 14 return this.first() 15 .find('img') 16 .andSelf().filter('img') 17 .first(); 18 }; 19 20 var ORBIT = { 21 22 defaults: { 23 animation: 'horizontal-push', // fade, horizontal-slide, vertical-slide, horizontal-push, vertical-push 24 animationSpeed: 600, // how fast animations are 25 timer: true, // display timer? 26 advanceSpeed: 4000, // if timer is enabled, time between transitions 27 pauseOnHover: false, // if you hover pauses the slider 28 startClockOnMouseOut: false, // if clock should start on MouseOut 29 startClockOnMouseOutAfter: 1000, // how long after MouseOut should the timer start again 30 directionalNav: true, // manual advancing directional navs 31 directionalNavRightText: 'Right', // text of right directional element for accessibility 32 directionalNavLeftText: 'Left', // text of left directional element for accessibility 33 captions: true, // do you want captions? 34 captionAnimation: 'fade', // fade, slideOpen, none 35 captionAnimationSpeed: 600, // if so how quickly should they animate in 36 resetTimerOnClick: false, // true resets the timer instead of pausing slideshow progress on manual navigation 37 bullets: false, // true or false to activate the bullet navigation 38 bulletThumbs: false, // thumbnails for the bullets 39 bulletThumbLocation: '', // relative path to thumbnails from this file 40 bulletThumbsHideOnSmall: true, // hide thumbs on small devices 41 afterSlideChange: $.noop, // callback to execute after slide changes 42 afterLoadComplete: $.noop, // callback to execute after everything has been loaded 43 fluid: true, 44 centerBullets: true, // center bullet nav with js, turn this off if you want to position the bullet nav manually 45 singleCycle: false, // cycles through orbit slides only once 46 slideNumber: false, // display slide numbers? 47 stackOnSmall: false // stack slides on small devices (i.e. phones) 48 }, 49 50 activeSlide: 0, 51 numberSlides: 0, 52 orbitWidth: null, 53 orbitHeight: null, 54 locked: null, 55 timerRunning: null, 56 degrees: 0, 57 wrapperHTML: '<div class="orbit-wrapper" />', 58 timerHTML: '<div class="timer"><span class="mask"><span class="rotator"></span></span><span class="pause"></span></div>', 59 captionHTML: '<div class="orbit-caption"></div>', 60 directionalNavHTML: '<div class="slider-nav hide-for-small"><span class="right"></span><span class="left"></span></div>', 61 bulletHTML: '<ul class="orbit-bullets"></ul>', 62 slideNumberHTML: '<span class="orbit-slide-counter"></span>', 63 64 init: function (element, options) { 65 var $imageSlides, 66 imagesLoadedCount = 0, 67 self = this; 68 69 // Bind functions to correct context 70 this.clickTimer = $.proxy(this.clickTimer, this); 71 this.addBullet = $.proxy(this.addBullet, this); 72 this.resetAndUnlock = $.proxy(this.resetAndUnlock, this); 73 this.stopClock = $.proxy(this.stopClock, this); 74 this.startTimerAfterMouseLeave = $.proxy(this.startTimerAfterMouseLeave, this); 75 this.clearClockMouseLeaveTimer = $.proxy(this.clearClockMouseLeaveTimer, this); 76 this.rotateTimer = $.proxy(this.rotateTimer, this); 77 78 this.options = $.extend({}, this.defaults, options); 79 if (this.options.timer === 'false') this.options.timer = false; 80 if (this.options.captions === 'false') this.options.captions = false; 81 if (this.options.directionalNav === 'false') this.options.directionalNav = false; 82 83 this.$element = $(element); 84 this.$wrapper = this.$element.wrap(this.wrapperHTML).parent(); 85 this.$slides = this.$element.children('img, a, div, figure, li'); 86 87 this.$element.on('movestart', function(e) { 88 // If the movestart is heading off in an upwards or downwards 89 // direction, prevent it so that the browser scrolls normally. 90 if ((e.distX > e.distY && e.distX < -e.distY) || 91 (e.distX < e.distY && e.distX > -e.distY)) { 92 e.preventDefault(); 93 } 94 }); 95 96 this.$element.bind('orbit.next', function () { 97 self.shift('next'); 98 }); 99 100 this.$element.bind('orbit.prev', function () { 101 self.shift('prev'); 102 }); 103 104 this.$element.bind('swipeleft', function () { 105 $(this).trigger('orbit.next'); 106 }); 107 108 this.$element.bind('swiperight', function () { 109 $(this).trigger('orbit.prev'); 110 }); 111 112 this.$element.bind('orbit.goto', function (event, index) { 113 self.shift(index); 114 }); 115 116 this.$element.bind('orbit.start', function (event, index) { 117 self.startClock(); 118 }); 119 120 this.$element.bind('orbit.stop', function (event, index) { 121 self.stopClock(); 122 }); 123 124 $imageSlides = this.$slides.filter('img'); 125 126 if ($imageSlides.length === 0) { 127 this.loaded(); 128 } else { 129 $imageSlides.bind('imageready', function () { 130 imagesLoadedCount += 1; 131 if (imagesLoadedCount === $imageSlides.length) { 132 self.loaded(); 133 } 134 }); 135 } 136 }, 137 138 loaded: function () { 139 this.$element 140 .addClass('orbit') 141 .css({width: '1px', height: '1px'}); 142 143 if (this.options.stackOnSmall) { 144 this.$element.addClass('orbit-stack-on-small'); 145 } 146 147 this.$slides.addClass('orbit-slide').css({"opacity" : 0}); 148 149 this.setDimentionsFromLargestSlide(); 150 this.updateOptionsIfOnlyOneSlide(); 151 this.setupFirstSlide(); 152 this.notifySlideChange(); 153 154 if (this.options.timer) { 155 this.setupTimer(); 156 this.startClock(); 157 } 158 159 if (this.options.captions) { 160 this.setupCaptions(); 161 } 162 163 if (this.options.directionalNav) { 164 this.setupDirectionalNav(); 165 } 166 167 if (this.options.bullets) { 168 this.setupBulletNav(); 169 this.setActiveBullet(); 170 } 171 172 this.options.afterLoadComplete.call(this); 173 Holder.run(); 174 }, 175 176 currentSlide: function () { 177 return this.$slides.eq(this.activeSlide); 178 }, 179 180 notifySlideChange: function() { 181 if (this.options.slideNumber) { 182 var txt = (this.activeSlide+1) + ' of ' + this.$slides.length; 183 this.$element.trigger("orbit.change", {slideIndex: this.activeSlide, slideCount: this.$slides.length}); 184 if (this.$counter === undefined) { 185 var $counter = $(this.slideNumberHTML).html(txt); 186 this.$counter = $counter; 187 this.$wrapper.append(this.$counter); 188 } else { 189 this.$counter.html(txt); 190 } 191 } 192 }, 193 194 setDimentionsFromLargestSlide: function () { 195 //Collect all slides and set slider size of largest image 196 var self = this, 197 $fluidPlaceholder; 198 199 self.$element.add(self.$wrapper).width(this.$slides.first().outerWidth()); 200 self.$element.add(self.$wrapper).height(this.$slides.first().height()); 201 self.orbitWidth = this.$slides.first().outerWidth(); 202 self.orbitHeight = this.$slides.first().height(); 203 $fluidPlaceholder = this.$slides.first().findFirstImage().clone(); 204 205 206 this.$slides.each(function () { 207 var slide = $(this), 208 slideWidth = slide.outerWidth(), 209 slideHeight = slide.height(); 210 211 if (slideWidth > self.$element.outerWidth()) { 212 self.$element.add(self.$wrapper).width(slideWidth);
213 self.orbitWidth = self.$element.outerWidth(); 214 } 215 if (slideHeight > self.$element.height()) { 216 self.$element.add(self.$wrapper).height(slideHeight); 217 self.orbitHeight = self.$element.height(); 218 $fluidPlaceholder = $(this).findFirstImage().clone(); 219 } 220 self.numberSlides += 1; 221 }); 222 223 if (this.options.fluid) { 224 if (typeof this.options.fluid === "string") { 225 // $fluidPlaceholder = $("<img>").attr("src", "http://placehold.it/" + this.options.fluid); 226 $fluidPlaceholder = $("<img>").attr("data-src", "holder.js/" + this.options.fluid); 227 //var inner = $("<div/>").css({"display":"inline-block", "width":"2px", "height":"2px"}); 228 //$fluidPlaceholder = $("<div/>").css({"float":"left"}); 229 //$fluidPlaceholder.wrapInner(inner); 230 231 //$fluidPlaceholder = $("<div/>").css({"height":"1px", "width":"2px"}); 232 //$fluidPlaceholder = $("<div style='display:inline-block;width:2px;height:1px;'></div>"); 233 } 234 235 self.$element.prepend($fluidPlaceholder); 236 $fluidPlaceholder.addClass('fluid-placeholder'); 237 self.$element.add(self.$wrapper).css({width: 'inherit'}); 238 self.$element.add(self.$wrapper).css({height: 'inherit'}); 239 240 $(window).bind('resize', function () { 241 self.orbitWidth = self.$element.outerWidth(); 242 self.orbitHeight = self.$element.height(); 243 }); 244 } 245 }, 246 247 //Animation locking functions 248 lock: function () { 249 this.locked = true; 250 }, 251 252 unlock: function () { 253 this.locked = false; 254 }, 255 256 updateOptionsIfOnlyOneSlide: function () { 257 if(this.$slides.length === 1) { 258 this.options.directionalNav = false; 259 this.options.timer = false; 260 this.options.bullets = false; 261 } 262 }, 263 264 setupFirstSlide: function () { 265 //Set initial front photo z-index and fades it in 266 var self = this; 267 this.$slides.first() 268 .css({"z-index" : 3, "opacity" : 1}) 269 .fadeIn(function() { 270 //brings in all other slides IF css declares a display: none 271 self.$slides.css({"display":"block"}) 272 }); 273 }, 274 275 startClock: function () { 276 var self = this; 277 278 if(!this.options.timer) { 279 return false; 280 } 281 282 if (this.$timer.is(':hidden')) { 283 this.clock = setInterval(function () { 284 self.$element.trigger('orbit.next'); 285 }, this.options.advanceSpeed); 286 } else { 287 this.timerRunning = true; 288 this.$pause.removeClass('active'); 289 this.clock = setInterval(this.rotateTimer, this.options.advanceSpeed / 180, false); 290 } 291 }, 292 293 rotateTimer: function (reset) { 294 var degreeCSS = "rotate(" + this.degrees + "deg)"; 295 this.degrees += 2; 296 this.$rotator.css({ 297 "-webkit-transform": degreeCSS, 298 "-moz-transform": degreeCSS, 299 "-o-transform": degreeCSS, 300 "-ms-transform": degreeCSS 301 }); 302 if (reset) { 303 this.degrees = 0; 304 this.$rotator.removeClass('move'); 305 this.$mask.removeClass('move'); 306 } 307 if(this.degrees > 180) { 308 this.$rotator.addClass('move'); 309 this.$mask.addClass('move'); 310 } 311 if(this.degrees > 360) { 312 this.$rotator.removeClass('move'); 313 this.$mask.removeClass('move'); 314 this.degrees = 0; 315 this.$element.trigger('orbit.next'); 316 } 317 }, 318 319 stopClock: function () { 320 if (!this.options.timer) { 321 return false; 322 } else { 323 this.timerRunning = false; 324 clearInterval(this.clock); 325 this.$pause.addClass('active'); 326 } 327 }, 328 329 setupTimer: function () { 330 this.$timer = $(this.timerHTML); 331 this.$wrapper.append(this.$timer); 332 333 this.$rotator = this.$timer.find('.rotator'); 334 this.$mask = this.$timer.find('.mask'); 335 this.$pause = this.$timer.find('.pause'); 336 337 this.$timer.click(this.clickTimer); 338 339 if (this.options.startClockOnMouseOut) { 340 this.$wrapper.mouseleave(this.startTimerAfterMouseLeave); 341 this.$wrapper.mouseenter(this.clearClockMouseLeaveTimer); 342 } 343 344 if (this.options.pauseOnHover) { 345 this.$wrapper.mouseenter(this.stopClock); 346 } 347 }, 348 349 startTimerAfterMouseLeave: function () { 350 var self = this; 351 352 this.outTimer = setTimeout(function() { 353 if(!self.timerRunning){ 354 self.startClock(); 355 } 356 }, this.options.startClockOnMouseOutAfter) 357 }, 358 359 clearClockMouseLeaveTimer: function () { 360 clearTimeout(this.outTimer); 361 }, 362 363 clickTimer: function () { 364 if(!this.timerRunning) { 365 this.startClock(); 366 } else { 367 this.stopClock(); 368 } 369 }, 370 371 setupCaptions: function () { 372 this.$caption = $(this.captionHTML); 373 this.$wrapper.append(this.$caption); 374 this.setCaption(); 375 }, 376 377 setCaption: function () { 378 var captionLocation = this.currentSlide().attr('data-caption'), 379 captionHTML; 380 381 if (!this.options.captions) { 382 return false; 383 } 384 385 //Set HTML for the caption if it exists 386 if (captionLocation) { 387 //if caption text is blank, don't show captions 388 if ($.trim($(captionLocation).text()).length < 1){ 389 return false; 390 } 391 392 // if location selector starts with '#', remove it so we don't see id="#selector" 393 if (captionLocation.charAt(0) == '#') { 394 captionLocation = captionLocation.substring(1, captionLocation.length); 395 } 396 captionHTML = $('#' + captionLocation).html(); //get HTML from the matching HTML entity 397 this.$caption 398 .attr('id', captionLocation) // Add ID caption TODO why is the id being set? 399 .html(captionHTML); // Change HTML in Caption 400 //Animations for Caption entrances 401 switch (this.options.captionAnimation) { 402 case 'none': 403 this.$caption.show(); 404 break; 405 case 'fade': 406 this.$caption.fadeIn(this.options.captionAnimationSpeed); 407 break; 408 case 'slideOpen': 409 this.$caption.slideDown(this.options.captionAnimationSpeed); 410 break; 411 } 412 } else { 413 //Animations for Caption exits 414 switch (this.options.captionAnimation) { 415 case 'none': 416 this.$caption.hide(); 417 break; 418 case 'fade': 419 this.$caption.fadeOut(this.options.captionAnimationSpeed); 420 break; 421 case 'slideOpen':
422 this.$caption.slideUp(this.options.captionAnimationSpeed); 423 break; 424 } 425 } 426 }, 427 428 setupDirectionalNav: function () { 429 var self = this, 430 $directionalNav = $(this.directionalNavHTML); 431 432 $directionalNav.find('.right').html(this.options.directionalNavRightText); 433 $directionalNav.find('.left').html(this.options.directionalNavLeftText); 434 435 this.$wrapper.append($directionalNav); 436 437 this.$wrapper.find('.left').click(function () { 438 self.stopClock(); 439 if (self.options.resetTimerOnClick) { 440 self.rotateTimer(true); 441 self.startClock(); 442 } 443 self.$element.trigger('orbit.prev'); 444 }); 445 446 this.$wrapper.find('.right').click(function () { 447 self.stopClock(); 448 if (self.options.resetTimerOnClick) { 449 self.rotateTimer(true); 450 self.startClock(); 451 } 452 self.$element.trigger('orbit.next'); 453 }); 454 }, 455 456 setupBulletNav: function () { 457 this.$bullets = $(this.bulletHTML); 458 this.$wrapper.append(this.$bullets); 459 this.$slides.each(this.addBullet); 460 this.$element.addClass('with-bullets'); 461 if (this.options.centerBullets) this.$bullets.css('margin-left', -this.$bullets.outerWidth() / 2); 462 if (this.options.bulletThumbsHideOnSmall) this.$bullets.addClass('hide-for-small'); 463 }, 464 465 addBullet: function (index, slide) { 466 var position = index + 1, 467 $li = $('<li>' + (position) + '</li>'), 468 thumbName, 469 self = this; 470 471 if (this.options.bulletThumbs) { 472 thumbName = $(slide).attr('data-thumb'); 473 if (thumbName) { 474 $li 475 .addClass('has-thumb') 476 .css({background: "url(" + this.options.bulletThumbLocation + thumb
476Name + ") no-repeat"});; 477 } 478 } 479 this.$bullets.append($li); 480 $li.data('index', index); 481 $li.click(function () { 482 self.stopClock(); 483 if (self.options.resetTimerOnClick) { 484 self.rotateTimer(true); 485 self.startClock(); 486 } 487 self.$element.trigger('orbit.goto', [$li.data('index')]) 488 }); 489 }, 490 491 setActiveBullet: function () { 492 if(!this.options.bullets) { return false; } else { 493 this.$bullets.find('li') 494 .removeClass('active') 495 .eq(this.activeSlide) 496 .addClass('active'); 497 } 498 }, 499 500 resetAndUnlock: function () { 501 this.$slides 502 .eq(this.prevActiveSlide) 503 .css({"z-index" : 1}); 504 this.unlock(); 505 this.options.afterSlideChange.call(this, this.$slides.eq(this.prevActiveSlide), this.$slides.eq(this.activeSlide)); 506 }, 507 508 shift: function (direction) { 509 var slideDirection = direction; 510 511 //remember previous activeSlide 512 this.prevActiveSlide = this.activeSlide; 513 514 //exit function if bullet clicked is same as the current image 515 if (this.prevActiveSlide == slideDirection) { return false; } 516 517 if (this.$slides.length == "1") { return false; } 518 if (!this.locked) { 519 this.lock(); 520 //deduce the proper activeImage 521 if (direction == "next") { 522 this.activeSlide++; 523 if (this.activeSlide == this.numberSlides) { 524 this.activeSlide = 0; 525 } 526 } else if (direction == "prev") { 527 this.activeSlide-- 528 if (this.activeSlide < 0) { 529 this.activeSlide = this.numberSlides - 1; 530 } 531 } else { 532 this.activeSlide = direction; 533 if (this.prevActiveSlide < this.activeSlide) { 534 slideDirection = "next"; 535 } else if (this.prevActiveSlide > this.activeSlide) { 536 slideDirection = "prev" 537 } 538 } 539 540 //set to correct bullet 541 this.setActiveBullet(); 542 this.notifySlideChange(); 543 544 //set previous slide z-index to one below what new activeSlide will be 545 this.$slides 546 .eq(this.prevActiveSlide) 547 .css({"z-index" : 2}); 548 549 //fade 550 if (this.options.animation == "fade") { 551 this.$slides 552 .eq(this.activeSlide) 553 .css({"opacity" : 0, "z-index" : 3}) 554 .animate({"opacity" : 1}, this.options.animationSpeed, this.resetAndUnlock); 555 this.$slides 556 .eq(this.prevActiveSlide) 557 .animate({"opacity":0}, this.options.animationSpeed); 558 } 559 560 //horizontal-slide 561 if (this.options.animation == "horizontal-slide") { 562 if (slideDirection == "next") { 563 this.$slides 564 .eq(this.activeSlide) 565 .css({"left": this.orbitWidth, "z-index" : 3}) 566 .css("opacity", 1) 567 .animate({"left" : 0}, this.options.animationSpeed, this.resetAndUnlock); 568 } 569 if (slideDirection == "prev") { 570 this.$slides 571 .eq(this.activeSlide) 572 .css({"left": -this.orbitWidth, "z-index" : 3}) 573 .css("opacity", 1) 574 .animate({"left" : 0}, this.options.animationSpeed, this.resetAndUnlock); 575 } 576 this.$slides 577 .eq(this.prevActiveSlide) 578 .css("opacity", 0); 579 } 580 581 //vertical-slide 582 if (this.options.animation == "vertical-slide") { 583 if (slideDirection == "prev") { 584 this.$slides 585 .eq(this.activeSlide) 586 .css({"top": this.orbitHeight, "z-index" : 3}) 587 .css("opacity", 1) 588 .animate({"top" : 0}, this.options.animationSpeed, this.resetAndUnlock); 589 this.$slides 590 .eq(this.prevActiveSlide) 591 .css("opacity", 0); 592 } 593 if (slideDirection == "next") { 594 this.$slides 595 .eq(this.activeSlide) 596 .css({"top": -this.orbitHeight, "z-index" : 3}) 597 .css("opacity", 1) 598 .animate({"top" : 0}, this.options.animationSpeed, this.resetAndUnlock); 599 } 600 this.$slides 601 .eq(this.prevActiveSlide) 602 .css("opacity", 0); 603 } 604 605 //horizontal-push 606 if (this.options.animation == "horizontal-push") { 607 if (slideDirection == "next") { 608 this.$slides 609 .eq(this.activeSlide) 610 .css({"left": this.orbitWidth, "z-index" : 3}) 611 .animate({"left" : 0, "opacity" : 1}, this.options.animationSpeed, this.resetAndUnlock); 612 this.$slides 613 .eq(this.prevActiveSlide) 614 .animate({"left" : -this.orbitWidth}, this.options.animationSpeed, "", function(){ 615 $(this).css({"opacity" : 0}); 616 }); 617 } 618 if (slideDirection == "prev") { 619 this.$slides 620 .eq(this.activeSlide) 621 .css({"left": -this.orbitWidth, "z-index" : 3}) 622 .animate({"left" : 0, "opacity" : 1}, this.options.animationSpeed, this.resetAndUnlock); 623 this.$slides 624 .eq(this.prevActiveSlide) 625 .animate({"left" : this.orbitWidth}, this.options.animationSpeed, "", function(){ 626 $(this).css({"opacity" : 0}); 627 }); 628 } 629 } 630 631 //vertical-push 632 if (this.options.animation == "vertical-push") { 633 if (slideDirection == "next") { 634 this.$slides 635 .eq(this.activeSlide) 636 .css({top: -this.orbitHeight, "z-index" : 3}) 637 .css("opacity", 1) 638 .animate({top : 0, "opacity":1}, this.options.animationSpeed, this.resetAndUnlock); 639 this.$slides 640 .eq(this.prevActiveSlide) 641 .css("opacity", 0) 642 .animate({top : this.orbitHeight}, this.options.animationSpeed, ""); 643 } 644 if (slideDirection == "prev") { 645 this.$slides 646 .eq(this.activeSlide) 647 .css({top: this.orbitHeight, "z-index" : 3}) 648 .css("opacity", 1) 649 .animate({top : 0}, this.options.animationSpeed, this.resetAndUnlock); 650 this.$slides 651 .eq(this.prevActiveSlide) 652 .css("opacity", 0) 653 .animate({top : -this.orbitHeight}, this.options.animationSpeed); 654 } 655 } 656 657 this.setCaption(); 658 } 659 660 // if on last slide and singleCycle is true, don't loop through slides again 661 // .length is zero based so must minus 1 to match activeSlide index 662 if (this.activeSlide === this.$slides.length-1 && this.options.singleCycle) { 663 this.stopClock(); 664 } 665 } 666 }; 667 668 $.fn.orbit = function (options) { 669 return this.each(function () { 670 var orbit = $.extend({}, ORBIT); 671 orbit.init(this, options); 672 });
673 }; 674 675})(jQuery); 676 677/*! 678 * jQuery imageready Plugin 679 * http://www.zurb.com/playground/ 680 * 681 * Copyright 2011, ZURB 682 * Released under the MIT License 683 */ 684(function ($) { 685 686 var options = {}; 687 688 $.event.special.imageready = { 689 690 setup: function (data, namespaces, eventHandle) { 691 options = data || options; 692 }, 693 694 add: function (handleObj) { 695 var $this = $(this), 696 src; 697 698 if ( this.nodeType === 1 && this.tagName.toLowerCase() === 'img' && this.src !== '' ) { 699 if (options.forceLoad) { 700 src = $this.attr('src'); 701 $this.attr('src', ''); 702 bindToLoad(this, handleObj.handler); 703 $this.attr('src', src); 704 } else if ( this.complete || this.readyState === 4 ) { 705 handleObj.handler.apply(this, arguments); 706 } else { 707 bindToLoad(this, handleObj.handler); 708 } 709 } 710 }, 711 712 teardown: function (namespaces) { 713 $(this).unbind('.imageready'); 714 } 715 }; 716 717 function bindToLoad(element, callback) { 718 var $this = $(element); 719 720 $this.bind('load.imageready', function () { 721 callback.apply(element, arguments); 722 $this.unbind('load.imageready'); 723 }); 724 } 725 726}(jQuery)); 727 728/* 729 730Holder - 1.3 - client side image placeholders 731(c) 2012 Ivan Malopinsky / http://imsky.co 732 733Provided under the Apache 2.0 License: http://www.apache.org/licenses/LICENSE-2.0 734Commercial use requires attribution. 735 736*/ 737 738var Holder = Holder || {}; 739(function (app, win) { 740 741var preempted = false, 742fallback = false, 743canvas = document.createElement('canvas'); 744 745//http://javascript.nwbox.com/ContentLoaded by Diego Perini with modifications 746function contentLoaded(n,t){var l="complete",s="readystatechange",u=!1,h=u,c=!0,i=n.document,a=i.documentElement,e=i.addEventListener?"addEventListener":"attachEvent",v=i.addEventListener?"removeEventListener":"detachEvent",f=i.addEventListener?"":"on",r=function(e){(e.type!=s||i.readyState==l)&&((e.type=="load"?n:i)[v](f+e.type,r,u),!h&&(h=!0)&&t.call(n,null))},o=function(){try{a.doScroll("left")}catch(n){setTimeout(o,50);return}r("poll")};if(i.readyState==l)t.call(n,"lazy");else{if(i.createEventObject&&a.doScroll){try{c=!n.frameElement}catch(y){}c&&o()}i[e](f+"DOMContentLoaded",r,u),i[e](f+s,r,u),n[e](f+"load",r,u)}}; 747 748//https://gist.github.com/991057 by Jed Schmidt with modifications 749function selector(a){ 750 a=a.match(/^(\W)?(.*)/);var b=document["getElement"+(a[1]?a[1]=="#"?"ById":"sByClassName":"sByTagName")](a[2]); 751 var ret=[]; b!=null&&(b.length?ret=b:b.length==0?ret=b:ret=[b]); return ret; 752} 753 754//shallow object property extend 755function extend(a,b){var c={};for(var d in a)c[d]=a[d];for(var e in b)c[e]=b[e];return c} 756 757function draw(ctx, dimensions, template) { 758 var dimension_arr = [dimensions.height, dimensions.width].sort(); 759 var maxFactor = Math.round(dimension_arr[1] / 16), 760 minFactor = Math.round(dimension_arr[0] / 16); 761 var text_height = Math.max(template.size, maxFactor); 762 canvas.width = dimensions.width; 763 canvas.height = dimensions.height; 764 ctx.textAlign = "center"; 765 ctx.textBaseline = "middle"; 766 ctx.fillStyle = template.background; 767 ctx.fillRect(0, 0, dimensions.width, dimensions.height); 768 ctx.fillStyle = template.foreground; 769 ctx.font = "bold " + text_height + "px sans-serif"; 770 var text = template.text ? template.text : (dimensions.width + "x" + dimensions.height); 771 if (Math.round(ctx.measureText(text).width) / dimensions.width > 1) { 772 text_height = Math.max(minFactor, template.size); 773 } 774 ctx.font = "bold " + text_height + "px sans-serif"; 775 ctx.fillText(text, (dimensions.width / 2), (dimensions.height / 2), dimensions.width); 776 return canvas.toDataURL("image/png"); 777} 778 779if (!canvas.getContext) { 780 fallback = true; 781} else { 782 if (canvas.toDataURL("image/png").indexOf("data:image/png") < 0) { 783 //Android doesn't support data URI 784 fallback = true; 785 } else { 786 var ctx = canvas.getContext("2d"); 787 } 788} 789 790var settings = { 791 domain: "holder.js", 792 images: "img", 793 themes: { 794 "gray": { 795 background: "#eee", 796 foreground: "#aaa", 797 size: 12 798 }, 799 "social": { 800 background: "#3a5a97", 801 foreground: "#fff", 802 size: 12 803 }, 804 "industrial": { 805 background: "#434A52", 806 foreground: "#C2F200", 807 size: 12 808 } 809 } 810}; 811 812 813 814app.flags = { 815 dimensions: { 816 regex: /([0-9]+)x([0-9]+)/, 817 output: function(val){ 818 var exec = this.regex.exec(val); 819 return { 820 width: +exec[1], 821 height: +exec[2] 822 } 823 } 824 }, 825 colors: { 826 regex: /#([0-9a-f]{3,})\:#([0-9a-f]{3,})/i, 827 output: function(val){ 828 var exec = this.regex.exec(val); 829 return { 830 size: settings.themes.gray.size, 831 foreground: "#" + exec[2], 832 background: "#" + exec[1] 833 } 834 } 835 }, 836 text: { 837 regex: /text\:(.*)/, 838 output: function(val){ 839 return this.regex.exec(val)[1]; 840 } 841 } 842} 843 844for(var flag in app.flags){ 845 app.flags[flag].match = function (val){ 846 return val.match(this.regex) 847 } 848} 849 850app.add_theme = function (name, theme) {
851 name != null && theme != null && (settings.themes[name] = theme); 852 return app; 853}; 854 855app.add_image = function (src, el) { 856 var node = selector(el); 857 if (node.length) { 858 for (var i = 0, l = node.length; i < l; i++) { 859 var img = document.createElement("img") 860 img.setAttribute("data-src", src); 861 node[i].appendChild(img); 862 } 863 } 864 return app; 865}; 866 867app.run = function (o) { 868 var options = extend(settings, o), 869 images = selector(options.images), 870 preempted = true; 871 872 for (var l = images.length, i = 0; i < l; i++) { 873 var theme = settings.themes.gray; 874 var src = images[i].getAttribute("data-src") || images[i].getAttribute("src"); 875 if (src && !! ~src.indexOf(options.domain)) { 876 var render = false, 877 dimensions = null, 878 text = null; 879 var flags = src.substr(src.indexOf(options.domain) + options.domain.length + 1).split("/"); 880 for (sl = flags.length, j = 0; j < sl; j++) { 881 if (app.flags.dimensions.match(flags[j])) { 882 render = true; 883 dimensions = app.flags.dimensions.output(flags[j]); 884 } else if (app.flags.colors.match(flags[j])) { 885 theme = app.flags.colors.output(flags[j]); 886 } else if (options.themes[flags[j]]) { 887 //If a theme is specified, it will override custom colors 888 theme = options.themes[flags[j]]; 889 } else if (app.flags.text.match(flags[j])) { 890 text = app.flags.text.output(flags[j]); 891 } 892 } 893 if (render) { 894 images[i].setAttribute("data-src", src); 895 var dimensions_caption = dimensions.width + "x" + dimensions.height; 896 images[i].setAttribute("alt", text ? text : theme.text ? theme.text + " [" + dimensions_caption + "]" : dimensions_caption); 897 898 // Fallback 899 // images[i].style.width = dimensions.width + "px"; 900 // images[i].style.height = dimensions.height + "px"; 901 images[i].style.backgroundColor = theme.background; 902 903 var theme = (text ? extend(theme, { 904 text: text 905 }) : theme); 906 907 if (!fallback) { 908 images[i].setAttribute("src", draw(ctx, dimensions, theme)); 909 } 910 } 911 } 912 } 913 return app; 914}; 915contentLoaded(win, function () { 916 preempted || app.run() 917}) 918 919})(Holder, window);
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.