1sincosJsonp([5],{ 2 3/***/ 0: 4/***/ function(module, exports, __webpack_require__) { 5 6 "use strict"; 7 8 __webpack_require__(217); 9 10 __webpack_require__(212); 11 12 __webpack_require__(219); 13 14 __webpack_require__(204); 15 16 __webpack_require__(206); 17 18 __webpack_require__(205); 19 20 __webpack_require__(215); 21 22 __webpack_require__(218); 23 24 __webpack_require__(211); 25 26 __webpack_require__(253); 27 28 __webpack_require__(199); 29 30/***/ }, 31 32/***/ 199: 33/***/ function(module, exports, __webpack_require__) { 34 35 /* WEBPACK VAR INJECTION */(function($) {"use strict"; 36 37 $(".accordion-trigger").click(function () { 38 var panel = $(this).siblings('.accordion-panel')[0]; 39 if (panel.style.maxHeight) { 40 panel.style.maxHeight = null; 41 } else { 42 panel.style.maxHeight = panel.scrollHeight + "px"; 43 } 44 }); 45 /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(2))) 46 47/***/ }, 48 49/***/ 202: 50/***/ function(module, exports, __webpack_require__) { 51 52 /* WEBPACK VAR INJECTION */(function(jQuery) {'use strict'; 53 54 /* Source: http://osvaldas.info/flexbox-based-responsive-equal-height-blocks-with-javascript-fallback */ 55 56 ;(function ($, window, document, undefined) { 57 'use strict'; 58 59 var s = document.body || document.documentElement, 60 s = s.style; 61 62 var $list = $('.equal-height-columns'), 63 $items = $list.find('.equal-height-column'), 64 getMaxHeight = function getMaxHeight(items) { 65 var maxHeight = 0, 66 itemHeight = 0; 67 68 items.each(function () { 69 itemHeight = parseInt($(this).outerHeight()); 70 if (itemHeight > maxHeight) { 71 maxHeight = itemHeight; 72 } 73 }); 74 75 return maxHeight; 76 }, 77 setHeights = function setHeights() { 78 $items.css('height', 'auto'); 79 80 var perRow = Math.floor($list.width() / $items.width()); 81 82 if (perRow === null || perRow < 2) { 83 return true; 84 } 85 86 var maxHeight = null; 87 var $row = null; 88 89 for (var i = 0, j = $items.length; i < j; i += perRow) { 90 $row = $items.slice(i, i + perRow); 91 maxHeight = getMaxHeight($row); 92 $row.css('height', maxHeight); 93 } 94 }; 95 96 setHeights(); 97 $(window).on('resize', setHeights); 98 $list.find('img').on('load', setHeights); 99 })(jQuery, window, document); 100 /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(2))) 101 102/***/ }, 103 104/***/ 204: 105/***/ function(module, exports, __webpack_require__) { 106 107 /* WEBPACK VAR INJECTION */(function(jQuery) {'use strict'; 108 109 /** 110 * BxSlider v4.1.2 - Fully loaded, responsive content slider 111 * http://bxslider.com 112 * 113 * Copyright 2014, Steven Wanderski - http://stevenwanderski.com - http://bxcreative.com 114 * Written while drinking Belgian ales and listening to jazz 115 * 116 * Released under the MIT license - http://opensource.org/licenses/MIT 117 */ 118 119 ;(function ($) { 120 121 var plugin = {}; 122 123 var defaults = { 124 125 // GENERAL 126 mode: 'horizontal', 127 slideSelector: '', 128 infiniteLoop: true, 129 hideControlOnEnd: false, 130 speed: 500, 131 easing: null, 132 slideMargin: 0, 133 startSlide: 0, 134 randomStart: false, 135 captions: false, 136 ticker: false, 137 tickerHover: false, 138 adaptiveHeight: false, 139 adaptiveHeightSpeed: 500, 140 video: false, 141 useCSS: true, 142 preloadImages: 'visible', 143 responsive: true, 144 slideZIndex: 50, 145 wrapperClass: 'bx-wrapper', 146 147 // TOUCH 148 touchEnabled: true, 149 swipeThreshold: 50, 150 oneToOneTouch: true, 151 preventDefaultSwipeX: true, 152 preventDefaultSwipeY: false, 153 154 // PAGER 155 pager: true, 156 pagerType: 'full', 157 pagerShortSeparator: ' / ', 158 pagerSelector: null, 159 buildPager: null, 160 pagerCustom: null, 161 162 // CONTROLS 163 controls: true, 164 nextText: 'Next', 165 prevText: 'Prev', 166 nextSelector: null, 167 prevSelector: null, 168 autoControls: false, 169 startText: 'Start', 170 stopText: 'Stop', 171 autoControlsCombine: false, 172 autoControlsSelector: null, 173 174 // AUTO 175 auto: false, 176 pause: 4000, 177 autoStart: true, 178 autoDirection: 'next', 179 autoHover: false, 180 autoDelay: 0, 181 autoSlideForOnePage: false, 182 183 // CAROUSEL 184 minSlides: 1, 185 maxSlides: 1, 186 moveSlides: 0, 187 slideWidth: 0, 188 189 // CALLBACKS 190 onSliderLoad: function onSliderLoad() {}, 191 onSlideBefore: function onSlideBefore() {}, 192 onSlideAfter: function onSlideAfter() {}, 193 onSlideNext: function onSlideNext() {}, 194 onSlidePrev: function onSlidePrev() {}, 195 onSliderResize: function onSliderResize() {} 196 }; 197 198 $.fn.bxSlider = function (options) { 199 200 if (this.length == 0) return this; 201 202 // support mutltiple elements 203 if (this.length > 1) { 204 this.each(function () { 205 $(this).bxSlider(options); 206 }); 207 return this; 208 } 209 210 // create a namespace to be used throughout the plugin 211 var slider = {}; 212 // set a reference to our slider element 213 var el = this; 214 plugin.el = this; 215 216 /** 217 * Makes slideshow responsive 218 */ 219 // first get the original window dimens (thanks alot IE) 220 var windowWidth = $(window).width(); 221 var windowHeight = $(window).height(); 222 223 // Strict mode does not allow implicit globals 224 var speed; 225 226 /** 227 * =================================================================================== 228 * = PRIVATE FUNCTIONS 229 * =================================================================================== 230 */ 231 232 /** 233 * Initializes namespace settings to be used throughout plugin 234 */
235 var init = function init() { 236 // merge user-supplied options with the defaults 237 slider.settings = $.extend({}, defaults, options); 238 // parse slideWidth setting 239 slider.settings.slideWidth = parseInt(slider.settings.slideWidth); 240 // store the original children 241 slider.children = el.children(slider.settings.slideSelector); 242 // check if actual number of slides is less than minSlides / maxSlides 243 if (slider.children.length < slider.settings.minSlides) slider.settings.minSlides = slider.children.length; 244 if (slider.children.length < slider.settings.maxSlides) slider.settings.maxSlides = slider.children.length; 245 // if random start, set the startSlide setting to random number 246 if (slider.settings.randomStart) slider.settings.startSlide = Math.floor(Math.random() * slider.children.length); 247 // store active slide information 248 slider.active = { index: slider.settings.startSlide }; 249 // store if the slider is in carousel mode (displaying / moving multiple slides) 250 slider.carousel = slider.settings.minSlides > 1 || slider.settings.maxSlides > 1; 251 // if carousel, force preloadImages = 'all' 252 if (slider.carousel) slider.settings.preloadImages = 'all'; 253 // calculate the min / max width thresholds based on min / max number of slides 254 // used to setup and update carousel slides dimensions 255 slider.minThreshold = slider.settings.minSlides * slider.settings.slideWidth + (slider.settings.minSlides - 1) * slider.settings.slideMargin; 256 slider.maxThreshold = slider.settings.maxSlides * slider.settings.slideWidth + (slider.settings.maxSlides - 1) * slider.settings.slideMargin; 257 // store the current state of the slider (if currently animating, working is true) 258 slider.working = false; 259 // initialize the controls object 260 slider.controls = {}; 261 // initialize an auto interval 262 slider.interval = null; 263 // determine which property to use for transitions 264 slider.animProp = slider.settings.mode == 'vertical' ? 'top' : 'left'; 265 // determine if hardware acceleration can be used 266 slider.usingCSS = slider.settings.useCSS && slider.settings.mode != 'fade' && function () { 267 // create our test div element 268 var div = document.createElement('div'); 269 // css transition properties 270 var props = ['WebkitPerspective', 'MozPerspective', 'OPerspective', 'msPerspective']; 271 // test for each property 272 for (var i in props) { 273 if (div.style[props[i]] !== undefined) { 274 slider.cssPrefix = props[i].replace('Perspective', '').toLowerCase(); 275 slider.animProp = '-' + slider.cssPrefix + '-transform'; 276 return true; 277 } 278 } 279 return false; 280 }(); 281 // if vertical mode always make maxSlides and minSlides equal 282 if (slider.settings.mode == 'vertical') slider.settings.maxSlides = slider.settings.minSlides; 283 // save original style data 284 el.data("origStyle", el.attr("style")); 285 el.children(slider.settings.slideSelector).each(function () { 286 $(this).data("origStyle", $(this).attr("style")); 287 }); 288 // perform all DOM / CSS modifications 289 setup(); 290 }; 291 292 /** 293 * Performs all DOM and CSS modifications 294 */ 295 var setup = function setup() { 296 // wrap el in a wrapper 297 el.wrap('<div class="' + slider.settings.wrapperClass + '"><div class="bx-viewport"></div></div>'); 298 // store a namspace reference to .bx-viewport 299 slider.viewport = el.parent(); 300 // add a loading div to display while images are loading 301 slider.loader = $('<div class="bx-loading" />'); 302 slider.viewport.prepend(slider.loader); 303 // set el to a massive width, to hold any needed slides 304 // also strip any margin and padding from el 305 el.css({ 306 width: slider.settings.mode == 'horizontal' ? slider.children.length * 100 + 215 + '%' : 'auto', 307 position: 'relative' 308 }); 309 // if using CSS, add the easing property 310 if (slider.usingCSS && slider.settings.easing) { 311 el.css('-' + slider.cssPrefix + '-transition-timing-function', slider.settings.easing); 312 // if not using CSS and no easing value was supplied, use the default JS animation easing (swing) 313 } else if (!slider.settings.easing) { 314 slider.settings.easing = 'swing'; 315 } 316 var slidesShowing = getNumberSlidesShowing(); 317 // make modifications to the viewport (.bx-viewport) 318 slider.viewport.css({ 319 width: '100%', 320 overflow: 'hidden', 321 position: 'relative' 322 }); 323 slider.viewport.parent().css({ 324 maxWidth: getViewportMaxWidth() 325 }); 326 // make modification to the wrapper (.bx-wrapper) 327 if (!slider.settings.pager) { 328 slider.viewport.parent().css({ 329 margin: '0 auto 0px' 330 }); 331 } 332 // apply css to all slider children 333 slider.children.css({ 334 'float': slider.settings.mode == 'horizontal' ? 'left' : 'none', 335 listStyle: 'none', 336 position: 'relative' 337 }); 338 // apply the calculated width after the float is applied to prevent scrollbar interference 339 slider.children.css('width', getSlideWidth()); 340 // if slideMargin is supplied, add the css 341 if (slider.settings.mode == 'horizontal' && slider.settings.slideMargin > 0) slider.children.css('marginRight', slider.settings.slideMargin); 342 if (slider.settings.mode == 'vertical' && slider.settings.slideMargin > 0) slider.children.css('marginBottom', slider.settings.slideMargin); 343 // if "fade" mode, add positioning and z-index CSS 344 if (slider.settings.mode == 'fade') { 345 slider.children.css({ 346 position: 'absolute', 347 zIndex: 0, 348 display: 'none' 349 }); 350 // prepare the z-index on the showing element 351 slider.children.eq(slider.settings.startSlide).css({ zIndex: slider.settings.slideZIndex, display: 'block' }); 352 } 353 // create an element to contain all slider controls (pager, start / stop, etc) 354 slider.controls.el = $('<div class="bx-controls" />'); 355 // if captions are requested, add them
356 if (slider.settings.captions) appendCaptions(); 357 // check if startSlide is last slide 358 slider.active.last = slider.settings.startSlide == getPagerQty() - 1; 359 // if video is true, set up the fitVids plugin 360 if (slider.settings.video) el.fitVids(); 361 // set the default preload selector (visible) 362 var preloadSelector = slider.children.eq(slider.settings.startSlide); 363 if (slider.settings.preloadImages == "all") preloadSelector = slider.children; 364 // only check for control addition if not in "ticker" mode 365 if (!slider.settings.ticker) { 366 // if pager is requested, add it 367 if (slider.settings.pager) appendPager(); 368 // if controls are requested, add them 369 if (slider.settings.controls) appendControls(); 370 // if auto is true, and auto controls are requested, add them 371 if (slider.settings.auto && slider.settings.autoControls) appendControlsAuto(); 372 // if any control option is requested, add the controls wrapper 373 if (slider.settings.controls || slider.settings.autoControls || slider.settings.pager) slider.viewport.after(slider.controls.el); 374 // if ticker mode, do not allow a pager 375 } else { 376 slider.settings.pager = false; 377 } 378 // preload all images, then perform final DOM / CSS modifications that depend on images being loaded 379 loadElements(preloadSelector, start); 380 }; 381 382 var loadElements = function loadElements(selector, callback) { 383 var total = selector.find('img, iframe').length; 384 if (total == 0) { 385 callback(); 386 return; 387 } 388 var count = 0; 389 selector.find('img, iframe').each(function () { 390 $(this).one('load', function () { 391 if (++count == total) callback(); 392 }).each(function () { 393 if (this.complete) $(this).load(); 394 }); 395 }); 396 }; 397 398 /** 399 * Start the slider 400 */ 401 var start = function start() { 402 // if infinite loop, prepare additional slides 403 if (slider.settings.infiniteLoop && slider.settings.mode != 'fade' && !slider.settings.ticker) { 404 var slice = slider.settings.mode == 'vertical' ? slider.settings.minSlides : slider.settings.maxSlides; 405 var sliceAppend = slider.children.slice(0, slice).clone().addClass('bx-clone'); 406 var slicePrepend = slider.children.slice(-slice).clone().addClass('bx-clone'); 407 el.append(sliceAppend).prepend(slicePrepend); 408 } 409 // remove the loading DOM element 410 slider.loader.remove(); 411 // set the left / top position of "el" 412 setSlidePosition(); 413 // if "vertical" mode, always use adaptiveHeight to prevent odd behavior 414 if (slider.settings.mode == 'vertical') slider.settings.adaptiveHeight = true; 415 // set the viewport height 416 slider.viewport.height(getViewportHeight()); 417 // make sure everything is positioned just right (same as a window resize) 418 el.redrawSlider(); 419 // onSliderLoad callback 420 slider.settings.onSliderLoad(slider.active.index); 421 // slider has been fully initialized 422 slider.initialized = true; 423 // bind the resize call to the window 424 if (slider.settings.responsive) $(window).bind('resize', resizeWindow); 425 // if auto is true and has more than 1 page, start the show 426 if (slider.settings.auto && slider.settings.autoStart && (getPagerQty() > 1 || slider.settings.autoSlideForOnePage)) initAuto(); 427 // if ticker is true, start the ticker 428 if (slider.settings.ticker) initTicker(); 429 // if pager is requested, make the appropriate pager link active 430 if (slider.settings.pager) updatePagerActive(slider.settings.startSlide); 431 // check for any updates to the controls (like hideControlOnEnd updates) 432 if (slider.settings.controls) updateDirectionControls(); 433 // if touchEnabled is true, setup the touch events 434 if (slider.settings.touchEnabled && !slider.settings.ticker) initTouch(); 435 }; 436 437 /** 438 * Returns the calculated height of the viewport, used to determine either adaptiveHeight or the maxHeight value 439 */ 440 var getViewportHeight = function getViewportHeight() { 441 var height = 0; 442 // first determine which children (slides) should be used in our height calculation 443 var children = $(); 444 // if mode is not "vertical" and adaptiveHeight is false, include all children 445 if (slider.settings.mode != 'vertical' && !slider.settings.adaptiveHeight) { 446 children = slider.children; 447 } else { 448 // if not carousel, return the single active child 449 if (!slider.carousel) { 450 children = slider.children.eq(slider.active.index); 451 // if carousel, return a slice of children 452 } else { 453 // get the individual slide index 454 var currentIndex = slider.settings.moveSlides == 1 ? slider.active.index : slider.active.index * getMoveBy(); 455 // add the current slide to the children 456 children = slider.children.eq(currentIndex); 457 // cycle through the remaining "showing" slides 458 for (var i = 1; i <= slider.settings.maxSlides - 1; i++) { 459 // if looped back to the start 460 if (currentIndex + i >= slider.children.length) { 461 children = children.add(slider.children.eq(i - 1)); 462 } else { 463 children = children.add(slider.children.eq(currentIndex + i
463)); 464 } 465 } 466 } 467 } 468 // if "vertical" mode, calculate the sum of the heights of the children 469 if (slider.settings.mode == 'vertical') { 470 children.each(function (index) { 471 height += $(this).outerHeight(); 472 }); 473 // add user-supplied margins 474 if (slider.settings.slideMargin > 0) { 475 height += slider.settings.slideMargin * (slider.settings.minSlides - 1); 476 } 477 // if not "vertical" mode, calculate the max height of the children 478 } else { 479 height = Math.max.apply(Math, children.map(function () { 480 return $(this).outerHeight(false); 481 }).get()); 482 } 483 484 if (slider.viewport.css('box-sizing') == 'border-box') { 485 height += parseFloat(slider.viewport.css('padding-top')) + parseFloat(slider.viewport.css('padding-bottom')) + parseFloat(slider.viewport.css('border-top-width')) + parseFloat(slider.viewport.css('border-bottom-width')); 486 } else if (slider.viewport.css('box-sizing') == 'padding-box') { 487 height += parseFloat(slider.viewport.css('padding-top')) + parseFloat(slider.viewport.css('padding-bottom')); 488 } 489 490 return height; 491 }; 492 493 /** 494 * Returns the calculated width to be used for the outer wrapper / viewport 495 */ 496 var getViewportMaxWidth = function getViewportMaxWidth() { 497 var width = '100%'; 498 if (slider.settings.slideWidth > 0) { 499 if (slider.settings.mode == 'horizontal') { 500 width = slider.settings.maxSlides * slider.settings.slideWidth + (slider.settings.maxSlides - 1) * slider.settings.slideMargin; 501 } else { 502 width = slider.settings.slideWidth; 503 } 504 } 505 return width; 506 }; 507 508 /** 509 * Returns the calculated width to be applied to each slide 510 */ 511 var getSlideWidth = function getSlideWidth() { 512 // start with any user-supplied slide width 513 var newElWidth = slider.settings.slideWidth; 514 // get the current viewport width 515 var wrapWidth = slider.viewport.width(); 516 // if slide width was not supplied, or is larger than the viewport use the viewport width 517 if (slider.settings.slideWidth == 0 || slider.settings.slideWidth > wrapWidth && !slider.carousel || slider.settings.mode == 'vertical') { 518 newElWidth = wrapWidth; 519 // if carousel, use the thresholds to determine the width 520 } else if (slider.settings.maxSlides > 1 && slider.settings.mode == 'horizontal') { 521 if (wrapWidth > slider.maxThreshold) { 522 // newElWidth = (wrapWidth - (slider.settings.slideMargin * (slider.settings.maxSlides - 1))) / slider.settings.maxSlides; 523 } else if (wrapWidth < slider.minThreshold) { 524 newElWidth = (wrapWidth - slider.settings.slideMargin * (slider.settings.minSlides - 1)) / slider.settings.minSlides; 525 } 526 } 527 return newElWidth; 528 }; 529 530 /** 531 * Returns the number of slides currently visible in the viewport (includes partially visible slides) 532 */ 533 var getNumberSlidesShowing = function getNumberSlidesShowing() { 534 var slidesShowing = 1; 535 if (slider.settings.mode == 'horizontal' && slider.settings.slideWidth > 0) { 536 // if viewport is smaller than minThreshold, return minSlides 537 if (slider.viewport.width() < slider.minThreshold) { 538 slidesShowing = slider.settings.minSlides; 539 // if viewport is larger than minThreshold, return maxSlides 540 } else if (slider.viewport.width() > slider.maxThreshold) { 541 slidesShowing = slider.settings.maxSlides; 542 // if viewport is between min / max thresholds, divide viewport width by first child width 543 } else { 544 var childWidth = slider.children.first().width() + slider.settings.slideMargin; 545 slidesShowing = Math.floor((slider.viewport.width() + slider.settings.slideMargin) / childWidth); 546 } 547 // if "vertical" mode, slides showing will always be minSlides 548 } else if (slider.settings.mode == 'vertical') { 549 slidesShowing = slider.settings.minSlides; 550 } 551 return slidesShowing; 552 }; 553 554 /** 555 * Returns the number of pages (one full viewport of slides is one "page") 556 */ 557 var getPagerQty = function getPagerQty() { 558 var pagerQty = 0; 559 // if moveSlides is specified by the user 560 if (slider.settings.moveSlides > 0) { 561 if (slider.settings.infiniteLoop) { 562 pagerQty = Math.ceil(slider.children.length / getMoveBy()); 563 } else { 564 // use a while loop to determine pages 565 var breakPoint = 0; 566 var counter = 0; 567 // when breakpoint goes above children length, counter is the number of pages 568 while (breakPoint < slider.children.length) { 569 ++pagerQty; 570 breakPoint = counter + getNumberSlidesShowing(); 571 counter += slider.settings.moveSlides <= getNumberSlidesShowing() ? slider.settings.moveSlides : getNumberSlidesShowing(); 572 } 573 }
574 // if moveSlides is 0 (auto) divide children length by sides showing, then round up 575 } else { 576 pagerQty = Math.ceil(slider.children.length / getNumberSlidesShowing()); 577 } 578 return pagerQty; 579 }; 580 581 /** 582 * Returns the number of indivual slides by which to shift the slider 583 */ 584 var getMoveBy = function getMoveBy() { 585 // if moveSlides was set by the user and moveSlides is less than number of slides showing 586 if (slider.settings.moveSlides > 0 && slider.settings.moveSlides <= getNumberSlidesShowing()) { 587 return slider.settings.moveSlides; 588 } 589 // if moveSlides is 0 (auto) 590 return getNumberSlidesShowing(); 591 }; 592 593 /** 594 * Sets the slider's (el) left or top position 595 */ 596 var setSlidePosition = function setSlidePosition() { 597 // if last slide, not infinite loop, and number of children is larger than specified maxSlides 598 if (slider.children.length > slider.settings.maxSlides && slider.active.last && !slider.settings.infiniteLoop) { 599 if (slider.settings.mode == 'horizontal') { 600 // get the last child's position 601 var lastChild = slider.children.last(); 602 var position = lastChild.position(); 603 // set the left position 604 setPositionProperty(-(position.left - (slider.viewport.width() - lastChild.outerWidth())), 'reset', 0); 605 } else if (slider.settings.mode == 'vertical') { 606 // get the last showing index's position 607 var lastShowingIndex = slider.children.length - slider.settings.minSlides; 608 var position = slider.children.eq(lastShowingIndex).position(); 609 // set the top position 610 setPositionProperty(-position.top, 'reset', 0); 611 } 612 // if not last slide 613 } else { 614 // get the position of the first showing slide 615 var position = slider.children.eq(slider.active.index * getMoveBy()).position(); 616 // check for last slide 617 if (slider.active.index == getPagerQty() - 1) slider.active.last = true; 618 // set the repective position 619 if (position != undefined) { 620 if (slider.settings.mode == 'horizontal') setPositionProperty(-position.left, 'reset', 0);else if (slider.settings.mode == 'vertical') setPositionProperty(-position.top, 'reset', 0); 621 } 622 } 623 }; 624 625 /** 626 * Sets the el's animating property position (which in turn will sometimes animate el). 627 * If using CSS, sets the transform property. If not using CSS, sets the top / left property. 628 * 629 * @param value (int) 630 * - the animating property's value 631 * 632 * @param type (string) 'slider', 'reset', 'ticker' 633 * - the type of instance for which the function is being 634 * 635 * @param duration (int) 636 * - the amount of time (in ms) the transition should occupy 637 * 638 * @param params (array) optional 639 * - an optional parameter containing any variables that need to be passed in 640 */ 641 var setPositionProperty = function setPositionProperty(value, type, duration, params) { 642 // use CSS transform 643 if (slider.usingCSS) { 644 // determine the translate3d value 645 var propValue = slider.settings.mode == 'vertical' ? 'translate3d(0, ' + value + 'px, 0)' : 'translate3d(' + value + 'px, 0, 0)'; 646 // add the CSS transition-duration 647 el.css('-' + slider.cssPrefix + '-transition-duration', duration / 1000 + 's'); 648 if (type == 'slide') { 649 // set the property value 650 el.css(slider.animProp, propValue); 651 // bind a callback method - executes when CSS transition completes 652 el.bind('transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd', function () { 653 // unbind the callback 654 el.unbind('transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd'); 655 updateAfterSlideTransition(); 656 }); 657 } else if (type == 'reset') { 658 el.css(slider.animProp, propValue); 659 } else if (type == 'ticker') { 660 // make the transition use 'linear' 661 el.css('-' + slider.cssPrefix + '-transition-timing-function', 'linear'); 662 el.css(slider.animProp, propValue); 663 // bind a callback method - executes when CSS transition completes 664 el.bind('transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd', function () { 665 // unbind the callback 666 el.unbind('transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd'); 667 // reset the position 668 setPositionProperty(params['resetValue'], 'reset', 0); 669 // start the loop again 670 tickerLoop(); 671 }); 672 } 673 // use JS animate 674 } else { 675 var animateObj = {}; 676 animateObj[slider.animProp] = value; 677 if (type == 'slide') { 678 el.animate(animateObj, duration, slider.settings.easing, function () { 679 updateAfterSlideTransition(); 680 }); 681 } else if (type == 'reset') { 682 el.css(slider.animProp, value); 683 } else if (type == 'ticker') { 684 el.animate(animateObj, speed, 'linear', function () { 685 setPositionProperty(params['resetValue'], 'reset', 0); 686 // run the recursive loop after animation 687 tickerLoop(); 688 }); 689 } 690 } 691 }; 692 693 /** 694 * Populates the pager with proper amount of pages 695 */ 696 var populatePager = function populatePager() { 697 var pagerHtml = ''; 698 var pagerQty = getPagerQty(); 699 // loop through each pager item 700 for (var i = 0; i < pagerQty; i++) { 701 var linkContent = ''; 702 // if a buildPager function is supplied, use it to get pager link value, else use index + 1 703 if (slider.settings.buildPager && $.isFunction(slider.settings.buildPager)) { 704 linkContent = slider.settings.buildPager(i); 705 slider.pagerEl.addClass('bx-custom-pager'); 706 } else { 707 linkContent = i + 1; 708 slider.pagerEl.addClass('bx-default-pager'); 709 } 710 // var linkContent = slider.settings.buildPager && $.isFunction(slider.settings.buildPager) ? slider.settings.buildPager(i) : i + 1; 711 // add the markup to the string 712 pagerHtml += '<div class="bx-pager-item">
712<a href="" data-slide-index="' + i + '" class="bx-pager-link">' + linkContent + '</a></div>'; 713 } 714 // populate the pager element with pager links 715 slider.pagerEl.html(pagerHtml); 716 }; 717 718 /** 719 * Appends the pager to the controls element 720 */ 721 var appendPager = function appendPager() { 722 if (!slider.settings.pagerCustom) { 723 // create the pager DOM element 724 slider.pagerEl = $('<div class="bx-pager" />'); 725 // if a pager selector was supplied, populate it with the pager 726 if (slider.settings.pagerSelector) { 727 $(slider.settings.pagerSelector).html(slider.pagerEl); 728 // if no pager selector was supplied, add it after the wrapper 729 } else { 730 slider.controls.el.addClass('bx-has-pager').append(slider.pagerEl); 731 } 732 // populate the pager 733 populatePager(); 734 } else { 735 slider.pagerEl = $(slider.settings.pagerCustom); 736 } 737 // assign the pager click binding 738 slider.pagerEl.on('click', 'a', clickPagerBind); 739 }; 740 741 /** 742 * Appends prev / next controls to the controls element 743 */ 744 var appendControls = function appendControls() { 745 slider.controls.next = $('<a class="bx-next" href="">' + slider.settings.nextText + '</a>'); 746 slider.controls.prev = $('<a class="bx-prev" href="">' + slider.settings.prevText + '</a>'); 747 // bind click actions to the controls 748 slider.controls.next.bind('click', clickNextBind); 749 slider.controls.prev.bind('click', clickPrevBind); 750 // if nextSlector was supplied, populate it 751 if (slider.settings.nextSelector) { 752 $(slider.settings.nextSelector).append(slider.controls.next); 753 } 754 // if prevSlector was supplied, populate it 755 if (slider.settings.prevSelector) { 756 $(slider.settings.prevSelector).append(slider.controls.prev); 757 } 758 // if no custom selectors were supplied 759 if (!slider.settings.nextSelector && !slider.settings.prevSelector) { 760 // add the controls to the DOM 761 slider.controls.directionEl = $('<div class="bx-controls-direction" />'); 762 // add the control elements to the directionEl 763 slider.controls.directionEl.append(slider.controls.prev).append(slider.controls.next); 764 // slider.viewport.append(slider.controls.directionEl); 765 slider.controls.el.addClass('bx-has-controls-direction').append(slider.controls.directionEl); 766 } 767 }; 768 769 /** 770 * Appends start / stop auto controls to the controls element 771 */ 772 var appendControlsAuto = function appendControlsAuto() { 773 slider.controls.start = $('<div class="bx-controls-auto-item"><a class="bx-start" href="">' + slider.settings.startText + '</a></div>'); 774 slider.controls.stop = $('<div class="bx-controls-auto-item"><a class="bx-stop" href="">' + slider.settings.stopText + '</a></div>'); 775 // add the controls to the DOM 776 slider.controls.autoEl = $('<div class="bx-controls-auto" />'); 777 // bind click actions to the controls 778 slider.controls.autoEl.on('click', '.bx-start', clickStartBind); 779 slider.controls.autoEl.on('click', '.bx-stop', clickStopBind); 780 // if autoControlsCombine, insert only the "start" control 781 if (slider.settings.autoControlsCombine) { 782 slider.controls.autoEl.append(slider.controls.start); 783 // if autoControlsCombine is false, insert both controls 784 } else { 785 slider.controls.autoEl.append(slider.controls.start).append(slider.controls.stop); 786 } 787 // if auto controls selector was supplied, populate it with the controls 788 if (slider.settings.autoControlsSelector) { 789 $(slider.settings.autoControlsSelector).html(slider.controls.autoEl); 790 // if auto controls selector was not supplied, add it after the wrapper 791 } else { 792 slider.controls.el.addClass('bx-has-controls-auto').append(slider.controls.autoEl); 793 } 794 // update the auto controls
795 updateAutoControls(slider.settings.autoStart ? 'stop' : 'start'); 796 }; 797 798 /** 799 * Appends image captions to the DOM 800 */ 801 var appendCaptions = function appendCaptions() { 802 // cycle through each child 803 slider.children.each(function (index) { 804 // get the image title attribute 805 var title = $(this).find('img:first').attr('title'); 806 // append the caption 807 if (title != undefined && ('' + title).length) { 808 $(this).append('<div class="bx-caption"><span>' + title + '</span></div>'); 809 } 810 }); 811 }; 812 813 /** 814 * Click next binding 815 * 816 * @param e (event) 817 * - DOM event object 818 */ 819 var clickNextBind = function clickNextBind(e) { 820 // if auto show is running, stop it 821 if (slider.settings.auto) el.stopAuto(); 822 el.goToNextSlide(); 823 e.preventDefault(); 824 }; 825 826 /** 827 * Click prev binding 828 * 829 * @param e (event) 830 * - DOM event object 831 */ 832 var clickPrevBind = function clickPrevBind(e) { 833 // if auto show is running, stop it 834 if (slider.settings.auto) el.stopAuto(); 835 el.goToPrevSlide(); 836 e.preventDefault(); 837 }; 838 839 /** 840 * Click start binding 841 * 842 * @param e (event) 843 * - DOM event object 844 */ 845 var clickStartBind = function clickStartBind(e) { 846 el.startAuto(); 847 e.preventDefault(); 848 }; 849 850 /** 851 * Click stop binding 852 * 853 * @param e (event) 854 * - DOM event object 855 */ 856 var clickStopBind = function clickStopBind(e) { 857 el.stopAuto(); 858 e.preventDefault(); 859 }; 860 861 /** 862 * Click pager binding 863 * 864 * @param e (event) 865 * - DOM event object 866 */ 867 var clickPagerBind = function clickPagerBind(e) { 868 // if auto show is running, stop it 869 if (slider.settings.auto) el.stopAuto(); 870 var pagerLink = $(e.currentTarget); 871 if (pagerLink.attr('data-slide-index') !== undefined) { 872 var pagerIndex = parseInt(pagerLink.attr('data-slide-index')); 873 // if clicked pager link is not active, continue with the goToSlide call 874 if (pagerIndex != slider.active.index) el.goToSlide(pagerIndex); 875 e.preventDefault(); 876 } 877 }; 878 879 /** 880 * Updates the pager links with an active class 881 * 882 * @param slideIndex (int) 883 * - index of slide to make active 884 */ 885 var updatePagerActive = function updatePagerActive(slideIndex) { 886 // if "short" pager type 887 var len = slider.children.length; // nb of children 888 if (slider.settings.pagerType == 'short') { 889 if (slider.settings.maxSlides > 1) { 890 len = Math.ceil(slider.children.length / slider.settings.maxSlides); 891 } 892 slider.pagerEl.html(slideIndex + 1 + slider.settings.pagerShortSeparator + len); 893 return; 894 } 895 // remove all pager active classes 896 slider.pagerEl.find('a').removeClass('active'); 897 // apply the active class for all pagers 898 slider.pagerEl.each(function (i, el) { 899 $(el).find('a').eq(slideIndex).addClass('active'); 900 }); 901 }; 902 903 /** 904 * Performs needed actions after a slide transition 905 */ 906 var updateAfterSlideTransition = function updateAfterSlideTransition() { 907 // if infinte loop is true 908 if (slider.settings.infiniteLoop) { 909 var position = ''; 910 // first slide 911 if (slider.active.index == 0) { 912 // set the new position 913 position = slider.children.eq(0).position(); 914 // carousel, last slide 915 } else if (slider.active.index == getPagerQty() - 1 && slider.carousel) { 916 position = slider.children.eq((getPagerQty() - 1) * getMoveBy()).position(); 917 // last slide 918 } else if (slider.active.index == slider.children.length - 1) { 919 position = slider.children.eq(slider.children.length - 1).position(); 920 } 921 if (position) { 922 if (slider.settings.mode == 'horizontal') { 923 setPositionProperty(-position.left, 'reset', 0); 924 } else if (slider.settings.mode == 'vertical') { 925 setPositionProperty(-position.top, 'reset', 0); 926 } 927 } 928 } 929 // declare that the transition is complete 930 slider.working = false; 931 // onSlideAfter callback 932 slider.settings.onSlideAfter(slider.children.eq(slider.active.index), slider.oldIndex, slider.active.index); 933 }; 934 935 /** 936 * Updates the auto controls state (either active, or combined switch) 937 * 938 * @param state (string) "start", "stop" 939 * - the new state of the auto show 940 */ 941 var updateAutoControls = function updateAutoControls(state) { 942 // if autoControlsCombine is true, replace the current control with the new state 943 if (slider.settings.autoControlsCombine) { 944 slider.controls.autoEl.html(slider.controls[state]); 945 // if autoControlsCombine is false, apply the "active" class to the appropriate control 946 } else { 947 slider.controls.autoEl.find('a').removeClass('active');
948 slider.controls.autoEl.find('a:not(.bx-' + state + ')').addClass('active'); 949 } 950 }; 951 952 /** 953 * Updates the direction controls (checks if either should be hidden) 954 */ 955 var updateDirectionControls = function updateDirectionControls() { 956 if (getPagerQty() == 1) { 957 slider.controls.prev.addClass('disabled'); 958 slider.controls.next.addClass('disabled'); 959 } else if (!slider.settings.infiniteLoop && slider.settings.hideControlOnEnd) { 960 // if first slide 961 if (slider.active.index == 0) { 962 slider.controls.prev.addClass('disabled'); 963 slider.controls.next.removeClass('disabled'); 964 // if last slide 965 } else if (slider.active.index == getPagerQty() - 1) { 966 slider.controls.next.addClass('disabled'); 967 slider.controls.prev.removeClass('disabled'); 968 // if any slide in the middle 969 } else { 970 slider.controls.prev.removeClass('disabled'); 971 slider.controls.next.removeClass('disabled'); 972 } 973 } 974 }; 975 976 /** 977 * Initialzes the auto process 978 */ 979 var initAuto = function initAuto() { 980 // if autoDelay was supplied, launch the auto show using a setTimeout() call 981 if (slider.settings.autoDelay > 0) { 982 var timeout = setTimeout(el.startAuto, slider.settings.autoDelay); 983 // if autoDelay was not supplied, start the auto show normally 984 } else { 985 el.startAuto(); 986 } 987 // if autoHover is requested 988 if (slider.settings.autoHover) { 989 // on el hover 990 el.hover(function () { 991 // if the auto show is currently playing (has an active interval) 992 if (slider.interval) { 993 // stop the auto show and pass true agument which will prevent control update 994 el.stopAuto(true); 995 // create a new autoPaused value which will be used by the relative "mouseout" event 996 slider.autoPaused = true; 997 } 998 }, function () { 999 // if the autoPaused value was created be the prior "mouseover" event 1000 if (slider.autoPaused) { 1001 // start the auto show and pass true agument which will prevent control update 1002 el.startAuto(true); 1003 // reset the autoPaused value 1004 slider.autoPaused = null; 1005 } 1006 }); 1007 } 1008 }; 1009 1010 /** 1011 * Initialzes the ticker process 1012 */ 1013 var initTicker = function initTicker() { 1014 var startPosition = 0; 1015 // if autoDirection is "next", append a clone of the entire slider 1016 if (slider.settings.autoDirection == 'next') { 1017 el.append(slider.children.clone().addClass('bx-clone')); 1018 // if autoDirection is "prev", prepend a clone of the entire slider, and set the left position 1019 } else { 1020 el.prepend(slider.children.clone().addClass('bx-clone')); 1021 var position = slider.children.first().position(); 1022 startPosition = slider.settings.mode == 'horizontal' ? -position.left : -position.top; 1023 } 1024 setPositionProperty(startPosition, 'reset', 0); 1025 // do not allow controls in ticker mode 1026 slider.settings.pager = false; 1027 slider.settings.controls = false; 1028 slider.settings.autoControls = false; 1029 // if autoHover is requested 1030 if (slider.settings.tickerHover && !slider.usingCSS) { 1031 // on el hover 1032 slider.viewport.hover(function () { 1033 el.stop(); 1034 }, function () { 1035 // calculate the total width of children (used to calculate the speed ratio) 1036 var totalDimens = 0; 1037 slider.children.each(function (index) { 1038 totalDimens += slider.settings.mode == 'horizontal' ? $(this).outerWidth(true) : $(this).outerHeight(true); 1039 }); 1040 // calculate the speed ratio (used to determine the new speed to finish the paused animation) 1041 var ratio = slider.settings.speed / totalDimens; 1042 // determine which property to use 1043 var property = slider.settings.mode == 'horizontal' ? 'left' : 'top'; 1044 // calculate the new speed 1045 var newSpeed = ratio * (totalDimens - Math.abs(parseInt(el.css(property)))); 1046 tickerLoop(newSpeed); 1047 }); 1048 } 1049 // start the ticker loop 1050 tickerLoop(); 1051 }; 1052 1053 /** 1054 * Runs a continuous loop, news ticker-style 1055 */ 1056 var tickerLoop = function tickerLoop(resumeSpeed) { 1057 speed = resumeSpeed ? resumeSpeed : slider.settings.speed; 1058 var position = { left: 0, top: 0 }; 1059 var reset = { left: 0, top: 0 }; 1060 // if "next" animate left position to last child, then reset left to 0 1061 if (slider.settings.autoDirection == 'next') { 1062 position = el.find('.bx-clone').first().position(); 1063 // if "prev" animate left position to 0, then reset left to first non-clone child 1064 } else { 1065 reset = slider.children.first().position(); 1066 } 1067 var animateProperty = slider.settings.mode == 'horizontal' ? -position.left : -position.top; 1068 var resetValue = slider.settings.mode == 'horizontal' ? -reset.left : -reset.top; 1069 var params = { resetValue: resetValue }; 1070 setPositionProperty(animateProperty, 'ticker', speed, params); 1071 }; 1072 1073 /** 1074 * Initializes touch events 1075 */ 1076 var initTouch = function initTouch() { 1077 // initialize object to contain all touch values 1078 slider.touch = { 1079 start: { x: 0, y: 0 }, 1080 end: { x: 0, y: 0 } 1081 }; 1082 slider.viewport.bind('touchstart', onTouchStart); 1083 }; 1084 1085 /** 1086 * Event handler for "touchstart" 1087 * 1088 * @param e (event) 1089 * - DOM event object 1090 */ 1091 var onTouchStart = function onTouchStart(e) { 1092 if (slider.working) { 1093 e.preventDefault(); 1094 } else { 1095 // record the original position when touch starts 1096 slider.touch.originalPos = el.position(); 1097 var orig = e.originalEvent; 1098 // record the starting touch x, y coordinates
1099 slider.touch.start.x = orig.changedTouches[0].pageX; 1100 slider.touch.start.y = orig.changedTouches[0].pageY; 1101 // bind a "touchmove" event to the viewport 1102 slider.viewport.bind('touchmove', onTouchMove); 1103 // bind a "touchend" event to the viewport 1104 slider.viewport.bind('touchend', onTouchEnd); 1105 } 1106 }; 1107 1108 /** 1109 * Event handler for "touchmove" 1110 * 1111 * @param e (event) 1112 * - DOM event object 1113 */ 1114 var onTouchMove = function onTouchMove(e) { 1115 var orig = e.originalEvent; 1116 // if scrolling on y axis, do not prevent default 1117 var xMovement = Math.abs(orig.changedTouches[0].pageX - slider.touch.start.x); 1118 var yMovement = Math.abs(orig.changedTouches[0].pageY - slider.touch.start.y); 1119 // x axis swipe 1120 if (xMovement * 3 > yMovement && slider.settings.preventDefaultSwipeX) { 1121 e.preventDefault(); 1122 // y axis swipe 1123 } else if (yMovement * 3 > xMovement && slider.settings.preventDefaultSwipeY) { 1124 e.preventDefault(); 1125 } 1126 if (slider.settings.mode != 'fade' && slider.settings.oneToOneTouch) { 1127 var value = 0; 1128 // if horizontal, drag along x axis 1129 if (slider.settings.mode == 'horizontal') { 1130 var change = orig.changedTouches[0].pageX - slider.touch.start.x; 1131 value = slider.touch.originalPos.left + change; 1132 // if vertical, drag along y axis 1133 } else { 1134 var change = orig.changedTouches[0].pageY - slider.touch.start.y; 1135 value = slider.touch.originalPos.top + change; 1136 } 1137 setPositionProperty(value, 'reset', 0); 1138 } 1139 }; 1140 1141 /** 1142 * Event handler for "touchend" 1143 * 1144 * @param e (event) 1145 * - DOM event object 1146 */ 1147 var onTouchEnd = function onTouchEnd(e) { 1148 slider.viewport.unbind('touchmove', onTouchMove); 1149 var orig = e.originalEvent; 1150 var value = 0; 1151 // record end x, y positions 1152 slider.touch.end.x = orig.changedTouches[0].pageX; 1153 slider.touch.end.y = orig.changedTouches[0].pageY; 1154 // if fade mode, check if absolute x distance clears the threshold 1155 if (slider.settings.mode == 'fade') { 1156 var distance = Math.abs(slider.touch.start.x - slider.touch.end.x); 1157 if (distance >= slider.settings.swipeThreshold) { 1158 slider.touch.start.x > slider.touch.end.x ? el.goToNextSlide() : el.goToPrevSlide(); 1159 el.stopAuto(); 1160 } 1161 // not fade mode 1162 } else { 1163 var distance = 0; 1164 // calculate distance and el's animate property 1165 if (slider.settings.mode == 'horizontal') { 1166 distance = slider.touch.end.x - slider.touch.start.x; 1167 value = slider.touch.originalPos.left; 1168 } else { 1169 distance = slider.touch.end.y - slider.touch.start.y; 1170 value = slider.touch.originalPos.top; 1171 } 1172 // if not infinite loop and first / last slide, do not attempt a slide transition 1173 if (!slider.settings.infiniteLoop && (slider.active.index == 0 && distance > 0 || slider.active.last && distance < 0)) { 1174 setPositionProperty(value, 'reset', 200); 1175 } else { 1176 // check if distance clears threshold 1177 if (Math.abs(distance) >= slider.settings.swipeThreshold) { 1178 distance < 0 ? el.goToNextSlide() : el.goToPrevSlide(); 1179 el.stopAuto(); 1180 } else { 1181 // el.animate(property, 200); 1182 setPositionProperty(value, 'reset', 200); 1183 } 1184 } 1185 } 1186 slider.viewport.unbind('touchend', onTouchEnd); 1187 }; 1188 1189 /** 1190 * Window resize event callback 1191 */ 1192 var resizeWindow = function resizeWindow(e) { 1193 // don't do anything if slider isn't initialized. 1194 if (!slider.initialized) return; 1195 // get the new window dimens (again, thank you IE) 1196 var windowWidthNew = $(window).width(); 1197 var windowHeightNew = $(window).height(); 1198 // make sure that it is a true window resize 1199 // *we must check this because our dinosaur friend IE fires a window resize event when certain DOM elements 1200 // are resized. Can you just die already?* 1201 if (windowWidth != windowWidthNew || windowHeight != windowHeightNew) { 1202 // set the new window dimens 1203 windowWidth = windowWidthNew; 1204 windowHeight = windowHeightNew; 1205 // update all dynamic elements 1206 el.redrawSlider(); 1207 // Call user resize handler 1208 slider.settings.onSliderResize.call(el, slider.active.index); 1209 } 1210 }; 1211 1212 /** 1213 * =================================================================================== 1214 * = PUBLIC FUNCTIONS 1215 * =================================================================================== 1216 */ 1217 1218 /** 1219 * Performs slide transition to the specified slide 1220 * 1221 * @param slideIndex (int) 1222 * - the destination slide's index (zero-based) 1223 * 1224 * @param direction (string) 1225 * - INTERNAL USE ONLY - the direction of travel ("prev" / "next") 1226 */ 1227 el.goToSlide = function (slideIndex, direction) { 1228 // if plugin is currently in motion, ignore request 1229 if (slider.working || slider.active.index == slideIndex) return; 1230 // declare that plugin is in motion 1231 slider.working = true; 1232 // store the old index 1233 slider.oldIndex = slider.active.index; 1234 // if slideIndex is less than zero, set active index to last child (this happens during infinite loop) 1235 if (slideIndex < 0) { 1236 slider.active.index = getPagerQty() - 1; 1237 // if slideIndex is greater than children length, set active index to 0 (this happens during infinite loop) 1238 } else if (slideIndex >= getPagerQty()) { 1239 slider.active.index = 0; 1240 // set active index to requested slide 1241 } else { 1242 slider.active.index = slideIndex; 1243 } 1244 // onSlideBefore, onSlideNext, onSlidePrev callbacks 1245 slider.settings.onSlideBefore(slider.children.eq(slider.active.index), slider.oldIndex, slider.active.index); 1246 if (direction == 'next') { 1247 slider.settings.onSlideNext(slider.children.eq(slider.active.index), slider.oldIndex, slider.active.index); 1248 } else if (direction == 'prev') { 1249 slider.settings.onSlidePrev(slider.children.eq(slider.active.index), slider.oldIndex, slider.active.index); 1250 } 1251 // check if last slide 1252 slider.active.last = slider.active.index >= getPagerQty() - 1; 1253 // update the pager with active class 1254 if (slider.settings.pager) updatePagerActive(slider.active.index); 1255 // // check for direction control update 1256 if (slider.settings.controls) updateDirectionControls(); 1257 // if slider is set to mode: "fade" 1258 if (slider.settings.mode == 'fade') { 1259 // if adaptiveHeight is true and next height is different from current height, animate to the new height 1260 if (slider.settings.adaptiveHeight && slider.viewport.height() != getViewportHe
1260ight()) { 1261 slider.viewport.animate({ height: getViewportHeight() }, slider.settings.adaptiveHeightSpeed); 1262 } 1263 // fade out the visible child and reset its z-index value 1264 slider.children.filter(':visible').fadeOut(slider.settings.speed).css({ zIndex: 0 }); 1265 // fade in the newly requested slide 1266 slider.children.eq(slider.active.index).css('zIndex', slider.settings.slideZIndex + 1).fadeIn(slider.settings.speed, function () { 1267 $(this).css('zIndex', slider.settings.slideZIndex); 1268 updateAfterSlideTransition(); 1269 }); 1270 // slider mode is not "fade" 1271 } else { 1272 // if adaptiveHeight is true and next height is different from current height, animate to the new height 1273 if (slider.settings.adaptiveHeight && slider.viewport.height() != getViewportHeight()) { 1274 slider.viewport.animate({ height: getViewportHeight() }, slider.settings.adaptiveHeightSpeed); 1275 } 1276 var moveBy = 0; 1277 var position = { left: 0, top: 0 }; 1278 // if carousel and not infinite loop 1279 if (!slider.settings.infiniteLoop && slider.carousel && slider.active.last) { 1280 if (slider.settings.mode == 'horizontal') { 1281 // get the last child position 1282 var lastChild = slider.children.eq(slider.children.length - 1); 1283 position = lastChild.position(); 1284 // calculate the position of the last slide 1285 moveBy = slider.viewport.width() - lastChild.outerWidth(); 1286 } else { 1287 // get last showing index position 1288 var lastShowingIndex = slider.children.length - slider.settings.minSlides; 1289 position = slider.children.eq(lastShowingIndex).position(); 1290 } 1291 // horizontal carousel, going previous while on first slide (infiniteLoop mode) 1292 } else if (slider.carousel && slider.active.last && direction == 'prev') { 1293 // get the last child position 1294 var eq = slider.settings.moveSlides == 1 ? slider.settings.maxSlides - getMoveBy() : (getPagerQty() - 1) * getMoveBy() - (slider.children.length - slider.settings.maxSlides); 1295 var lastChild = el.children('.bx-clone').eq(eq); 1296 position = lastChild.position(); 1297 // if infinite loop and "Next" is clicked on the last slide 1298 } else if (direction == 'next' && slider.active.index == 0) { 1299 // get the last clone position 1300 position = el.find('> .bx-clone').eq(slider.settings.maxSlides).position(); 1301 slider.active.last = false; 1302 // normal non-zero requests 1303 } else if (slideIndex >= 0) { 1304 var requestEl = slideIndex * getMoveBy(); 1305 position = slider.children.eq(requestEl).position(); 1306 } 1307 1308 /* If the position doesn't exist 1309 * (e.g. if you destroy the slider on a next click), 1310 * it doesn't throw an error. 1311 */ 1312 if ("undefined" !== typeof position) { 1313 var value = slider.settings.mode == 'horizontal' ? -(position.left - moveBy) : -position.top; 1314 // plugin values to be animated 1315 setPositionProperty(value, 'slide', slider.settings.speed); 1316 } 1317 } 1318 }; 1319 1320 /** 1321 * Transitions to the next slide in the show 1322 */ 1323 el.goToNextSlide = function () { 1324 // if infiniteLoop is false and last page is showing, disregard call 1325 if (!slider.settings.infiniteLoop && slider.active.last) return; 1326 var pagerIndex = parseInt(slider.active.index) + 1; 1327 el.goToSlide(pagerIndex, 'next'); 1328 }; 1329 1330 /** 1331 * Transitions to the prev slide in the show 1332 */ 1333 el.goToPrevSlide = function () { 1334 // if infiniteLoop is false and last page is showing, disregard call 1335 if (!slider.settings.infiniteLoop && slider.active.index == 0) return; 1336 var pagerIndex = parseInt(slider.active.index) - 1; 1337 el.goToSlide(pagerIndex, 'prev'); 1338 }; 1339 1340 /** 1341 * Starts the auto show 1342 * 1343 * @param preventControlUpdate (boolean) 1344 * - if true, auto controls state will not be updated 1345 */ 1346 el.startAuto = function (preventControlUpdate) { 1347 // if an interval already exists, disregard call 1348 if (slider.interval) return; 1349 // create an interval 1350 slider.interval = setInterval(function () { 1351 slider.settings.autoDirection == 'next' ? el.goToNextSlide() : el.goToPrevSlide(); 1352 }, slider.settings.pause); 1353 // if auto controls are displayed and preventControlUpdate is not true 1354 if (slider.settings.autoControls && preventControlUpdate != true) updateAutoControls('stop'); 1355 }; 1356 1357 /** 1358 * Stops the auto show 1359 * 1360 * @param preventControlUpdate (boolean) 1361 * - if true, auto controls state will not be updated 1362 */ 1363 el.stopAuto = function (preventControlUpdate) { 1364 // if no interval exists, disregard call 1365 if (!slider.interval) return; 1366 // clear the interval 1367 clearInterval(slider.interval); 1368 slider.interval = null; 1369 // if auto controls are displayed and preventControlUpdate is not true 1370 if (slider.settings.autoControls && preventControlUpdate != true) updateAutoControls('start'); 1371 }; 1372 1373 /** 1374 * Returns current slide index (zero-based) 1375 */ 1376 el.getCurrentSlide = function () { 1377 return slider.active.index; 1378 }; 1379 1380 /** 1381 * Returns current slide element 1382 */ 1383 el.getCurrentSlideElement = function () { 1384 return slider.children.eq(slider.active.index); 1385 }; 1386 1387 /** 1388 * Returns number of slides in show 1389 */ 1390 el.getSlideCount = function () { 1391 return slider.children.length; 1392 }; 1393 1394 /** 1395 * Update all dynamic slider elements 1396 */ 1397 el.redrawSlider = function () { 1398 // resize all children in ratio to new screen size 1399 slider.children.add(el.find('.bx-clone')).width(getSlideWidth()); 1400 // adjust the height
1401 slider.viewport.css('height', getViewportHeight()); 1402 // update the slide position 1403 if (!slider.settings.ticker) setSlidePosition(); 1404 // if active.last was true before the screen resize, we want 1405 // to keep it last no matter what screen size we end on 1406 if (slider.active.last) slider.active.index = getPagerQty() - 1; 1407 // if the active index (page) no longer exists due to the resize, simply set the index as last 1408 if (slider.active.index >= getPagerQty()) slider.active.last = true; 1409 // if a pager is being displayed and a custom pager is not being used, update it 1410 if (slider.settings.pager && !slider.settings.pagerCustom) { 1411 populatePager(); 1412 updatePagerActive(slider.active.index); 1413 } 1414 }; 1415 1416 /** 1417 * Destroy the current instance of the slider (revert everything back to original state) 1418 */ 1419 el.destroySlider = function () { 1420 // don't do anything if slider has already been destroyed 1421 if (!slider.initialized) return; 1422 slider.initialized = false; 1423 $('.bx-clone', this).remove(); 1424 slider.children.each(function () { 1425 $(this).data("origStyle") != undefined ? $(this).attr("style", $(this).data("origStyle")) : $(this).removeAttr('style'); 1426 }); 1427 $(this).data("origStyle") != undefined ? this.attr("style", $(this).data("origStyle")) : $(this).removeAttr('style'); 1428 $(this).unwrap().unwrap(); 1429 if (slider.controls.el) slider.controls.el.remove(); 1430 if (slider.controls.next) slider.controls.next.remove(); 1431 if (slider.controls.prev) slider.controls.prev.remove(); 1432 if (slider.pagerEl && slider.settings.controls) slider.pagerEl.remove(); 1433 $('.bx-caption', this).remove(); 1434 if (slider.controls.autoEl) slider.controls.autoEl.remove(); 1435 clearInterval(slider.interval); 1436 if (slider.settings.responsive) $(window).unbind('resize', resizeWindow); 1437 }; 1438 1439 /** 1440 * Reload the slider (revert all DOM changes, and re-initialize) 1441 */ 1442 el.reloadSlider = function (settings) { 1443 if (settings != undefined) options = settings; 1444 el.destroySlider(); 1445 init(); 1446 }; 1447 1448 init(); 1449 1450 // returns the current jQuery object 1451 return this; 1452 }; 1453 })(jQuery); 1454 /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(2))) 1455 1456/***/ }, 1457 1458/***/ 205: 1459/***/ function(module, exports, __webpack_require__) { 1460 1461 /* WEBPACK VAR INJECTION */(function(jQuery) {'use strict'; 1462 1463 (function ($) { 1464 $.cart = function (element, options) { 1465 var cart = this; 1466 var $cart_btn = $(element); 1467 1468 cart.settings = {}; 1469 1470 // Merge options with defaults 1471 cart.settings = $.extend({ 1472 buyButtonSelector: '.js-product__buy-button', 1473 buyBundleButtonSelector: '.js-bundle__buy-button', 1474 cartHighlightClass: 'cart-button--highlighted', 1475 productFormSelector: '.product__form', 1476 quantitySelector: '.cart-button__quantity', 1477 sumSelector: '.cart-button__sum' 1478 }, options); 1479 1480 // Init the cart plugin 1481 var init = function init() { 1482 cart.quantityContainer = $(cart.settings.quantitySelector); 1483 cart.sumContainer = $(cart.settings.sumSelector); 1484 cart.messageContainer = $(cart.settings.messageBoxSelector); 1485 if ($cart_btn.length === 1) { 1486 setupBuyButtons(); 1487 } 1488 }; 1489 1490 // Get data for ajax submission 1491 var getProductData = function getProductData(productId, caller) { 1492 // If quickbuy, we need to compose product data 1493 var productData = ''; 1494 var productForm = $(cart.settings.productFormSelector); 1495 1496 if (productForm.length === 1 && productForm.children('input[name="id"]').val() === productId) { 1497 // We are on the product page 1498 productData = productForm.serialize(); 1499 } else if (productForm.hasClass('bundle__form')) { 1500 // we're on a bundle form, may contain multiple products with attributes 1501 productData = $(caller).serialize(); 1502 } else { 1503 // we're on a "quick buy" page, like a category or the frontpage 1504 productData = getProductQuickbuyData(productId); 1505 } 1506 1507 return productData; 1508 }; 1509 1510 // Update the shopping cart 1511 var update = function update(newQuantity, newSum) { 1512 if (newQuantity !== getQuantity()) { 1513 highlightCart(); 1514 } 1515 cart.setQuantity(newQuantity); 1516 cart.setSum(newSum); 1517 }; 1518 1519 var setupBuyButtons = function setupBuyButtons() { 1520 // Buy button event 1521 var buyButtons = $(cart.settings.buyButtonSelector); 1522 var buyBundleButtons = $(cart.settings.buyBundleButtonSelector); 1523 1524 buyButtons.off('click').click(function (event) { 1525 event.preventDefault(); 1526 var form = $(this).closest('form')[0]; 1527 var productId = $(this).attr('data-product-id'); 1528 $.post('/handlevogn/leggtil/ajax', getProductData(productId, form), function (data) { 1529 update(data.contents.length, data.total_pricified.total); 1530 if (data.msg !== '' && data.msg !== undefined) { 1531 $.growl({ message: data.msg, type: 'warning' }); 1532 } else { 1533 if (window.FEATURES.get('modal_cart')) { 1534 window.CART_INIT_DATA = data; 1535 window.showCart(); 1536 } else { 1537 $.growl({ message: $(event.target).data('success-msg'), template_selector: '#cart-notify' }); 1538 } 1539 } 1540 }, 'json'); 1541 }); 1542 1543 buyBundleButtons.off('click').click(function (event) { 1544 event.preventDefault(); 1545 var form = $(this).closest('form')[0]; 1546 var formData = $(form).serialize(); 1547 $.post('/handlevogn/addBundle', formData, function (data) { 1548 console.log(data); 1549 update(data.items, data.total); 1550 if (data.msg !== '') { 1551 $.growl({ message: data.msg, type: 'warning' }); 1552 } else { 1553 if (window.FEATURES.get('modal_cart')) { 1554 window.CART_INIT_DATA = data; 1555 window.showCart(); 1556 } else { 1557 $.growl({ message: $(event.target).data('success-msg'), template_selector: '#cart-notify' }); 1558 } 1559 } 1560 }, 'json'); 1561 }); 1562 }; 1563 1564 // Get quickbuy data for ajax submission 1565 var getProductQuickbuyData = function getProductQuickbuyData(productId) { 1566 return 'id=' + productId + '&path=' + encodeURIComponent(window.location.pathname.split('?')[0]) + // return path, in case of errors 1567 '&' + encodeURI("attributt[][0]") + '=' + '&antall=1' + '&ekstra_tekst=' + '&ekstra_velg=0'; 1568 }; 1569 1570 // Set cart quantity 1571 cart.setQuantity = function (quantity) { 1572 if (parseInt(quantity, 10) > 99) { 1573 cart.quantityContainer.html('<i class="icon-larger-than"></i>99'); 1574 } else { 1575 cart.quantityContainer.text(quantity); 1576 } 1577 1578 if (quantity > 0) { 1579 $cart_btn.removeClass('cart-button--empty'); 1580 } else { 1581 $cart_btn.addClass('cart-button--empty'); 1582 } 1583 }; 1584 1585 // Find quantity 1586 var getQuantity = function getQuantity() { 1587 var quantity = cart.quantityContainer.html().replace('<i class="icon-larger-than"></i>', ''); // Strip > if number is ">99" 1588 return parseInt(quantity, 10); 1589 }; 1590 1591 // Set cart sum 1592 cart.setSum = function (sum) { 1593 cart.sumContainer.html(sum); 1594 }; 1595 1596 // Highlight the cart 1597 var highlightCart = function highlightCart() { 1598 $cart_btn.addClass(cart.settings.cartHighlightClass); 1599 setTimeout(function () { 1600 $cart_btn.removeClass(cart.settings.cartHighlightClass); 1601 }, 200); 1602 }; 1603 1604 init(); 1605 }; 1606
1607 $.fn.cart = function (options) { 1608 return this.each(function () { 1609 if (undefined === $(this).data('cart')) { 1610 var plugin = new $.cart(this, options); 1611 $(this).data('cart', plugin); 1612 } 1613 }); 1614 }; 1615 })(jQuery); 1616 /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(2))) 1617 1618/***/ }, 1619 1620/***/ 206: 1621/***/ function(module, exports, __webpack_require__) { 1622 1623 /* WEBPACK VAR INJECTION */(function(jQuery) {"use strict"; 1624 1625 /*! 1626 * fancyBox - jQuery Plugin 1627 * version: 2.1.5 (Fri, 14 Jun 2013) 1628 * @requires jQuery v1.6 or later 1629 * 1630 * Examples at http://fancyapps.com/fancybox/ 1631 * License: www.fancyapps.com/fancybox/#license 1632 * 1633 * Copyright 2012 Janis Skarnelis - [email protected] 1634 * 1635 */ 1636 1637 (function (window, document, $, undefined) { 1638 "use strict"; 1639 1640 var H = $("html"), 1641 W = $(window), 1642 D = $(document), 1643 F = $.fancybox = function () { 1644 F.open.apply(this, arguments); 1645 }, 1646 IE = navigator.userAgent.match(/msie/i), 1647 didUpdate = null, 1648 isTouch = document.createTouch !== undefined, 1649 isQuery = function isQuery(obj) { 1650 return obj && obj.hasOwnProperty && obj instanceof $; 1651 }, 1652 isString = function isString(str) { 1653 return str && $.type(str) === "string"; 1654 }, 1655 isPercentage = function isPercentage(str) { 1656 return isString(str) && str.indexOf('%') > 0; 1657 }, 1658 isScrollable = function isScrollable(el) { 1659 return el && !(el.style.overflow && el.style.overflow === 'hidden') && (el.clientWidth && el.scrollWidth > el.clientWidth || el.clientHeight && el.scrollHeight > el.clientHeight); 1660 }, 1661 getScalar = function getScalar(orig, dim) { 1662 var value = parseInt(orig, 10) || 0; 1663 1664 if (dim && isPercentage(orig)) { 1665 value = F.getViewport()[dim] / 100 * value; 1666 } 1667 1668 return Math.ceil(value); 1669 }, 1670 getValue = function getValue(value, dim) { 1671 return getScalar(value, dim) + 'px'; 1672 }; 1673 1674 $.extend(F, { 1675 // The current version of fancyBox 1676 version: '2.1.5', 1677 1678 defaults: { 1679 padding: 15, 1680 margin: 20, 1681 1682 width: 800, 1683 height: 600, 1684 minWidth: 100, 1685 minHeight: 100, 1686 maxWidth: 9999, 1687 maxHeight: 9999, 1688 pixelRatio: 1, // Set to 2 for retina display support 1689 1690 autoSize: true, 1691 autoHeight: false, 1692 autoWidth: false, 1693 1694 autoResize: true, 1695 autoCenter: !isTouch, 1696 fitToView: true, 1697 aspectRatio: false, 1698 topRatio: 0.5, 1699 leftRatio: 0.5, 1700 1701 scrolling: 'auto', // 'auto', 'yes' or 'no' 1702 wrapCSS: '', 1703 1704 arrows: true, 1705 closeBtn: true, 1706 closeClick: false, 1707 nextClick: false, 1708 mouseWheel: true, 1709 autoPlay: false, 1710 playSpeed: 3000, 1711 preload: 3, 1712 modal: false, 1713 loop: true, 1714 1715 ajax: { 1716 dataType: 'html', 1717 headers: { 'X-fancyBox': true } 1718 }, 1719 iframe: { 1720 scrolling: 'auto', 1721 preload: true 1722 }, 1723 swf: { 1724 wmode: 'transparent', 1725 allowfullscreen: 'true', 1726 allowscriptaccess: 'always' 1727 }, 1728 1729 keys: { 1730 next: { 1731 13: 'left', // enter 1732 34: 'up', // page down 1733 39: 'left', // right arrow 1734 40: 'up' // down arrow 1735 }, 1736 prev: { 1737 8: 'right', // backspace 1738 33: 'down', // page up 1739 37: 'right', // left arrow 1740 38: 'down' // up arrow 1741 }, 1742 close: [27], // escape key 1743 play: [32], // space - start/stop slideshow 1744 toggle: [70] // letter "f" - toggle fullscreen 1745 }, 1746 1747 direction: { 1748 next: 'left', 1749 prev: 'right' 1750 }, 1751 1752 scrollOutside: true, 1753 1754 // Override some properties 1755 index: 0, 1756 type: null, 1757 href: null, 1758 content: null, 1759 title: null, 1760 1761 // HTML templates 1762 tpl: { 1763 wrap: '<div class="fancybox-wrap" tabIndex="-1"><div class="fancybox-skin"><div class="fancybox-outer"><div class="fancybox-inner"></div></div></div></div>', 1764 image: '<img class="fancybox-image" src="{href}" alt="" />', 1765 iframe: '<iframe id="fancybox-frame{rnd}" name="fancybox-frame{rnd}" class="fancybox-iframe" frameborder="0" vspace="0" hspace="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen' + (IE ? ' allowtransparency="true"' : '') + '></iframe>', 1766 error: '<p class="fancybox-error">The requested content cannot be loaded.<br/>Please try again later.</p>', 1767 closeBtn: '<a title="Close" class="fancybox-item fancybox-close" href="javascript:;"></a>', 1768 next: '<a title="Next" class="fancybox-nav fancybox-next" href="javascript:;"><span></span></a>', 1769 prev: '<a title="Previous" class="fancybox-nav fancybox-prev" href="javascript:;"><span></span></a>' 1770 }, 1771 1772 // Properties for each animation type 1773 // Opening fancyBox 1774 openEffect: 'fade', // 'elastic', 'fade' or 'none' 1775 openSpeed: 250, 1776 openEasing: 'swing', 1777 openOpacity: true, 1778 openMethod: 'zoomIn', 1779 1780 // Closing fancyBox 1781 closeEffect: 'fade', // 'elastic', 'fade' or 'none' 1782 closeSpeed: 250, 1783 closeEasing: 'swing', 1784 closeOpacity: true, 1785 closeMethod: 'zoomOut', 1786 1787 // Changing next gallery item 1788 nextEffect: 'elastic', // 'elastic', 'fade' or 'none' 1789 nextSpeed: 250, 1790 nextEasing: 'swing', 1791 nextMethod: 'changeIn', 1792 1793 // Changing previous gallery item 1794 prevEffect: 'elastic', // 'elastic', 'fade' or 'none' 1795 prevSpeed: 250, 1796 prevEasing: 'swing', 1797 prevMethod: 'changeOut', 1798 1799 // Enable default helpers 1800 helpers: { 1801 overlay: true, 1802 title: true 1803 }, 1804 1805 // Callbacks 1806 onCancel: $.noop, // If canceling 1807 beforeLoad: $.noop, // Before loading 1808 afterLoad: $.noop, // After loading 1809 beforeShow: $.noop, // Before changing in current item 1810 afterShow: $.noop, // After opening 1811 beforeChange: $.noop, // Before changing gallery item 1812 beforeClose: $.noop, // Before closing 1813 afterClose: $.noop // After closing 1814 }, 1815 1816 //Current state 1817 group: {}, // Selected group 1818 opts: {}, // Group options 1819 previous: null, // Previous element
vendor: 4,724 bytes, lines 1820-2029
1820 coming: null, // Element being loaded 1821 current: null, // Currently loaded element 1822 isActive: false, // Is activated 1823 isOpen: false, // Is currently open 1824 isOpened: false, // Have been fully opened at least once 1825 1826 wrap: null, 1827 skin: null, 1828 outer: null, 1829 inner: null, 1830 1831 player: { 1832 timer: null, 1833 isActive: false 1834 }, 1835 1836 // Loaders 1837 ajaxLoad: null, 1838 imgPreload: null, 1839 1840 // Some collections 1841 transitions: {}, 1842 helpers: {}, 1843 1844 /* 1845 * Static methods 1846 */ 1847 1848 open: function open(group, opts) { 1849 if (!group) { 1850 return; 1851 } 1852 1853 if (!$.isPlainObject(opts)) { 1854 opts = {}; 1855 } 1856 1857 // Close if already active 1858 if (false === F.close(true)) { 1859 return; 1860 } 1861 1862 // Normalize group 1863 if (!$.isArray(group)) { 1864 group = isQuery(group) ? $(group).get() : [group]; 1865 } 1866 1867 // Recheck if the type of each element is `object` and set content type (image, ajax, etc) 1868 $.each(group, function (i, element) { 1869 var obj = {}, 1870 href, 1871 title, 1872 content, 1873 type, 1874 rez, 1875 hrefParts, 1876 selector; 1877 1878 if ($.type(element) === "object") { 1879 // Check if is DOM element 1880 if (element.nodeType) { 1881 element = $(element); 1882 } 1883 1884 if (isQuery(element)) { 1885 obj = { 1886 href: element.data('fancybox-href') || element.attr('href'), 1887 title: element.data('fancybox-title') || element.attr('title'), 1888 isDom: true, 1889 element: element 1890 }; 1891 1892 if ($.metadata) { 1893 $.extend(true, obj, element.metadata()); 1894 } 1895 } else { 1896 obj = element; 1897 } 1898 } 1899 1900 href = opts.href || obj.href || (isString(element) ? element : null); 1901 title = opts.title !== undefined ? opts.title : obj.title || ''; 1902 1903 content = opts.content || obj.content; 1904 type = content ? 'html' : opts.type || obj.type; 1905 1906 if (!type && obj.isDom) { 1907 type = element.data('fancybox-type'); 1908 1909 if (!type) { 1910 rez = element.prop('class').match(/fancybox\.(\w+)/); 1911 type = rez ? rez[1] : null; 1912 } 1913 } 1914 1915 if (isString(href)) { 1916 // Try to guess the content type 1917 if (!type) { 1918 if (F.isImage(href)) { 1919 type = 'image'; 1920 } else if (F.isSWF(href)) { 1921 type = 'swf'; 1922 } else if (href.charAt(0) === '#') { 1923 type = 'inline'; 1924 } else if (isString(element)) { 1925 type = 'html'; 1926 content = element; 1927 } 1928 } 1929 1930 // Split url into two pieces with source url and content selector, e.g, 1931 // "/mypage.html #my_id" will load "/mypage.html" and display element having id "my_id" 1932 if (type === 'ajax') { 1933 hrefParts = href.split(/\s+/, 2); 1934 href = hrefParts.shift(); 1935 selector = hrefParts.shift(); 1936 } 1937 } 1938 1939 if (!content) { 1940 if (type === 'inline') { 1941 if (href) { 1942 content = $(isString(href) ? href.replace(/.*(?=#[^\s]+$)/, '') : href); //strip for ie7 1943 } else if (obj.isDom) { 1944 content = element; 1945 } 1946 } else if (type === 'html') { 1947 content = href; 1948 } else if (!type && !href && obj.isDom) { 1949 type = 'inline'; 1950 content = element; 1951 } 1952 } 1953 1954 $.extend(obj, { 1955 href: href, 1956 type: type, 1957 content: content, 1958 title: title, 1959 selector: selector 1960 }); 1961 1962 group[i] = obj; 1963 }); 1964 1965 // Extend the defaults 1966 F.opts = $.extend(true, {}, F.defaults, opts); 1967 1968 // All options are merged recursive except keys 1969 if (opts.keys !== undefined) { 1970 F.opts.keys = opts.keys ? $.extend({}, F.defaults.keys, opts.keys) : false; 1971 } 1972 1973 F.group = group; 1974 1975 return F._start(F.opts.index); 1976 }, 1977 1978 // Cancel image loading or abort ajax request 1979 cancel: function cancel() { 1980 var coming = F.coming; 1981 1982 if (!coming || false === F.trigger('onCancel')) { 1983 return; 1984 } 1985 1986 F.hideLoading(); 1987 1988 if (F.ajaxLoad) { 1989 F.ajaxLoad.abort(); 1990 } 1991 1992 F.ajaxLoad = null; 1993 1994 if (F.imgPreload) { 1995 F.imgPreload.onload = F.imgPreload.onerror = null; 1996 } 1997 1998 if (coming.wrap) { 1999 coming.wrap.stop(true, true).trigger('onReset').remove(); 2000 } 2001 2002 F.coming = null; 2003 2004 // If the first item has been canceled, then clear everything 2005 if (!F.current) { 2006 F._afterZoomOut(coming); 2007 } 2008 }, 2009 2010 // Start closing animation if is open; remove immediately if opening/closing 2011 close: function close(event) { 2012 F.cancel(); 2013 2014 if (false === F.trigger('beforeClose')) { 2015 return; 2016 } 2017 2018 F.unbindEvents(); 2019 2020 if (!F.isActive) { 2021 return; 2022 } 2023 2024 if (!F.isOpen || event === true) { 2025 $('.fancybox-wrap').stop(true).trigger('onReset').remove(); 2026 2027 F._afterZoomOut(); 2028 } else { 2029 F.isOpen = F.isOpened = false;
2030 F.isClosing = true; 2031 2032 $('.fancybox-item, .fancybox-nav').remove(); 2033 2034 F.wrap.stop(true, true).removeClass('fancybox-opened'); 2035 2036 F.transitions[F.current.closeMethod](); 2037 } 2038 }, 2039 2040 // Manage slideshow: 2041 // $.fancybox.play(); - toggle slideshow 2042 // $.fancybox.play( true ); - start 2043 // $.fancybox.play( false ); - stop 2044 play: function play(action) { 2045 var clear = function clear() { 2046 clearTimeout(F.player.timer); 2047 }, 2048 set = function set() { 2049 clear(); 2050 2051 if (F.current && F.player.isActive) { 2052 F.player.timer = setTimeout(F.next, F.current.playSpeed); 2053 } 2054 }, 2055 stop = function stop() { 2056 clear(); 2057 2058 D.unbind('.player'); 2059 2060 F.player.isActive = false; 2061 2062 F.trigger('onPlayEnd'); 2063 }, 2064 start = function start() { 2065 if (F.current && (F.current.loop || F.current.index < F.group.length - 1)) { 2066 F.player.isActive = true; 2067 2068 D.bind({ 2069 'onCancel.player beforeClose.player': stop, 2070 'onUpdate.player': set, 2071 'beforeLoad.player': clear 2072 }); 2073 2074 set(); 2075 2076 F.trigger('onPlayStart'); 2077 } 2078 }; 2079 2080 if (action === true || !F.player.isActive && action !== false) { 2081 start(); 2082 } else { 2083 stop(); 2084 } 2085 }, 2086 2087 // Navigate to next gallery item 2088 next: function next(direction) { 2089 var current = F.current; 2090 2091 if (current) { 2092 if (!isString(direction)) { 2093 direction = current.direction.next; 2094 } 2095 2096 F.jumpto(current.index + 1, direction, 'next'); 2097 } 2098 }, 2099 2100 // Navigate to previous gallery item 2101 prev: function prev(direction) { 2102 var current = F.current; 2103 2104 if (current) { 2105 if (!isString(direction)) { 2106 direction = current.direction.prev; 2107 } 2108 2109 F.jumpto(current.index - 1, direction, 'prev'); 2110 } 2111 }, 2112 2113 // Navigate to gallery item by index 2114 jumpto: function jumpto(index, direction, router) { 2115 var current = F.current; 2116 2117 if (!current) { 2118 return; 2119 } 2120 2121 index = getScalar(index); 2122 2123 F.direction = direction || current.direction[index >= current.index ? 'next' : 'prev']; 2124 F.router = router || 'jumpto'; 2125 2126 if (current.loop) { 2127 if (index < 0) { 2128 index = current.group.length + index % current.group.length; 2129 } 2130 2131 index = index % current.group.length; 2132 } 2133 2134 if (current.group[index] !== undefined) { 2135 F.cancel(); 2136 2137 F._start(index); 2138 } 2139 }, 2140 2141 // Center inside viewport and toggle position type to fixed or absolute if needed 2142 reposition: function reposition(e, onlyAbsolute) { 2143 var current = F.current, 2144 wrap = current ? current.wrap : null, 2145 pos; 2146 2147 if (wrap) { 2148 pos = F._getPosition(onlyAbsolute); 2149 2150 if (e && e.type === 'scroll') { 2151 delete pos.position; 2152 2153 wrap.stop(true, true).animate(pos, 200); 2154 } else { 2155 wrap.css(pos); 2156 2157 current.pos = $.extend({}, current.dim, pos); 2158 } 2159 } 2160 }, 2161 2162 update: function update(e) { 2163 var type = e && e.type, 2164 anyway = !type || type === 'orientationchange'; 2165 2166 if (anyway) { 2167 clearTimeout(didUpdate); 2168 2169 didUpdate = null; 2170 } 2171 2172 if (!F.isOpen || didUpdate) { 2173 return; 2174 } 2175 2176 didUpdate = setTimeout(function () { 2177 var current = F.current; 2178 2179 if (!current || F.isClosing) { 2180 return; 2181 } 2182 2183 F.wrap.removeClass('fancybox-tmp'); 2184 2185 if (anyway || type === 'load' || type === 'resize' && current.autoResize) { 2186 F._setDimension(); 2187 } 2188 2189 if (!(type === 'scroll' && current.canShrink)) { 2190 F.reposition(e); 2191 } 2192 2193 F.trigger('onUpdate'); 2194 2195 didUpdate = null; 2196 }, anyway && !isTouch ? 0 : 300); 2197 }, 2198 2199 // Shrink content to fit inside viewport or restore if resized 2200 toggle: function toggle(action) { 2201 if (F.isOpen) { 2202 F.current.fitToView = $.type(action) === "boolean" ? action : !F.current.fitToView; 2203 2204 // Help browser to restore document dimensions 2205 if (isTouch) { 2206 F.wrap.removeAttr('style').addClass('fancybox-tmp'); 2207 2208 F.trigger('onUpdate'); 2209 } 2210 2211 F.update(); 2212 } 2213 }, 2214 2215 hideLoading: function hideLoading() { 2216 D.unbind('.loading'); 2217 2218 $('#fancybox-loading').remove(); 2219 }, 2220 2221 showLoading: function showLoading() { 2222 var el, viewport; 2223 2224 F.hideLoading(); 2225 2226 el = $('<div id="fancybox-loading"><div></div></div>').click(F.cancel).appendTo('body'); 2227 2228 // If user will press the escape-button, the request will be canceled 2229 D.bind('keydown.loading', function (e) { 2230 if ((e.which || e.keyCode) === 27) { 2231 e.preventDefault(); 2232 2233 F.cancel(); 2234 } 2235 }); 2236 2237 if (!F.defaults.fixed) { 2238 viewport = F.getViewport(); 2239 2240 el.css({ 2241 position: 'absolute', 2242 top: viewport.h * 0.5 + viewport.y, 2243 left: viewport.w * 0.5 + viewport.x 2244 }); 2245 } 2246 }, 2247 2248 getViewport: function getViewport() { 2249 var locked = F.current && F.current.locked || false, 2250 rez = { 2251 x: W.scrollLeft(), 2252 y: W.scrollTop() 2253 }; 2254 2255 if (locked) { 2256 rez.w = locked[0].clientWidth; 2257 rez.h = locked[0].clientHeight; 2258 } else { 2259 // See http://bugs.jquery.com/ticket/6724 2260 rez.w = isTouch && window.innerWidth ? window.innerWidth : W.width(); 2261 rez.h = isTouch && window.innerHeight ? window.innerHeight : W.he
vendor: 26,499 bytes, lines 2261-3280
2261ight(); 2262 } 2263 2264 return rez; 2265 }, 2266 2267 // Unbind the keyboard / clicking actions 2268 unbindEvents: function unbindEvents() { 2269 if (F.wrap && isQuery(F.wrap)) { 2270 F.wrap.unbind('.fb'); 2271 } 2272 2273 D.unbind('.fb'); 2274 W.unbind('.fb'); 2275 }, 2276 2277 bindEvents: function bindEvents() { 2278 var current = F.current, 2279 keys; 2280 2281 if (!current) { 2282 return; 2283 } 2284 2285 // Changing document height on iOS devices triggers a 'resize' event, 2286 // that can change document height... repeating infinitely 2287 W.bind('orientationchange.fb' + (isTouch ? '' : ' resize.fb') + (current.autoCenter && !current.locked ? ' scroll.fb' : ''), F.update); 2288 2289 keys = current.keys; 2290 2291 if (keys) { 2292 D.bind('keydown.fb', function (e) { 2293 var code = e.which || e.keyCode, 2294 target = e.target || e.srcElement; 2295 2296 // Skip esc key if loading, because showLoading will cancel preloading 2297 if (code === 27 && F.coming) { 2298 return false; 2299 } 2300 2301 // Ignore key combinations and key events within form elements 2302 if (!e.ctrlKey && !e.altKey && !e.shiftKey && !e.metaKey && !(target && (target.type || $(target).is('[contenteditable]')))) { 2303 $.each(keys, function (i, val) { 2304 if (current.group.length > 1 && val[code] !== undefined) { 2305 F[i](val[code]); 2306 2307 e.preventDefault(); 2308 return false; 2309 } 2310 2311 if ($.inArray(code, val) > -1) { 2312 F[i](); 2313 2314 e.preventDefault(); 2315 return false; 2316 } 2317 }); 2318 } 2319 }); 2320 } 2321 2322 if ($.fn.mousewheel && current.mouseWheel) { 2323 F.wrap.bind('mousewheel.fb', function (e, delta, deltaX, deltaY) { 2324 var target = e.target || null, 2325 parent = $(target), 2326 canScroll = false; 2327 2328 while (parent.length) { 2329 if (canScroll || parent.is('.fancybox-skin') || parent.is('.fancybox-wrap')) { 2330 break; 2331 } 2332 2333 canScroll = isScrollable(parent[0]); 2334 parent = $(parent).parent(); 2335 } 2336 2337 if (delta !== 0 && !canScroll) { 2338 if (F.group.length > 1 && !current.canShrink) { 2339 if (deltaY > 0 || deltaX > 0) { 2340 F.prev(deltaY > 0 ? 'down' : 'left'); 2341 } else if (deltaY < 0 || deltaX < 0) { 2342 F.next(deltaY < 0 ? 'up' : 'right'); 2343 } 2344 2345 e.preventDefault(); 2346 } 2347 } 2348 }); 2349 } 2350 }, 2351 2352 trigger: function trigger(event, o) { 2353 var ret, 2354 obj = o || F.coming || F.current; 2355 2356 if (!obj) { 2357 return; 2358 } 2359 2360 if ($.isFunction(obj[event])) { 2361 ret = obj[event].apply(obj, Array.prototype.slice.call(arguments, 1)); 2362 } 2363 2364 if (ret === false) { 2365 return false; 2366 } 2367 2368 if (obj.helpers) { 2369 $.each(obj.helpers, function (helper, opts) { 2370 if (opts && F.helpers[helper] && $.isFunction(F.helpers[helper][event])) { 2371 F.helpers[helper][event]($.extend(true, {}, F.helpers[helper].defaults, opts), obj); 2372 } 2373 }); 2374 } 2375 2376 D.trigger(event); 2377 }, 2378 2379 isImage: function isImage(str) { 2380 return isString(str) && str.match(/(^data:image\/.*,)|(\.(jp(e|g|eg)|gif|png|bmp|webp|svg)((\?|#).*)?$)/i); 2381 }, 2382 2383 isSWF: function isSWF(str) { 2384 return isString(str) && str.match(/\.(swf)((\?|#).*)?$/i); 2385 }, 2386 2387 _start: function _start(index) { 2388 var coming = {}, 2389 obj, 2390 href, 2391 type, 2392 margin, 2393 padding; 2394 2395 index = getScalar(index); 2396 obj = F.group[index] || null; 2397 2398 if (!obj) { 2399 return false; 2400 } 2401 2402 coming = $.extend(true, {}, F.opts, obj); 2403 2404 // Convert margin and padding properties to array - top, right, bottom, left 2405 margin = coming.margin; 2406 padding = coming.padding; 2407 2408 if ($.type(margin) === 'number') { 2409 coming.margin = [margin, margin, margin, margin]; 2410 } 2411 2412 if ($.type(padding) === 'number') { 2413 coming.padding = [padding, padding, padding, padding]; 2414 } 2415 2416 // 'modal' propery is just a shortcut 2417 if (coming.modal) { 2418 $.extend(true, coming, { 2419 closeBtn: false, 2420 closeClick: false, 2421 nextClick: false, 2422 arrows: false, 2423 mouseWheel: false, 2424 keys: null, 2425 helpers: { 2426 overlay: { 2427 closeClick: false 2428 } 2429 } 2430 }); 2431 } 2432 2433 // 'autoSize' property is a shortcut, too 2434 if (coming.autoSize) { 2435 coming.autoWidth = coming.autoHeight = true; 2436 } 2437 2438 if (coming.width === 'auto') { 2439 coming.autoWidth = true; 2440 } 2441 2442 if (coming.height === 'auto') { 2443 coming.autoHeight = true; 2444 } 2445 2446 /* 2447 * Add reference to the group, so it`s possible to access from callbacks, example: 2448 * afterLoad : function() { 2449 * this.title = 'Image ' + (this.index + 1) + ' of ' + this.group.length + (this.title ? ' - ' + this.title : ''); 2450 * } 2451 */ 2452 2453 coming.group = F.group; 2454 coming.index = index; 2455 2456 // Give a chance for callback or helpers to update coming item (type, title, etc) 2457 F.coming = coming; 2458 2459 if (false === F.trigger('beforeLoad')) { 2460 F.coming = null; 2461 2462 return; 2463 } 2464 2465 type = coming.type; 2466 href = coming.href; 2467 2468 if (!type) { 2469 F.coming = null; 2470 2471 //If we can not determine content type then drop silently or display next/prev item if looping through gallery 2472 if (F.current && F.router && F.router !== 'jumpto') { 2473 F.current.index = index; 2474 2475 return F[F.router](F.direction); 2476 } 2477 2478 return false; 2479 } 2480 2481 F.isActive = true; 2482 2483 if (type === 'image' || type === 'swf') { 2484 coming.autoHeight = coming.autoWidth = false; 2485 coming.scrolling = 'visible'; 2486 } 2487 2488 if (type === 'image') { 2489 coming.aspectRatio = true; 2490 } 2491 2492 if (type === 'iframe' && isTouch) { 2493 coming.scrolling = 'scroll'; 2494 } 2495 2496 // Build the neccessary markup 2497 coming.wrap = $(coming.tpl.wrap).addClass('fancybox-' + (isTouch ? 'mobile' : 'desktop') + ' fancybox-type-' + type + ' fancybox-tmp ' + coming.wrapCSS).appendTo(coming.parent || 'body'); 2498 2499 $.extend(coming, { 2500 skin: $('.fancybox-skin', coming.wrap), 2501 outer: $('.fancybox-outer', coming.wrap), 2502 inner: $('.fancybox-inner', coming.wrap) 2503 }); 2504 2505 $.each(["Top", "Right", "Bottom", "Left"], function (i, v) { 2506 coming.skin.css('padding' + v, getValue(coming.padding[i])); 2507 }); 2508 2509 F.trigger('onReady'); 2510 2511 // Check before try to load; 'inline' and 'html' types need content, others - href 2512 if (type === 'inline' || type === 'html') { 2513 if (!coming.content || !coming.content.length) { 2514 return F._error('content'); 2515 } 2516 } else if (!href) { 2517 return F._error('href'); 2518 } 2519 2520 if (type === 'image') { 2521 F._loadImage(); 2522 } else if (type === 'ajax') { 2523 F._loadAjax(); 2524 } else if (type === 'iframe') { 2525 F._loadIframe(); 2526 } else { 2527 F._afterLoad(); 2528 } 2529 }, 2530 2531 _error: function _error(type) { 2532 $.extend(F.coming, { 2533 type: 'html', 2534 autoWidth: true, 2535 autoHeight: true, 2536 minWidth: 0, 2537 minHeight: 0, 2538 scrolling: 'no', 2539 hasError: type, 2540 content: F.coming.tpl.error 2541 }); 2542 2543 F._afterLoad(); 2544 }, 2545 2546 _loadImage: function _loadImage() { 2547 // Reset preload image so it is later possible to check "complete" property 2548 var img = F.imgPreload = new Image(); 2549 2550 img.onload = function () { 2551 this.onload = this.onerror = null; 2552 2553 F.coming.width = this.width / F.opts.pixelRatio; 2554 F.coming.height = this.height / F.opts.pixelRatio; 2555 2556 F._afterLoad(); 2557 }; 2558 2559 img.onerror = function () { 2560 this.onload = this.onerror = null; 2561 2562 F._error('image'); 2563 }; 2564 2565 img.src = F.coming.href; 2566 2567 if (img.complete !== true) { 2568 F.showLoading(); 2569 } 2570 }, 2571 2572 _loadAjax: function _loadAjax() { 2573 var coming = F.coming; 2574 2575 F.showLoading(); 2576 2577 F.ajaxLoad = $.ajax($.extend({}, coming.ajax, { 2578 url: coming.href, 2579 error: function error(jqXHR, textStatus) { 2580 if (F.coming && textStatus !== 'abort') { 2581 F._error('ajax', jqXHR); 2582 } else { 2583 F.hideLoading(); 2584 } 2585 }, 2586 success: function success(data, textStatus) { 2587 if (textStatus === 'success') { 2588 coming.content = data; 2589 2590 F._afterLoad(); 2591 } 2592 } 2593 })); 2594 }, 2595 2596 _loadIframe: function _loadIframe() { 2597 var coming = F.coming, 2598 iframe = $(coming.tpl.iframe.replace(/\{rnd\}/g, new Date().getTime())).attr('scrolling', isTouch ? 'auto' : coming.iframe.scrolling).attr('src', coming.href); 2599 2600 // This helps IE 2601 $(coming.wrap).bind('onReset', function () { 2602 try { 2603 $(this).find('iframe').hide().attr('src', '//about:blank').end().empty(); 2604 } catch (e) {} 2605 }); 2606 2607 if (coming.iframe.preload) { 2608 F.showLoading(); 2609 2610 iframe.one('load', function () { 2611 $(this).data('ready', 1); 2612 2613 // iOS will lose scrolling if we resize 2614 if (!isTouch) { 2615 $(this).bind('load.fb', F.update); 2616 } 2617 2618 // Without this trick: 2619 // - iframe won't scroll on iOS devices 2620 // - IE7 sometimes displays empty iframe 2621 $(this).parents('.fancybox-wrap').width('100%').removeClass('fancybox-tmp').show(); 2622 2623 F._afterLoad(); 2624 }); 2625 } 2626 2627 coming.content = iframe.appendTo(coming.inner); 2628 2629 if (!coming.iframe.preload) { 2630 F._afterLoad(); 2631 } 2632 }, 2633 2634 _preloadImages: function _preloadImages() { 2635 var group = F.group, 2636 current = F.current, 2637 len = group.length, 2638 cnt = current.preload ? Math.min(current.preload, len - 1) : 0, 2639 item, 2640 i; 2641 2642 for (i = 1; i <= cnt; i += 1) { 2643 item = group[(current.index + i) % len]; 2644 2645 if (item.type === 'image' && item.href) { 2646 new Image().src = item.href; 2647 } 2648 } 2649 }, 2650 2651 _afterLoad: function _afterLoad() { 2652 var coming = F.coming, 2653 previous = F.current, 2654 placeholder = 'fancybox-placeholder', 2655 current, 2656 content, 2657 type, 2658 scrolling, 2659 href, 2660 embed; 2661 2662 F.hideLoading(); 2663 2664 if (!coming || F.isActive === false) { 2665 return; 2666 } 2667 2668 if (false === F.trigger('afterLoad', coming, previous)) { 2669 coming.wrap.stop(true).trigger('onReset').remove(); 2670 2671 F.coming = null; 2672 2673 return; 2674 } 2675 2676 if (previous) { 2677 F.trigger('beforeChange', previous); 2678 2679 previous.wrap.stop(true).removeClass('fancybox-opened').find('.fancybox-item, .fancybox-nav').remove(); 2680 } 2681 2682 F.unbindEvents(); 2683 2684 current = coming; 2685 content = coming.content; 2686 type = coming.type; 2687 scrolling = coming.scrolling; 2688 2689 $.extend(F, { 2690 wrap: current.wrap, 2691 skin: current.skin, 2692 outer: current.outer, 2693 inner: current.inner, 2694 current: current, 2695 previous: previous 2696 }); 2697 2698 href = current.href; 2699 2700 switch (type) { 2701 case 'inline': 2702 case 'ajax': 2703 case 'html': 2704 if (current.selector) { 2705 content = $('<div>').html(content).find(current.selector); 2706 } else if (isQuery(content)) { 2707 if (!content.data(placeholder)) { 2708 content.data(placeholder, $('<div class="' + placeholder + '"></div>').insertAfter(content).hide()); 2709 } 2710 2711 content = content.show().detach(); 2712 2713 current.wrap.bind('onReset', function () { 2714 if ($(this).find(content).length) { 2715 content.hide().replaceAll(content.data(placeholder)).data(placeholder, false); 2716 } 2717 }); 2718 } 2719 break; 2720 2721 case 'image': 2722 content = current.tpl.image.replace('{href}', href); 2723 break; 2724 2725 case 'swf': 2726 content = '<object id="fancybox-swf" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="100%" height="100%"><param name="movie" value="' + href + '"></param>'; 2727 embed = ''; 2728 2729 $.each(current.swf, function (name, val) { 2730 content += '<param name="' + name + '" value="' + val + '"></param>'; 2731 embed += ' ' + name + '="' + val + '"'; 2732 }); 2733 2734 content += '<embed src="' + href + '" type="application/x-shockwave-flash" width="100%" height="100%"' + embed + '></embed></object>'; 2735 break; 2736 } 2737 2738 if (!(isQuery(content) && content.parent().is(current.inner))) { 2739 current.inner.append(content); 2740 } 2741 2742 // Give a chance for helpers or callbacks to update elements 2743 F.trigger('beforeShow'); 2744 2745 // Set scrolling before calculating dimensions 2746 current.inner.css('overflow', scrolling === 'yes' ? 'scroll' : scrolling === 'no' ? 'hidden' : scrolling); 2747 2748 // Set initial dimensions and start position 2749 F._setDimension(); 2750 2751 F.reposition(); 2752 2753 F.isOpen = false; 2754 F.coming = null; 2755 2756 F.bindEvents(); 2757 2758 if (!F.isOpened) { 2759 $('.fancybox-wrap').not(current.wrap).stop(true).trigger('onReset').remove(); 2760 } else if (previous.prevMethod) { 2761 F.transitions[previous.prevMethod](); 2762 } 2763 2764 F.transitions[F.isOpened ? current.nextMethod : current.openMethod](); 2765 2766 F._preloadImages(); 2767 }, 2768 2769 _setDimension: function _setDimension() { 2770 var viewport = F.getViewport(), 2771 steps = 0, 2772 canShrink = false, 2773 canExpand = false, 2774 wrap = F.wrap, 2775 skin = F.skin, 2776 inner = F.inner, 2777 current = F.current, 2778 width = current.width, 2779 height = current.height, 2780 minWidth = current.minWidth, 2781 minHeight = current.minHeight, 2782 maxWidth = current.maxWidth, 2783 maxHeight = current.maxHeight, 2784 scrolling = current.scrolling, 2785 scrollOut = current.scrollOutside ? current.scrollbarWidth : 0, 2786 margin = current.margin, 2787 wMargin = getScalar(margin[1] + margin[3]), 2788 hMargin = getScalar(margin[0] + margin[2]), 2789 wPadding, 2790 hPadding, 2791 wSpace, 2792 hSpace, 2793 origWidth, 2794 origHeight, 2795 origMaxWidth, 2796 origMaxHeight, 2797 ratio, 2798 width_, 2799 height_, 2800 maxWidth_, 2801 maxHeight_, 2802 iframe, 2803 body; 2804 2805 // Reset dimensions so we could re-check actual size 2806 wrap.add(skin).add(inner).width('auto').height('auto').removeClass('fancybox-tmp'); 2807 2808 wPadding = getScalar(skin.outerWidth(true) - skin.width()); 2809 hPadding = getScalar(skin.outerHeight(true) - skin.height()); 2810 2811 // Any space between content and viewport (margin, padding, border, title) 2812 wSpace = wMargin + wPadding; 2813 hSpace = hMargin + hPadding; 2814 2815 origWidth = isPercentage(width) ? (viewport.w - wSpace) * getScalar(width) / 100 : width; 2816 origHeight = isPercentage(height) ? (viewport.h - hSpace) * getScalar(height) / 100 : height; 2817 2818 if (current.type === 'iframe') { 2819 iframe = current.content; 2820 2821 if (current.autoHeight && iframe.data('ready') === 1) { 2822 try { 2823 if (iframe[0].contentWindow.document.location) { 2824 inner.width(origWidth).height(9999); 2825 2826 body = iframe.contents().find('body'); 2827 2828 if (scrollOut) { 2829 body.css('overflow-x', 'hidden'); 2830 } 2831 2832 origHeight = body.outerHeight(true); 2833 } 2834 } catch (e) {} 2835 } 2836 } else if (current.autoWidth || current.autoHeight) { 2837 inner.addClass('fancybox-tmp'); 2838 2839 // Set width or height in case we need to calculate only one dimension 2840 if (!current.autoWidth) { 2841 inner.width(origWidth); 2842 } 2843 2844 if (!current.autoHeight) { 2845 inner.height(origHeight); 2846 } 2847 2848 if (current.autoWidth) { 2849 origWidth = inner.width(); 2850 } 2851 2852 if (current.autoHeight) { 2853 origHeight = inner.height(); 2854 } 2855 2856 inner.removeClass('fancybox-tmp'); 2857 } 2858 2859 width = getScalar(origWidth); 2860 height = getScalar(origHeight); 2861 2862 ratio = origWidth / origHeight; 2863 2864 // Calculations for the content 2865 minWidth = getScalar(isPercentage(minWidth) ? getScalar(minWidth, 'w') - wSpace : minWidth); 2866 maxWidth = getScalar(isPercentage(maxWidth) ? getScalar(maxWidth, 'w') - wSpace : maxWidth); 2867 2868 minHeight = getScalar(isPercentage(minHeight) ? getScalar(minHeight, 'h') - hSpace : minHeight); 2869 maxHeight = getScalar(isPercentage(maxHeight) ? getScalar(maxHeight, 'h') - hSpace : maxHeight); 2870 2871 // These will be used to determine if wrap can fit in the viewport 2872 origMaxWidth = maxWidth; 2873 origMaxHeight = maxHeight; 2874 2875 if (current.fitToView) { 2876 maxWidth = Math.min(viewport.w - wSpace, maxWidth); 2877 maxHeight = Math.min(viewport.h - hSpace, maxHeight); 2878 } 2879 2880 maxWidth_ = viewport.w - wMargin; 2881 maxHeight_ = viewport.h - hMargin; 2882 2883 if (current.aspectRatio) { 2884 if (width > maxWidth) { 2885 width = maxWidth; 2886 height = getScalar(width / ratio); 2887 } 2888 2889 if (height > maxHeight) { 2890 height = maxHeight; 2891 width = getScalar(height * ratio); 2892 } 2893 2894 if (width < minWidth) { 2895 width = minWidth; 2896 height = getScalar(width / ratio); 2897 } 2898 2899 if (height < minHeight) { 2900 height = minHeight; 2901 width = getScalar(height * ratio); 2902 } 2903 } else { 2904 width = Math.max(minWidth, Math.min(width, maxWidth)); 2905 2906 if (current.autoHeight && current.type !== 'iframe') { 2907 inner.width(width); 2908 2909 height = inner.height(); 2910 } 2911 2912 height = Math.max(minHeight, Math.min(height, maxHeight)); 2913 } 2914 2915 // Try to fit inside viewport (including the title) 2916 if (current.fitToView) { 2917 inner.width(width).height(height); 2918 2919 wrap.width(width + wPadding); 2920 2921 // Real wrap dimensions 2922 width_ = wrap.width(); 2923 height_ = wrap.height(); 2924 2925 if (current.aspectRatio) { 2926 while ((width_ > maxWidth_ || height_ > maxHeight_) && width > minWidth && height > minHeight) { 2927 if (steps++ > 19) { 2928 break; 2929 } 2930 2931 height = Math.max(minHeight, Math.min(maxHeight, height - 10)); 2932 width = getScalar(height * ratio); 2933 2934 if (width < minWidth) { 2935 width = minWidth; 2936 height = getScalar(width / ratio); 2937 } 2938 2939 if (width > maxWidth) { 2940 width = maxWidth; 2941 height = getScalar(width / ratio); 2942 } 2943 2944 inner.width(width).height(height); 2945 2946 wrap.width(width + wPadding); 2947 2948 width_ = wrap.width(); 2949 height_ = wrap.height(); 2950 } 2951 } else { 2952 width = Math.max(minWidth, Math.min(width, width - (width_ - maxWidth_))); 2953 height = Math.max(minHeight, Math.min(height, height - (height_ - maxHeight_))); 2954 } 2955 } 2956 2957 if (scrollOut && scrolling === 'auto' && height < origHeight && width + wPadding + scrollOut < maxWidth_) { 2958 width += scrollOut; 2959 } 2960 2961 inner.width(width).height(height); 2962 2963 wrap.width(width + wPadding); 2964 2965 width_ = wrap.width(); 2966 height_ = wrap.height(); 2967 2968 canShrink = (width_ > maxWidth_ || height_ > maxHeight_) && width > minWidth && height > minHeight; 2969 canExpand = current.aspectRatio ? width < origMaxWidth && height < origMaxHeight && width < origWidth && height < origHeight : (width < origMaxWidth || height < origMaxHeight) && (width < origWidth || height < origHeight); 2970 2971 $.extend(current, { 2972 dim: { 2973 width: getValue(width_), 2974 height: getValue(height_) 2975 }, 2976 origWidth: origWidth, 2977 origHeight: origHeight, 2978 canShrink: canShrink, 2979 canExpand: canExpand, 2980 wPadding: wPadding, 2981 hPadding: hPadding, 2982 wrapSpace: height_ - skin.outerHeight(true), 2983 skinSpace: skin.height() - height 2984 }); 2985 2986 if (!iframe && current.autoHeight && height > minHeight && height < maxHeight && !canExpand) { 2987 inner.height('auto'); 2988 } 2989 }, 2990 2991 _getPosition: function _getPosition(onlyAbsolute) { 2992 var current = F.current, 2993 viewport = F.getViewport(), 2994 margin = current.margin, 2995 width = F.wrap.width() + margin[1] + margin[3], 2996 height = F.wrap.height() + margin[0] + margin[2], 2997 rez = { 2998 position: 'absolute', 2999 top: margin[0], 3000 left: margin[3] 3001 }; 3002 3003 if (current.autoCenter && current.fixed && !onlyAbsolute && height <= viewport.h && width <= viewport.w) { 3004 rez.position = 'fixed'; 3005 } else if (!current.locked) { 3006 rez.top += viewport.y; 3007 rez.left += viewport.x; 3008 } 3009 3010 rez.top = getValue(Math.max(rez.top, rez.top + (viewport.h - height) * current.topRatio)); 3011 rez.left = getValue(Math.max(rez.left, rez.left + (viewport.w - width) * current.leftRatio)); 3012 3013 return rez; 3014 }, 3015 3016 _afterZoomIn: function _afterZoomIn() { 3017 var current = F.current; 3018 3019 if (!current) { 3020 return; 3021 } 3022 3023 F.isOpen = F.isOpened = true; 3024 3025 F.wrap.css('overflow', 'visible').addClass('fancybox-opened'); 3026 3027 F.update(); 3028 3029 // Assign a click event 3030 if (current.closeClick || current.nextClick && F.group.length > 1) { 3031 F.inner.css('cursor', 'pointer').bind('click.fb', function (e) { 3032 if (!$(e.target).is('a') && !$(e.target).parent().is('a')) { 3033 e.preventDefault(); 3034 3035 F[current.closeClick ? 'close' : 'next'](); 3036 } 3037 }); 3038 } 3039 3040 // Create a close button 3041 if (current.closeBtn) { 3042 $(current.tpl.closeBtn).appendTo(F.skin).bind('click.fb', function (e) { 3043 e.preventDefault(); 3044 3045 F.close(); 3046 }); 3047 } 3048 3049 // Create navigation arrows 3050 if (current.arrows && F.group.length > 1) { 3051 if (current.loop || current.index > 0) { 3052 $(current.tpl.prev).appendTo(F.outer).bind('click.fb', F.prev); 3053 } 3054 3055 if (current.loop || current.index < F.group.length - 1) { 3056 $(current.tpl.next).appendTo(F.outer).bind('click.fb', F.next); 3057 } 3058 } 3059 3060 F.trigger('afterShow'); 3061 3062 // Stop the slideshow if this is the last item 3063 if (!current.loop && current.index === current.group.length - 1) { 3064 F.play(false); 3065 } else if (F.opts.autoPlay && !F.player.isActive) { 3066 F.opts.autoPlay = false; 3067 3068 F.play(); 3069 } 3070 }, 3071 3072 _afterZoomOut: function _afterZoomOut(obj) { 3073 obj = obj || F.current; 3074 3075 $('.fancybox-wrap').trigger('onReset').remove(); 3076 3077 $.extend(F, { 3078 group: {}, 3079 opts: {}, 3080 router: false, 3081 current: null, 3082 isActive: false, 3083 isOpened: false, 3084 isOpen: false, 3085 isClosing: false, 3086 wrap: null, 3087 skin: null, 3088 outer: null, 3089 inner: null 3090 }); 3091 3092 F.trigger('afterClose', obj); 3093 } 3094 }); 3095 3096 /* 3097 * Default transitions 3098 */ 3099 3100 F.transitions = { 3101 getOrigPosition: function getOrigPosition() { 3102 var current = F.current, 3103 element = current.element, 3104 orig = current.orig, 3105 pos = {}, 3106 width = 50, 3107 height = 50, 3108 hPadding = current.hPadding, 3109 wPadding = current.wPadding, 3110 viewport = F.getViewport(); 3111 3112 if (!orig && current.isDom && element.is(':visible')) { 3113 orig = element.find('img:first'); 3114 3115 if (!orig.length) { 3116 orig = element; 3117 } 3118 } 3119 3120 if (isQuery(orig)) { 3121 pos = orig.offset(); 3122 3123 if (orig.is('img')) { 3124 width = orig.outerWidth(); 3125 height = orig.outerHeight(); 3126 } 3127 } else { 3128 pos.top = viewport.y + (viewport.h - height) * current.topRatio; 3129 pos.left = viewport.x + (viewport.w - width) * current.leftRatio; 3130 } 3131 3132 if (F.wrap.css('position') === 'fixed' || current.locked) { 3133 pos.top -= viewport.y; 3134 pos.left -= viewport.x; 3135 } 3136 3137 pos = { 3138 top: getValue(pos.top - hPadding * current.topRatio), 3139 left: getValue(pos.left - wPadding * current.leftRatio), 3140 width: getValue(width + wPadding), 3141 height: getValue(height + hPadding) 3142 }; 3143 3144 return pos; 3145 }, 3146 3147 step: function step(now, fx) { 3148 var ratio, 3149 padding, 3150 value, 3151 prop = fx.prop, 3152 current = F.current, 3153 wrapSpace = current.wrapSpace, 3154 skinSpace = current.skinSpace; 3155 3156 if (prop === 'width' || prop === 'height') { 3157 ratio = fx.end === fx.start ? 1 : (now - fx.start) / (fx.end - fx.start); 3158 3159 if (F.isClosing) { 3160 ratio = 1 - ratio; 3161 } 3162 3163 padding = prop === 'width' ? current.wPadding : current.hPadding; 3164 value = now - padding; 3165 3166 F.skin[prop](getScalar(prop === 'width' ? value : value - wrapSpace * ratio)); 3167 F.inner[prop](getScalar(prop === 'width' ? value : value - wrapSpace * ratio - skinSpace * ratio)); 3168 } 3169 }, 3170 3171 zoomIn: function zoomIn() { 3172 var current = F.current, 3173 startPos = current.pos, 3174 effect = current.openEffect, 3175 elastic = effect === 'elastic', 3176 endPos = $.extend({ opacity: 1 }, startPos); 3177 3178 // Remove "position" property that breaks older IE 3179 delete endPos.position; 3180 3181 if (elastic) { 3182 startPos = this.getOrigPosition(); 3183 3184 if (current.openOpacity) { 3185 startPos.opacity = 0.1; 3186 } 3187 } else if (effect === 'fade') { 3188 startPos.opacity = 0.1; 3189 } 3190 3191 F.wrap.css(startPos).animate(endPos, { 3192 duration: effect === 'none' ? 0 : current.openSpeed, 3193 easing: current.openEasing, 3194 step: elastic ? this.step : null, 3195 complete: F._afterZoomIn 3196 }); 3197 }, 3198 3199 zoomOut: function zoomOut() { 3200 var current = F.current, 3201 effect = current.closeEffect, 3202 elastic = effect === 'elastic', 3203 endPos = { opacity: 0.1 }; 3204 3205 if (elastic) { 3206 endPos = this.getOrigPosition(); 3207 3208 if (current.closeOpacity) { 3209 endPos.opacity = 0.1; 3210 } 3211 } 3212 3213 F.wrap.animate(endPos, { 3214 duration: effect === 'none' ? 0 : current.closeSpeed, 3215 easing: current.closeEasing, 3216 step: elastic ? this.step : null, 3217 complete: F._afterZoomOut 3218 }); 3219 }, 3220 3221 changeIn: function changeIn() { 3222 var current = F.current, 3223 effect = current.nextEffect, 3224 startPos = current.pos, 3225 endPos = { opacity: 1 }, 3226 direction = F.direction, 3227 distance = 200, 3228 field; 3229 3230 startPos.opacity = 0.1; 3231 3232 if (effect === 'elastic') { 3233 field = direction === 'down' || direction === 'up' ? 'top' : 'left'; 3234 3235 if (direction === 'down' || direction === 'right') { 3236 startPos[field] = getValue(getScalar(startPos[field]) - distance); 3237 endPos[field] = '+=' + distance + 'px'; 3238 } else { 3239 startPos[field] = getValue(getScalar(startPos[field]) + distance); 3240 endPos[field] = '-=' + distance + 'px'; 3241 } 3242 } 3243 3244 // Workaround for http://bugs.jquery.com/ticket/12273 3245 if (effect === 'none') { 3246 F._afterZoomIn(); 3247 } else { 3248 F.wrap.css(startPos).animate(endPos, { 3249 duration: current.nextSpeed, 3250 easing: current.nextEasing, 3251 complete: F._afterZoomIn 3252 }); 3253 } 3254 }, 3255 3256 changeOut: function changeOut() { 3257 var previous = F.previous, 3258 effect = previous.prevEffect, 3259 endPos = { opacity: 0.1 }, 3260 direction = F.direction, 3261 distance = 200; 3262 3263 if (effect === 'elastic') { 3264 endPos[direction === 'down' || direction === 'up' ? 'top' : 'left'] = (direction === 'up' || direction === 'left' ? '-' : '+') + '=' + distance + 'px'; 3265 } 3266 3267 previous.wrap.animate(endPos, { 3268 duration: effect === 'none' ? 0 : previous.prevSpeed, 3269 easing: previous.prevEasing, 3270 complete: function complete() { 3271 $(this).trigger('onReset').remove(); 3272 } 3273 }); 3274 } 3275 }; 3276 3277 /* 3278 * Overlay helper 3279 */ 3280
3281 F.helpers.overlay = { 3282 defaults: { 3283 closeClick: true, // if true, fancyBox will be closed when user clicks on the overlay 3284 speedOut: 200, // duration of fadeOut animation 3285 showEarly: true, // indicates if should be opened immediately or wait until the content is ready 3286 css: {}, // custom CSS properties 3287 locked: !isTouch, // if true, the content will be locked into overlay 3288 fixed: true // if false, the overlay CSS position property will not be set to "fixed" 3289 }, 3290 3291 overlay: null, // current handle 3292 fixed: false, // indicates if the overlay has position "fixed" 3293 el: $('html'), // element that contains "the lock" 3294 3295 // Public methods 3296 create: function create(opts) { 3297 opts = $.extend({}, this.defaults, opts); 3298 3299 if (this.overlay) { 3300 this.close(); 3301 } 3302 3303 this.overlay = $('<div class="fancybox-overlay"></div>').appendTo(F.coming ? F.coming.parent : opts.parent); 3304 this.fixed = false; 3305 3306 if (opts.fixed && F.defaults.fixed) { 3307 this.overlay.addClass('fancybox-overlay-fixed'); 3308 3309 this.fixed = true; 3310 } 3311 }, 3312 3313 open: function open(opts) { 3314 var that = this; 3315 3316 opts = $.extend({}, this.defaults, opts); 3317 3318 if (this.overlay) { 3319 this.overlay.unbind('.overlay').width('auto').height('auto'); 3320 } else { 3321 this.create(opts); 3322 } 3323 3324 if (!this.fixed) { 3325 W.bind('resize.overlay', $.proxy(this.update, this)); 3326 3327 this.update(); 3328 } 3329 3330 if (opts.closeClick) { 3331 this.overlay.bind('click.overlay', function (e) { 3332 if ($(e.target).hasClass('fancybox-overlay')) { 3333 if (F.isActive) { 3334 F.close(); 3335 } else { 3336 that.close(); 3337 } 3338 3339 return false; 3340 } 3341 }); 3342 } 3343 3344 this.overlay.css(opts.css).show(); 3345 }, 3346 3347 close: function close() { 3348 var scrollV, scrollH; 3349 3350 W.unbind('resize.overlay'); 3351 3352 if (this.el.hasClass('fancybox-lock')) { 3353 $('.fancybox-margin').removeClass('fancybox-margin'); 3354 3355 scrollV = W.scrollTop(); 3356 scrollH = W.scrollLeft(); 3357 3358 this.el.removeClass('fancybox-lock'); 3359 3360 W.scrollTop(scrollV).scrollLeft(scrollH); 3361 } 3362 3363 $('.fancybox-overlay').remove().hide(); 3364 3365 $.extend(this, { 3366 overlay: null, 3367 fixed: false 3368 }); 3369 }, 3370 3371 // Private, callbacks 3372 3373 update: function update() { 3374 var width = '100%', 3375 offsetWidth; 3376 3377 // Reset width/height so it will not mess 3378 this.overlay.width(width).height('100%'); 3379 3380 // jQuery does not return reliable result for IE 3381 if (IE) { 3382 offsetWidth = Math.max(document.documentElement.offsetWidth, document.body.offsetWidth); 3383 3384 if (D.width() > offsetWidth) { 3385 width = D.width(); 3386 } 3387 } else if (D.width() > W.width()) { 3388 width = D.width(); 3389 } 3390 3391 this.overlay.width(width).height(D.height()); 3392 }, 3393 3394 // This is where we can manipulate DOM, because later it would cause iframes to reload 3395 onReady: function onReady(opts, obj) { 3396 var overlay = this.overlay; 3397 3398 $('.fancybox-overlay').stop(true, true); 3399 3400 if (!overlay) { 3401 this.create(opts); 3402 } 3403 3404 if (opts.locked && this.fixed && obj.fixed) { 3405 if (!overlay) { 3406 this.margin = D.height() > W.height() ? $('html').css('margin-right').replace("px", "") : false; 3407 } 3408 3409 obj.locked = this.overlay.append(obj.wrap); 3410 obj.fixed = false; 3411 } 3412 3413 if (opts.showEarly === true) { 3414 this.beforeShow.apply(this, arguments); 3415 } 3416 }, 3417 3418 beforeShow: function beforeShow(opts, obj) { 3419 var scrollV, scrollH; 3420 3421 if (obj.locked) { 3422 if (this.margin !== false) { 3423 $('*').filter(function () { 3424 return $(this).css('position') === 'fixed' && !$(this).hasClass("fancybox-overlay") && !$(this).hasClass("fancybox-wrap"); 3425 }).addClass('fancybox-margin'); 3426 3427 this.el.addClass('fancybox-margin'); 3428 } 3429 3430 scrollV = W.scrollTop(); 3431 scrollH = W.scrollLeft(); 3432 3433 this.el.addClass('fancybox-lock'); 3434 3435 W.scrollTop(scrollV).scrollLeft(scrollH); 3436 } 3437 3438 this.open(opts); 3439 }, 3440 3441 onUpdate: function onUpdate() { 3442 if (!this.fixed) { 3443 this.update(); 3444 } 3445 }, 3446 3447 afterClose: function afterClose(opts) { 3448 // Remove overlay if exists and fancyBox is not opening 3449 // (e.g., it is not being open using afterClose callback) 3450 //if (this.overlay && !F.isActive) { 3451 if (this.overlay && !F.coming) { 3452 this.overlay.fadeOut(opts.speedOut, $.proxy(this.close, this)); 3453 } 3454 } 3455 }; 3456 3457 /* 3458 * Title helper 3459 */ 3460 3461 F.helpers.title = { 3462 defaults: { 3463 type: 'float', // 'float', 'inside', 'outside' or 'over', 3464 position: 'bottom' // 'top' or 'bottom' 3465 }, 3466 3467 beforeShow: function beforeShow(opts) { 3468 var current = F.current, 3469 text = current.title, 3470 type = opts.type, 3471 title, 3472 target; 3473 3474 if ($.isFunction(text)) { 3475 text = text.call(current.element, current); 3476 } 3477 3478 if (!isString(text) || $.trim(text) === '') { 3479 return; 3480 } 3481 3482 title = $('<div class="fancybox-title fancybox-title-' + type + '-wrap">
vendor: 4,072 bytes, lines 3482-3641
3482' + text + '</div>'); 3483 3484 switch (type) { 3485 case 'inside': 3486 target = F.skin; 3487 break; 3488 3489 case 'outside': 3490 target = F.wrap; 3491 break; 3492 3493 case 'over': 3494 target = F.inner; 3495 break; 3496 3497 default: 3498 // 'float' 3499 target = F.skin; 3500 3501 title.appendTo('body'); 3502 3503 if (IE) { 3504 title.width(title.width()); 3505 } 3506 3507 title.wrapInner('<span class="child"></span>'); 3508 3509 //Increase bottom margin so this title will also fit into viewport 3510 F.current.margin[2] += Math.abs(getScalar(title.css('margin-bottom'))); 3511 break; 3512 } 3513 3514 title[opts.position === 'top' ? 'prependTo' : 'appendTo'](target); 3515 } 3516 }; 3517 3518 // jQuery plugin initialization 3519 $.fn.fancybox = function (options) { 3520 var index, 3521 that = $(this), 3522 selector = this.selector || '', 3523 run = function run(e) { 3524 var what = $(this).blur(), 3525 idx = index, 3526 relType, 3527 relVal; 3528 3529 if (!(e.ctrlKey || e.altKey || e.shiftKey || e.metaKey) && !what.is('.fancybox-wrap')) { 3530 relType = options.groupAttr || 'data-fancybox-group'; 3531 relVal = what.attr(relType); 3532 3533 if (!relVal) { 3534 relType = 'rel'; 3535 relVal = what.get(0)[relType]; 3536 } 3537 3538 if (relVal && relVal !== '' && relVal !== 'nofollow') { 3539 what = selector.length ? $(selector) : that; 3540 what = what.filter('[' + relType + '="' + relVal + '"]'); 3541 idx = what.index(this); 3542 } 3543 3544 options.index = idx; 3545 3546 // Stop an event from bubbling if everything is fine 3547 if (F.open(what, options) !== false) { 3548 e.preventDefault(); 3549 } 3550 } 3551 }; 3552 3553 options = options || {}; 3554 index = options.index || 0; 3555 3556 if (!selector || options.live === false) { 3557 that.unbind('click.fb-start').bind('click.fb-start', run); 3558 } else { 3559 D.undelegate(selector, 'click.fb-start').delegate(selector + ":not('.fancybox-item, .fancybox-nav')", 'click.fb-start', run); 3560 } 3561 3562 this.filter('[data-fancybox-start=1]').trigger('click'); 3563 3564 return this; 3565 }; 3566 3567 // Tests that need a body at doc ready 3568 D.ready(function () { 3569 var w1, w2; 3570 3571 if ($.scrollbarWidth === undefined) { 3572 // http://benalman.com/projects/jquery-misc-plugins/#scrollbarwidth 3573 $.scrollbarWidth = function () { 3574 var parent = $('<div style="width:50px;height:50px;overflow:auto"><div/></div>').appendTo('body'), 3575 child = parent.children(), 3576 width = child.innerWidth() - child.height(99).innerWidth(); 3577 3578 parent.remove(); 3579 3580 return width; 3581 }; 3582 } 3583 3584 if ($.support.fixedPosition === undefined) { 3585 $.support.fixedPosition = function () { 3586 var elem = $('<div style="position:fixed;top:20px;"></div>').appendTo('body'), 3587 fixed = elem[0].offsetTop === 20 || elem[0].offsetTop === 15; 3588 3589 elem.remove(); 3590 3591 return fixed; 3592 }(); 3593 } 3594 3595 $.extend(F.defaults, { 3596 scrollbarWidth: $.scrollbarWidth(), 3597 fixed: $.support.fixedPosition, 3598 parent: $('body') 3599 }); 3600 3601 //Get real width of page scroll-bar 3602 w1 = $(window).width(); 3603 3604 H.addClass('fancybox-lock-test'); 3605 3606 w2 = $(window).width(); 3607 3608 H.removeClass('fancybox-lock-test'); 3609 3610 $("<style type='text/css'>.fancybox-margin{margin-right:" + (w2 - w1) + "px;}</style>").appendTo("head"); 3611 }); 3612 })(window, document, jQuery); 3613 /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(2))) 3614 3615/***/ }, 3616 3617/***/ 211: 3618/***/ function(module, exports, __webpack_require__) { 3619 3620 /* WEBPACK VAR INJECTION */(function(jQuery) {'use strict'; 3621 3622 /* global sincos, jQuery */ 3623 3624 (function ($) { 3625 3626 $.productsearch = function (element, options) { 3627 3628 var productsearch = this; 3629 3630 var $productsearch_input = $(element); 3631 3632 productsearch.settings = {}; 3633 3634 // Merge options with defaults 3635 productsearch.settings = $.extend({ 3636 searchSubmitSelector: '.js-product-search-submit', 3637 lastSearchString: '', 3638 resultsWrapper: 'ul', 3639 resultsWrapperClass: 'product-search__output', 3640 resultElementWrapper: 'li', 3641 resultElementWrapperClass: 'product-search__element',
3642 outputContainerSelector: '.js-product-search__container', 3643 outputWrapper: '.js-product-search-results', 3644 extraHitsSelector: '.js-product-search__extra-hits', 3645 numHitsSelector: '.js-product-search__num-extra-hits', 3646 noHitsSelector: '.js-product-search__no-hits', 3647 linkClass: 'themed-nav', 3648 minQueryLength: 3 3649 }, options); 3650 3651 // Init the plugin 3652 var init = function init() { 3653 productsearch.output_container = $(productsearch.settings.outputContainerSelector); 3654 productsearch.output_wrapper = $(productsearch.settings.outputWrapper); 3655 productsearch.no_hits = $(productsearch.settings.noHitsSelector); 3656 productsearch.extra_hits = $(productsearch.settings.extraHitsSelector); 3657 productsearch.num_extra_hits = $(productsearch.settings.numHitsSelector); 3658 setupListeners(); 3659 }; 3660 3661 // Which events should we listen for 3662 var setupListeners = function setupListeners() { 3663 $productsearch_input.on('keydown', function (event) { 3664 // Blur the field if 'esc' is pressed 3665 if (event.keyCode == 27) { 3666 return $(this).blur(); 3667 } 3668 3669 // Cannot cache this selector as new search results load async 3670 var links = productsearch.output_container.find('a.themed-nav:visible'), 3671 active = links.filter('.active'), 3672 index = $.inArray(active[0] || active, links); 3673 3674 //Can't do shit with no links 3675 if (links.length) { 3676 //Down/tab 40/9 3677 if (event.keyCode == 40 || event.keyCode == 9) { 3678 event.preventDefault(); 3679 3680 var next = Math.min(index + 1, links.length - 1); 3681 links.removeClass('active'); 3682 $(links[next]).addClass('active'); 3683 } 3684 //Up/shift+tab 38/9+ 3685 if (event.keyCode == 38 || event.keyCode == 9 && event.shiftKey === true) { 3686 event.preventDefault(); 3687 3688 var prev = Math.max(index - 1, -1); 3689 links.removeClass('active'); 3690 //Allow user to deselect results instead of force selecting the first result 3691 if (prev > -1) $(links[prev]).addClass('active'); 3692 } 3693 //Return/enter 10/13, if no result is .active then allow user to see search results page when hitting enter 3694 if (event.keyCode == 10 || event.keyCode == 13 && active.length) { 3695 event.preventDefault(); 3696 3697 active[0].click(); //Emulate native browser click 3698 } 3699 } 3700 }); 3701 $productsearch_input.on('change keyup', sincos.functions.debounce(search, 300)); 3702 $productsearch_input.on('focus', focusSearch); 3703 $productsearch_input.on('blur', sincos.functions.debounce(hideResults, 500)); 3704 productsearch.extra_hits.click(function (event) { 3705 event.preventDefault(); 3706 $(productsearch.settings.searchSubmitSelector).trigger('click'); 3707 }); 3708 }; 3709 3710 var focusSearch = function focusSearch() { 3711 if (hasResults()) { 3712 showResults(); 3713 } 3714 }; 3715 3716 var setActivityIndicator = function setActivityIndicator() { 3717 $productsearch_input.closest('form').addClass('search-box--loading'); 3718 }, 3719 resetActivityIndicator = function resetActivityIndicator() { 3720 $productsearch_input.closest('form').removeClass('search-box--loading'); 3721 }; 3722 3723 var search = function search() { 3724 var query = getSearchString(); 3725 3726 // Prevent querying the server for the same stuff twice 3727 // Prevent searching for short search terms 3728 if (query != productsearch.settings.lastSearchString && query.length >= productsearch.settings.minQueryLength) { 3729 productsearch.settings.lastSearchString = query; 3730
3731 setActivityIndicator(); 3732 $.ajax({ 3733 url: '/search', 3734 data: $productsearch_input.serialize(), 3735 dataType: 'json' 3736 }).done(function (data) { 3737 outputResults(data); 3738 }).always(resetActivityIndicator).error(clearResults); 3739 } else if (query.length < productsearch.settings.minQueryLength) { 3740 clearResults(); 3741 productsearch.settings.lastSearchString = query; 3742 resetActivityIndicator(); 3743 } 3744 }; 3745 3746 var getSearchString = function getSearchString() { 3747 return $productsearch_input.val().trim(); 3748 }; 3749 3750 var hasValidSearchString = function hasValidSearchString() { 3751 var query = getSearchString(); 3752 return query.length >= productsearch.settings.minQueryLength; 3753 }; 3754 3755 var outputResults = function outputResults(results) { 3756 productsearch.output_container.removeClass('is-hidden'); 3757 $productsearch_input.addClass('is-results'); 3758 3759 var output = $(document.createElement(productsearch.settings.resultsWrapper)).addClass(productsearch.settings.resultsWrapperClass); 3760 var row = $(document.createElement(productsearch.settings.resultElementWrapper)).addClass(productsearch.settings.resultElementWrapperClass); 3761 var i = 0; 3762 3763 $.each(results.produkter, function (index, elem) { 3764 output.append(row.clone().attr('id', 'prod-' + elem.id).html('<a class="' + productsearch.settings.linkClass + '" href="/produkt/' + elem.sti + '/' + elem.navn + '">' + elem.overskrift + '</a>').on('focusout', sincos.functions.debounce(hideResults, 500))); 3765 i++; 3766 }); 3767 3768 // If large number of hits, display number of extra hits 3769 productsearch.num_extra_hits.text(results.antall - i); 3770 3771 productsearch.output_container.html(output); 3772 3773 showResults(); 3774 3775 trackPageView(); 3776 }; 3777 3778 var hasResults = function hasResults() { 3779 return productsearch.output_container.find(productsearch.settings.resultElementWrapper).length > 0; 3780 }; 3781 3782 var hasExtraResults = function hasExtraResults() { 3783 return parseInt(productsearch.num_extra_hits.text(), 10) > 0; 3784 }; 3785 3786 var showResults = function showResults() { 3787 if (hasResults()) { 3788 productsearch.no_hits.addClass('is-hidden'); 3789 productsearch.output_wrapper.removeClass('is-hidden'); 3790 productsearch.output_container.removeClass('is-hidden'); 3791 $productsearch_input.addClass('is-results'); 3792 3793 if (hasExtraResults()) { 3794 productsearch.extra_hits.removeClass('is-hidden'); 3795 } else { 3796 productsearch.extra_hits.addClass('is-hidden'); 3797 } 3798 } else if (hasValidSearchString()) { 3799 displayEmptyResults(); 3800 } 3801 }; 3802 3803 var trackPageView = function trackPageView() { 3804 if ('ga' in window) { 3805 window.ga('send', 'pageview', 'search/?q=' + getSearchString()); 3806 } 3807 }; 3808 3809 var hideResults = function hideResults() { 3810 // If focus is not in the resultset, hide the resultset 3811 if (!$.contains(productsearch.output_wrapper.get(0), document.activeElement)) { 3812 productsearch.output_wrapper.addClass('is-hidden'); 3813 productsearch.extra_hits.addClass('is-hidden'); 3814 productsearch.output_container.addClass('is-hidden'); 3815 $productsearch_input.removeClass('is-results'); 3816 } 3817 }; 3818 3819 var clearResults = function clearResults() { 3820 productsearch.output_container.empty().addClass('is-hidden'); 3821 $productsearch_input.removeClass('is-results'); 3822 productsearch.output_wrapper.addClass('is-hidden'); 3823 productsearch.extra_hits.addClass('is-hidden'); 3824 productsearch.no_hits.addClass('is-hidden'); 3825 }; 3826 3827 var displayEmptyResults = function displayEmptyResults() { 3828 productsearch.no_hits.removeClass('is-hidden'); 3829 productsearch.extra_hits.addClass('is-hidden'); 3830 productsearch.output_wrapper.removeClass('is-hidden'); 3831 }; 3832 3833 init(); 3834 }; 3835 3836 $.fn.productsearch = function (options) { 3837 return this.each(function () { 3838 if (undefined === $(this).data('productsearch')) { 3839 var plugin = new $.productsearch(this, options); 3840 $(this).data('productsearch', plugin); 3841 } 3842 }); 3843 }; 3844 })(jQuery); 3845 /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(2))) 3846 3847/***/ }, 3848 3849/***/ 212: 3850/***/ function(module, exports, __webpack_require__) { 3851 3852 /* WEBPACK VAR INJECTION */(function(jQuery) {'use strict'; 3853 3854 /*! 3855 * SmartMenus jQuery Plugin - v0.9.7 - August 25, 2014 3856 * http://www.smartmenus.org/ 3857 * 3858 * Copyright 2014 Vasil Dinkov, Vadikom Web Ltd. 3859 * http://vadikom.com 3860 * 3861 * Licensed MIT 3862 */ 3863 3864 (function ($) { 3865 3866 var menuTrees = [], 3867 IE = !!window.createPopup, 3868 // detect it for the iframe shim 3869 mouse = false, 3870 // optimize for touch by default - we will detect for mouse input 3871 mouseDetectionEnabled = false;
3872 3873 // Handle detection for mouse input (i.e. desktop browsers, tablets with a mouse, etc.) 3874 function initMouseDetection(disable) { 3875 var eNS = '.smartmenus_mouse'; 3876 if (!mouseDetectionEnabled && !disable) { 3877 // if we get two consecutive mousemoves within 2 pixels from each other and within 300ms, we assume a real mouse/cursor is present 3878 // in practice, this seems like impossible to trick unintentianally with a real mouse and a pretty safe detection on touch devices (even with older browsers that do not support touch events) 3879 var firstTime = true, 3880 lastMove = null; 3881 $(document).bind(getEventsNS([['mousemove', function (e) { 3882 var thisMove = { x: e.pageX, y: e.pageY, timeStamp: new Date().getTime() }; 3883 if (lastMove) { 3884 var deltaX = Math.abs(lastMove.x - thisMove.x), 3885 deltaY = Math.abs(lastMove.y - thisMove.y); 3886 if ((deltaX > 0 || deltaY > 0) && deltaX <= 2 && deltaY <= 2 && thisMove.timeStamp - lastMove.timeStamp <= 300) { 3887 mouse = true; 3888 // if this is the first check after page load, check if we are not over some item by chance and call the mouseenter handler if yes 3889 if (firstTime) { 3890 var $a = $(e.target).closest('a'); 3891 if ($a.is('a')) { 3892 $.each(menuTrees, function () { 3893 if ($.contains(this.$root[0], $a[0])) { 3894 this.itemEnter({ currentTarget: $a[0] }); 3895 return false; 3896 } 3897 }); 3898 } 3899 firstTime = false; 3900 } 3901 } 3902 } 3903 lastMove = thisMove; 3904 }], [touchEvents() ? 'touchstart' : 'pointerover pointermove pointerout MSPointerOver MSPointerMove MSPointerOut', function (e) { 3905 if (isTouchEvent(e.originalEvent)) { 3906 mouse = false; 3907 } 3908 }]], eNS)); 3909 mouseDetectionEnabled = true; 3910 } else if (mouseDetectionEnabled && disable) { 3911 $(document).unbind(eNS); 3912 mouseDetectionEnabled = false; 3913 } 3914 } 3915 3916 function isTouchEvent(e) { 3917 return !/^(4|mouse)$/.test(e.pointerType); 3918 } 3919 3920 // we use this just to choose between toucn and pointer events when we need to, not for touch screen detection 3921 function touchEvents() { 3922 return 'ontouchstart' in window; 3923 } 3924 3925 // returns a jQuery bind() ready object 3926 function getEventsNS(defArr, eNS) { 3927 if (!eNS) { 3928 eNS = ''; 3929 } 3930 var obj = {}; 3931 $.each(defArr, function (index, value) { 3932 obj[value[0].split(' ').join(eNS + ' ') + eNS] = value[1]; 3933 }); 3934 return obj; 3935 } 3936 3937 $.SmartMenus = function (elm, options) { 3938 this.$root = $(elm); 3939 this.opts = options; 3940 this.rootId = ''; // internal 3941 this.$subArrow = null; 3942 this.subMenus = []; // all sub menus in the tree (UL elms) in no particular order (only real - e.g. UL's in mega sub menus won't be counted) 3943 this.activatedItems = []; // stores last activated A's for each level 3944 this.visibleSubMenus = []; // stores visible sub menus UL's 3945 this.showTimeout = 0; 3946 this.hideTimeout = 0; 3947 this.scrollTimeout = 0; 3948 this.clickActivated = false; 3949 this.zIndexInc = 0; 3950 this.$firstLink = null; // we'll use these for some tests 3951 this.$firstSub = null; // at runtime so we'll cache them 3952 this.disabled = false; 3953 this.$disableOverlay = null; 3954 this.isTouchScrolling = false; 3955 this.init(); 3956 }; 3957 3958 $.extend($.SmartMenus, { 3959 hideAll: function hideAll() { 3960 $.each(menuTrees, function () { 3961 this.menuHideAll(); 3962 }); 3963 }, 3964 destroy: function destroy() { 3965 while (menuTrees.length) { 3966 menuTrees[0].destroy(); 3967 } 3968 initMouseDetection(true); 3969 }, 3970 prototype: { 3971 init: function init(refresh) { 3972 var self = this; 3973 3974 if (!refresh) { 3975 menuTrees.push(this); 3976 3977 this.rootId = (new Date().getTime() + Math.random() + '').replace(/\D/g, ''); 3978 3979 if (this.$root.hasClass('sm-rtl')) { 3980 this.opts.rightToLeftSubMenus = true; 3981 } 3982 3983 // init root (main menu) 3984 var eNS = '.smartmenus'; 3985 this.$root.data('smartmenus', this).attr('data-smartmenus-id', this.rootId).dataSM('level', 1).bind(getEventsNS([['mouseover focusin', $.proxy(this.rootOver, this)], ['mouseout focusout', $.proxy(this.rootOut, this)]], eNS)).delegate('a', getEventsNS([['mouseenter', $.proxy(this.itemEnter, this)], ['mouseleave', $.proxy(this.itemLeave, this)], ['mousedown', $.proxy(this.itemDown, this)], ['focus', $.proxy(this.itemFocus, this)], ['blur', $.proxy(this.itemBlur, this)], ['click', $.proxy(this.itemClick, this)], ['touchend', $.proxy(this.itemTouchEnd, this)]], eNS)); 3986 3987 // hide menus on tap or click outside the root UL 3988 eNS += this.rootId; 3989 if (this.opts.hideOnClick) { 3990 $(document).bind(getEventsNS([['touchstart', $.proxy(this.docTouchStart, this)], ['touchmove', $.proxy(this.docTouchMove, this)], ['touchend', $.proxy(this.docTouchEnd, this)], 3991 // for Opera Mobile < 11.5, webOS browser, etc. we'll check click too 3992 ['click', $.proxy(this.docClick, this)]], eNS)); 3993 } 3994 // hide sub menus on resize 3995 $(window).bind(getEventsNS([['resize orientationchange', $.proxy(this.winResize, this)]], eNS)); 3996 3997 if (this.opts.subIndicators) { 3998 this.$subArrow = $('<span/>').addClass('sub-arrow'); 3999 if (this.opts.subIndicatorsText) { 4000 this.$subArrow.html(this.opts.subIndicatorsText); 4001 } 4002 } 4003 4004 // make sure mouse detection is enabled 4005 initMouseDetection(); 4006 } 4007 4008 // init sub menus 4009 this.$firstSub = this.$root.find('ul').each(function () { 4010 self.menuInit($(this)); 4011 }).eq(0); 4012 4013 this.$firstLink = this.$root.find('a').eq(0); 4014 4015 // find current item 4016 if (this.opts.markCurrentItem) { 4017 var reDefaultDoc = /(index|default)\.[^#\?\/]*/i, 4018 reHash = /#.*/, 4019 locHref = window.location.href.replace(reDefaultDoc, ''), 4020 locHrefNoHash = locHref.replace(reHash, ''); 4021 this.$root.find('a').each(function () { 4022 var href = this.href.replace(reDefaultDoc, ''), 4023 $this = $(this); 4024 if (href == locHref || href == locHrefNoHash) { 4025 $this.addClass('current'); 4026 if (self.opts.markCurrentTree) { 4027 $this.parent().parentsUntil('[data-smartmenus-id]', 'li').children('a').addClass('current'); 4028 } 4029 } 4030 }); 4031 } 4032 }, 4033 destroy: function destroy() { 4034 this.menuHideAll(); 4035 var eNS = '.smartmenus'; 4036 this.$root.removeData('smartmenus').removeAttr('data-smartmenus-id').removeDataSM('level').unbind(eNS).undelegate(eNS); 4037 eNS += this.rootId; 4038 $(document).unbind(eNS); 4039 $(window).unbind(eNS); 4040 if (this.opts.subIndicators) { 4041 this.$subArrow = null; 4042 } 4043 var self = this; 4044 $.each(this.subMenus, function () { 4045 if (this.hasClass('mega-menu')) { 4046 this.find('ul').removeDataSM('in-mega'); 4047 } 4048 if (this.dataSM('shown-before')) { 4049 if (self.opts.subMenusMinWidth || self.opts.subMenusMaxWidth) { 4050 this.css({ width: '', minWidth: '', maxWidth: '' }).removeClass('sm-nowrap'); 4051 } 4052 if (this.dataSM('scroll-arrows')) { 4053 this.dataSM('scroll-arrows').remove(); 4054 } 4055 this.css({ zIndex: '', top: '', left: '', marginLeft: '', marginTop: '', display: '' }); 4056 } 4057 if (self.opts.subIndicators) { 4058 this.dataSM('parent-a').removeClass('has-submenu').children('span.sub-arrow').remove(); 4059 } 4060 this.removeDataSM('shown-before').removeDataSM('ie-shim').removeDataSM('scroll-arrows').removeDataSM('parent-a').removeDataSM('level').removeDataSM('beforefirstshowfired').parent().removeDataSM('sub'); 4061 }); 4062 if (this.opts.markCurrentItem) { 4063 this.$root.find('a.current').removeClass('current'); 4064 } 4065 this.$root = null; 4066 this.$firstLink = null; 4067 this.$firstSub = null; 4068 if (this.$disableOverlay) { 4069 this.$disableOverlay.remove(); 4070 this.$disableOverlay = null; 4071 } 4072 menuTrees.splice($.inArray(this, menuTrees), 1); 4073 }, 4074 disable: function disable(noOverlay) { 4075 if (!this.disabled) { 4076 this.menuHideAll(); 4077 // display overlay over the menu to prevent interaction 4078 if (!noOverlay && !this.opts.isPopup && this.$root.is(':visible')) { 4079 var pos = this.$root.offset(); 4080 this.$disableOverlay = $('<div class="sm-jquery-disable-overlay"/>').css({ 4081 position: 'absolute', 4082 top: pos.top, 4083 left: pos.left, 4084 width: this.$root.outerWidth(), 4085 height: this.$root.outerHeight(),
4086 zIndex: this.getStartZIndex(true), 4087 opacity: 0 4088 }).appendTo(document.body); 4089 } 4090 this.disabled = true; 4091 } 4092 }, 4093 docClick: function docClick(e) { 4094 if (this.isTouchScrolling) { 4095 this.isTouchScrolling = false; 4096 return; 4097 } 4098 // hide on any click outside the menu or on a menu link 4099 if (this.visibleSubMenus.length && !$.contains(this.$root[0], e.target) || $(e.target).is('a')) { 4100 this.menuHideAll(); 4101 } 4102 }, 4103 docTouchEnd: function docTouchEnd(e) { 4104 if (!this.lastTouch) { 4105 return; 4106 } 4107 if (this.visibleSubMenus.length && (this.lastTouch.x2 === undefined || this.lastTouch.x1 == this.lastTouch.x2) && (this.lastTouch.y2 === undefined || this.lastTouch.y1 == this.lastTouch.y2) && (!this.lastTouch.target || !$.contains(this.$root[0], this.lastTouch.target))) { 4108 if (this.hideTimeout) { 4109 clearTimeout(this.hideTimeout); 4110 this.hideTimeout = 0; 4111 } 4112 // hide with a delay to prevent triggering accidental unwanted click on some page element 4113 var self = this; 4114 this.hideTimeout = setTimeout(function () { 4115 self.menuHideAll(); 4116 }, 350); 4117 } 4118 this.lastTouch = null; 4119 }, 4120 docTouchMove: function docTouchMove(e) { 4121 if (!this.lastTouch) { 4122 return; 4123 } 4124 var touchPoint = e.originalEvent.touches[0]; 4125 this.lastTouch.x2 = touchPoint.pageX; 4126 this.lastTouch.y2 = touchPoint.pageY; 4127 }, 4128 docTouchStart: function docTouchStart(e) { 4129 var touchPoint = e.originalEvent.touches[0]; 4130 this.lastTouch = { x1: touchPoint.pageX, y1: touchPoint.pageY, target: touchPoint.target }; 4131 }, 4132 enable: function enable() { 4133 if (this.disabled) { 4134 if (this.$disableOverlay) { 4135 this.$disableOverlay.remove(); 4136 this.$disableOverlay = null; 4137 } 4138 this.disabled = false; 4139 } 4140 }, 4141 getClosestMenu: function getClosestMenu(elm) { 4142 var $closestMenu = $(elm).closest('ul'); 4143 while ($closestMenu.dataSM('in-mega')) { 4144 $closestMenu = $closestMenu.parent().closest('ul'); 4145 } 4146 return $closestMenu[0] || null; 4147 }, 4148 getHeight: function getHeight($elm) { 4149 return this.getOffset($elm, true); 4150 }, 4151 // returns precise width/height float values 4152 getOffset: function getOffset($elm, height) { 4153 var old; 4154 if ($elm.css('display') == 'none') { 4155 old = { position: $elm[0].style.position, visibility: $elm[0].style.visibility }; 4156 $elm.css({ position: 'absolute', visibility: 'hidden' }).show(); 4157 } 4158 var box = $elm[0].getBoundingClientRect && $elm[0].getBoundingClientRect(), 4159 val = box && (height ? box.height || box.bottom - box.top : box.width || box.right - box.left); 4160 if (!val && val !== 0) { 4161 val = height ? $elm[0].offsetHeight : $elm[0].offsetWidth; 4162 } 4163 if (old) { 4164 $elm.hide().css(old); 4165 } 4166 return val; 4167 }, 4168 getStartZIndex: function getStartZIndex(root) { 4169 var zIndex = parseInt(this[root ? '$root' : '$firstSub'].css('z-index')); 4170 if (!root && isNaN(zIndex)) { 4171 zIndex = parseInt(this.$root.css('z-index')); 4172 } 4173 return !isNaN(zIndex) ? zIndex : 1; 4174 }, 4175 getTouchPoint: function getTouchPoint(e) { 4176 return e.touches && e.touches[0] || e.changedTouches && e.changedTouches[0] || e; 4177 }, 4178 getViewport: function getViewport(height) { 4179 var name = height ? 'Height' : 'Width', 4180 val = document.documentElement['client' + name], 4181 val2 = window['inner' + name]; 4182 if (val2) { 4183 val = Math.min(val, val2); 4184 } 4185 return val; 4186 }, 4187 getViewportHeight: function getViewportHeight() { 4188 return this.getViewport(true); 4189 }, 4190 getViewportWidth: function getViewportWidth() { 4191 return this.getViewport(); 4192 }, 4193 getWidth: function getWidth($elm) { 4194 return this.getOffset($elm); 4195 }, 4196 handleEvents: function handleEvents() { 4197 return !this.disabled && this.isCSSOn(); 4198 }, 4199 handleItemEvents: function handleItemEvents($a) { 4200 return this.handleEvents() && !this.isLinkInMegaMenu($a); 4201 }, 4202 isCollapsible: function isCollapsible() { 4203 return this.$firstSub.css('position') == 'static'; 4204 }, 4205 isCSSOn: function isCSSOn() { 4206 return this.$firstLink.css('display') == 'block'; 4207 }, 4208 isFixed: function isFixed() { 4209 var isFixed = this.$root.css('position') == 'fixed'; 4210 if (!isFixed) { 4211 this.$root.parentsUntil('body').each(function () { 4212 if ($(this).css('position') == 'fixed') { 4213 isFixed = true; 4214 return false;
4215 } 4216 }); 4217 } 4218 return isFixed; 4219 }, 4220 isLinkInMegaMenu: function isLinkInMegaMenu($a) { 4221 return !$a.parent().parent().dataSM('level'); 4222 }, 4223 isTouchMode: function isTouchMode() { 4224 return !mouse || this.isCollapsible(); 4225 }, 4226 itemActivate: function itemActivate($a) { 4227 var $li = $a.parent(), 4228 $ul = $li.parent(), 4229 level = $ul.dataSM('level'); 4230 // if for some reason the parent item is not activated (e.g. this is an API call to activate the item), activate all parent items first 4231 if (level > 1 && (!this.activatedItems[level - 2] || this.activatedItems[level - 2][0] != $ul.dataSM('parent-a')[0])) { 4232 var self = this; 4233 $($ul.parentsUntil('[data-smartmenus-id]', 'ul').get().reverse()).add($ul).each(function () { 4234 self.itemActivate($(this).dataSM('parent-a')); 4235 }); 4236 } 4237 // hide any visible deeper level sub menus 4238 if (this.visibleSubMenus.length > level) { 4239 this.menuHideSubMenus(!this.activatedItems[level - 1] || this.activatedItems[level - 1][0] != $a[0] ? level - 1 : level); 4240 } 4241 // save new active item and sub menu for this level 4242 this.activatedItems[level - 1] = $a; 4243 this.visibleSubMenus[level - 1] = $ul; 4244 if (this.$root.triggerHandler('activate.smapi', $a[0]) === false) { 4245 return; 4246 } 4247 // show the sub menu if this item has one 4248 var $sub = $li.dataSM('sub'); 4249 if ($sub && (this.isTouchMode() || !this.opts.showOnClick || this.clickActivated)) { 4250 this.menuShow($sub); 4251 } 4252 }, 4253 itemBlur: function itemBlur(e) { 4254 var $a = $(e.currentTarget); 4255 if (!this.handleItemEvents($a)) { 4256 return; 4257 } 4258 this.$root.triggerHandler('blur.smapi', $a[0]); 4259 }, 4260 itemClick: function itemClick(e) { 4261 if (this.isTouchScrolling) { 4262 this.isTouchScrolling = false; 4263 e.stopPropagation(); 4264 return false; 4265 } 4266 var $a = $(e.currentTarget); 4267 if (!this.handleItemEvents($a)) { 4268 return; 4269 } 4270 $a.removeDataSM('mousedown'); 4271 if (this.$root.triggerHandler('click.smapi', $a[0]) === false) { 4272 return false; 4273 } 4274 var $sub = $a.parent().dataSM('sub'); 4275 if (this.isTouchMode()) { 4276 // undo fix: prevent the address bar on iPhone from sliding down when expanding a sub menu 4277 if ($a.dataSM('href')) { 4278 $a.attr('href', $a.dataSM('href')).removeDataSM('href'); 4279 } 4280 // if the sub is not visible 4281 if ($sub && (!$sub.dataSM('shown-before') || !$sub.is(':visible'))) { 4282 // try to activate the item and show the sub 4283 this.itemActivate($a); 4284 // if "itemActivate" showed the sub, prevent the click so that the link is not loaded 4285 // if it couldn't show it, then the sub menus are disabled with an !important declaration (e.g. via mobile styles) so let the link get loaded 4286 if ($sub.is(':visible')) { 4287 return false; 4288 } 4289 } 4290 } else if (this.opts.showOnClick && $a.parent().parent().dataSM('level') == 1 && $sub) { 4291 this.clickActivated = true; 4292 this.menuShow($sub); 4293 return false; 4294 } 4295 if ($a.hasClass('disabled')) { 4296 return false; 4297 } 4298 if (this.$root.triggerHandler('select.smapi', $a[0]) === false) { 4299 return false; 4300 } 4301 }, 4302 itemDown: function itemDown(e) { 4303 var $a = $(e.currentTarget); 4304 if (!this.handleItemEvents($a)) { 4305 return; 4306 } 4307 $a.dataSM('mousedown', true); 4308 }, 4309 itemEnter: function itemEnter(e) { 4310 var $a = $(e.currentTarget); 4311 if (!this.handleItemEvents($a)) { 4312 return; 4313 } 4314 if (!this.isTouchMode()) { 4315 if (this.showTimeout) { 4316 clearTimeout(this.showTimeout); 4317 this.showTimeout = 0; 4318 } 4319 var self = this; 4320 this.showTimeout = setTimeout(function () { 4321 self.itemActivate($a); 4322 }, this.opts.showOnClick && $a.parent().parent().dataSM('level') == 1 ? 1 : this.opts.showTimeout); 4323 } 4324 this.$root.triggerHandler('mouseenter.smapi', $a[0]); 4325 }, 4326 itemFocus: function itemFocus(e) { 4327 var $a = $(e.currentTarget); 4328 if (!this.handleItemEvents($a)) { 4329 return; 4330 } 4331 // fix (the mousedown check): in some browsers a tap/click produces consecutive focus + click events so we don't need to activate the item on focus 4332 if ((!this.isTouchMode() || !$a.dataSM('mousedown')) && (!this.activatedItems.length || this.activatedItems[this.activatedItems.length - 1][0] != $a[0])) { 4333 this.itemActivate($a); 4334 } 4335 this.$root.triggerHandler('focus.smapi', $a[0]); 4336 }, 4337 itemLeave: function itemLeave(e) { 4338 var $a = $(e.currentTarget); 4339 if (!this.handleItemEvents($a)) { 4340 return; 4341 } 4342 if (!this.isTouchMode()) { 4343 if ($a[0].blur) { 4344 $a[0].blur(); 4345 } 4346 if (this.showTimeout) { 4347 clearTimeout(this.showTimeout); 4348 this.showTimeout = 0; 4349 } 4350 } 4351 $a.removeDataSM('mousedown');
4352 this.$root.triggerHandler('mouseleave.smapi', $a[0]); 4353 }, 4354 itemTouchEnd: function itemTouchEnd(e) { 4355 var $a = $(e.currentTarget); 4356 if (!this.handleItemEvents($a)) { 4357 return; 4358 } 4359 // prevent the address bar on iPhone from sliding down when expanding a sub menu 4360 var $sub = $a.parent().dataSM('sub'); 4361 if ($a.attr('href').charAt(0) !== '#' && $sub && (!$sub.dataSM('shown-before') || !$sub.is(':visible'))) { 4362 $a.dataSM('href', $a.attr('href')); 4363 $a.attr('href', '#'); 4364 } 4365 }, 4366 menuFixLayout: function menuFixLayout($ul) { 4367 // fixes a menu that is being shown for the first time 4368 if (!$ul.dataSM('shown-before')) { 4369 $ul.hide().dataSM('shown-before', true); 4370 } 4371 }, 4372 menuHide: function menuHide($sub) { 4373 if (this.$root.triggerHandler('beforehide.smapi', $sub[0]) === false) { 4374 return; 4375 } 4376 $sub.stop(true, true); 4377 if ($sub.is(':visible')) { 4378 var complete = function complete() { 4379 // unset z-index 4380 $sub.css('z-index', ''); 4381 }; 4382 // if sub is collapsible (mobile view) 4383 if (this.isCollapsible()) { 4384 if (this.opts.collapsibleHideFunction) { 4385 this.opts.collapsibleHideFunction.call(this, $sub, complete); 4386 } else { 4387 $sub.hide(this.opts.collapsibleHideDuration, complete); 4388 } 4389 } else { 4390 if (this.opts.hideFunction) { 4391 this.opts.hideFunction.call(this, $sub, complete); 4392 } else { 4393 $sub.hide(this.opts.hideDuration, complete); 4394 } 4395 } 4396 // remove IE iframe shim 4397 if ($sub.dataSM('ie-shim')) { 4398 $sub.dataSM('ie-shim').remove(); 4399 } 4400 // deactivate scrolling if it is activated for this sub 4401 if ($sub.dataSM('scroll')) { 4402 this.menuScrollStop($sub); 4403 $sub.css({ 'touch-action': '', '-ms-touch-action': '' }).unbind('.smartmenus_scroll').removeDataSM('scroll').dataSM('scroll-arrows').hide(); 4404 } 4405 // unhighlight parent item 4406 $sub.dataSM('parent-a').removeClass('highlighted'); 4407 var level = $sub.dataSM('level'); 4408 this.activatedItems.splice(level - 1, 1); 4409 this.visibleSubMenus.splice(level - 1, 1); 4410 this.$root.triggerHandler('hide.smapi', $sub[0]); 4411 } 4412 }, 4413 menuHideAll: function menuHideAll() { 4414 if (this.showTimeout) { 4415 clearTimeout(this.showTimeout); 4416 this.showTimeout = 0; 4417 } 4418 // hide all subs 4419 this.menuHideSubMenus(); 4420 // hide root if it's popup 4421 if (this.opts.isPopup) { 4422 this.$root.stop(true, true); 4423 if (this.$root.is(':visible')) { 4424 if (this.opts.hideFunction) { 4425 this.opts.hideFunction.call(this, this.$root); 4426 } else { 4427 this.$root.hide(this.opts.hideDuration); 4428 } 4429 // remove IE iframe shim 4430 if (this.$root.dataSM('ie-shim')) { 4431 this.$root.dataSM('ie-shim').remove(); 4432 } 4433 } 4434 } 4435 this.activatedItems = []; 4436 this.visibleSubMenus = []; 4437 this.clickActivated = false; 4438 // reset z-index increment 4439 this.zIndexInc = 0; 4440 }, 4441 menuHideSubMenus: function menuHideSubMenus(level) { 4442 if (!level) level = 0; 4443 for (var i = this.visibleSubMenus.length - 1; i > level; i--) { 4444 this.menuHide(this.visibleSubMenus[i]); 4445 } 4446 }, 4447 menuIframeShim: function menuIframeShim($ul) { 4448 // create iframe shim for the menu 4449 if (IE && this.opts.overlapControlsInIE && !$ul.dataSM('ie-shim')) { 4450 $ul.dataSM('ie-shim', $('<iframe/>').attr({ src: 'javascript:0', tabindex: -9 }).css({ position: 'absolute', top: 'auto', left: '0', opacity: 0, border: '0' })); 4451 } 4452 }, 4453 menuInit: function menuInit($ul) { 4454 if (!$ul.dataSM('in-mega')) { 4455 this.subMenus.push($ul); 4456 // mark UL's in mega drop downs (if any) so we can neglect them 4457 if ($ul.hasClass('mega-menu')) { 4458 $ul.find('ul').dataSM('in-mega', true); 4459 } 4460 // get level (much faster than, for example, using parentsUntil) 4461 var level = 2, 4462 par = $ul[0]; 4463 while ((par = par.parentNode.parentNode) != this.$root[0]) { 4464 level++; 4465 } 4466 // cache stuff 4467 $ul.dataSM('parent-a', $ul.prevAll('a').eq(-1)).dataSM('level', level).parent().dataSM('sub', $ul); 4468 // add sub indicator to parent item 4469 if (this.opts.subIndicators) { 4470 $ul.dataSM('parent-a').addClass('has-submenu')[this.opts.subIndicatorsPos](this.$subArrow.clone()); 4471 } 4472 } 4473 }, 4474 menuPosition: function menuPosition($sub) { 4475 var $a = $sub.dataSM('parent-a'), 4476 $ul = $sub.parent().parent(), 4477 level = $sub.dataSM('level'), 4478 subW = this.getWidth($sub), 4479 subH = this.getHeight($sub), 4480 itemOffset = $a.offset(), 4481 itemX = itemOffset.left, 4482 itemY = itemOffset.top, 4483 itemW = this.getWidth($a), 4484 itemH = this.getHeight($a), 4485 $win = $(window), 4486 winX = $win.scrollLeft(), 4487 winY = $win.scrollTop(), 4488 winW = this.getViewportWidth(),
4489 winH = this.getViewportHeight(), 4490 horizontalParent = $ul.hasClass('sm') && !$ul.hasClass('sm-vertical'), 4491 subOffsetX = level == 2 ? this.opts.mainMenuSubOffsetX : this.opts.subMenusSubOffsetX, 4492 subOffsetY = level == 2 ? this.opts.mainMenuSubOffsetY : this.opts.subMenusSubOffsetY, 4493 x, 4494 y; 4495 if (horizontalParent) { 4496 x = this.opts.rightToLeftSubMenus ? itemW - subW - subOffsetX : subOffsetX; 4497 y = this.opts.bottomToTopSubMenus ? -subH - subOffsetY : itemH + subOffsetY; 4498 } else { 4499 x = this.opts.rightToLeftSubMenus ? subOffsetX - subW : itemW - subOffsetX; 4500 y = this.opts.bottomToTopSubMenus ? itemH - subOffsetY - subH : subOffsetY; 4501 } 4502 if (this.opts.keepInViewport && !this.isCollapsible()) { 4503 var absX = itemX + x, 4504 absY = itemY + y; 4505 if (this.opts.rightToLeftSubMenus && absX < winX) { 4506 x = horizontalParent ? winX - absX + x : itemW - subOffsetX; 4507 } else if (!this.opts.rightToLeftSubMenus && absX + subW > winX + winW) { 4508 x = horizontalParent ? winX + winW - subW - absX + x : subOffsetX - subW; 4509 } 4510 if (!horizontalParent) { 4511 if (subH < winH && absY + subH > winY + winH) { 4512 y += winY + winH - subH - absY; 4513 } else if (subH >= winH || absY < winY) { 4514 y += winY - absY; 4515 } 4516 } 4517 // do we need scrolling? 4518 // 0.49 used for better precision when dealing with float values 4519 if (horizontalParent && (absY + subH > winY + winH + 0.49 || absY < winY) || !horizontalParent && subH > winH + 0.49) { 4520 var self = this; 4521 if (!$sub.dataSM('scroll-arrows')) { 4522 $sub.dataSM('scroll-arrows', $([$('<span class="scroll-up"><span class="scroll-up-arrow"></span></span>')[0], $('<span class="scroll-down"><span class="scroll-down-arrow"></span></span>')[0]]).bind({ 4523 mouseenter: function mouseenter() { 4524 $sub.dataSM('scroll').up = $(this).hasClass('scroll-up'); 4525 self.menuScroll($sub); 4526 }, 4527 mouseleave: function mouseleave(e) { 4528 self.menuScrollStop($sub); 4529 self.menuScrollOut($sub, e); 4530 }, 4531 'mousewheel DOMMouseScroll': function mousewheelDOMMouseScroll(e) { 4532 e.preventDefault(); 4533 } 4534 }).insertAfter($sub)); 4535 } 4536 // bind scroll events and save scroll data for this sub 4537 var eNS = '.smartmenus_scroll'; 4538 $sub.dataSM('scroll', { 4539 step: 1, 4540 // cache stuff for faster recalcs later 4541 itemH: itemH, 4542 subH: subH, 4543 arrowDownH: this.getHeight($sub.dataSM('scroll-arrows').eq(1)) 4544 }).bind(getEventsNS([['mouseover', function (e) { 4545 self.menuScrollOver($sub, e); 4546 }], ['mouseout', function (e) { 4547 self.menuScrollOut($sub, e); 4548 }], ['mousewheel DOMMouseScroll', function (e) { 4549 self.menuScrollMousewheel($sub, e); 4550 }]], eNS)).dataSM('scroll-arrows').css({ top: 'auto', left: '0', marginLeft: x + (parseInt($sub.css('border-left-width')) || 0), width: subW - (parseInt($sub.css('border-left-width')) || 0) - (parseInt($sub.css('border-right-width')) || 0), zIndex: $sub.css('z-index') }).eq(horizontalParent && this.opts.bottomToTopSubMenus ? 0 : 1).show(); 4551 // when a menu tree is fixed positioned we allow scrolling via touch too 4552 // since there is no other way to access such long sub menus if no mouse is present 4553 if (this.isFixed()) { 4554 $sub.css({ 'touch-action': 'none', '-ms-touch-action': 'none' }).bind(getEventsNS([[touchEvents() ? 'touchstart touchmove touchend' : 'pointerdown pointermove pointerup MSPointerDown MSPointerMove MSPointerUp', function (e) { 4555 self.menuScrollTouch($sub, e); 4556 }]], eNS)); 4557 } 4558 } 4559 } 4560 $sub.css({ top: 'auto', left: '0', marginLeft: x, marginTop: y - itemH }); 4561 // IE iframe shim 4562 this.menuIframeShim($sub); 4563 if ($sub.dataSM('ie-shim')) { 4564 $sub.dataSM('ie-shim').css({ zIndex: $sub.css('z-index'), width: subW, height: subH, marginLeft: x, marginTop: y - itemH }); 4565 } 4566 }, 4567 menuScroll: function menuScroll($sub, once, step) { 4568 var data = $sub.dataSM('scroll'), 4569 $arrows = $sub.dataSM('scroll-arrows'), 4570 y = parseFloat($sub.css('margin-top')), 4571 end = data.up ? data.upEnd : data.downEnd, 4572 diff; 4573 if (!once && data.velocity) { 4574 data.velocity *= 0.9; 4575 diff = data.velocity; 4576 if (diff < 0.5) { 4577 this.menuScrollStop($sub); 4578 return; 4579 } 4580 } else { 4581 diff = step || (once || !this.opts.scrollAccelerate ? this.opts.scrollStep : Math.floor(data.step)); 4582 } 4583 // hide any visible deeper level sub menus 4584 var level = $sub.dataSM('level'); 4585 if (this.visibleSubMenus.length > level) {
4586 this.menuHideSubMenus(level - 1); 4587 } 4588 var newY = data.up && end <= y || !data.up && end >= y ? y : Math.abs(end - y) > diff ? y + (data.up ? diff : -diff) : end; 4589 $sub.add($sub.dataSM('ie-shim')).css('margin-top', newY); 4590 // show opposite arrow if appropriate 4591 if (mouse && (data.up && newY > data.downEnd || !data.up && newY < data.upEnd)) { 4592 $arrows.eq(data.up ? 1 : 0).show(); 4593 } 4594 // if we've reached the end 4595 if (newY == end) { 4596 if (mouse) { 4597 $arrows.eq(data.up ? 0 : 1).hide(); 4598 } 4599 this.menuScrollStop($sub); 4600 } else if (!once) { 4601 if (this.opts.scrollAccelerate && data.step < this.opts.scrollStep) { 4602 data.step += 0.5; 4603 } 4604 var self = this; 4605 this.scrollTimeout = setTimeout(function () { 4606 self.menuScroll($sub); 4607 }, this.opts.scrollInterval); 4608 } 4609 }, 4610 menuScrollMousewheel: function menuScrollMousewheel($sub, e) { 4611 if (this.getClosestMenu(e.target) == $sub[0]) { 4612 e = e.originalEvent; 4613 var up = (e.wheelDelta || -e.detail) > 0; 4614 if ($sub.dataSM('scroll-arrows').eq(up ? 0 : 1).is(':visible')) { 4615 $sub.dataSM('scroll').up = up; 4616 this.menuScroll($sub, true); 4617 } 4618 } 4619 e.preventDefault(); 4620 }, 4621 menuScrollOut: function menuScrollOut($sub, e) { 4622 if (mouse) { 4623 if (!/^scroll-(up|down)/.test((e.relatedTarget || '').className) && ($sub[0] != e.relatedTarget && !$.contains($sub[0], e.relatedTarget) || this.getClosestMenu(e.relatedTarget) != $sub[0])) { 4624 $sub.dataSM('scroll-arrows').css('visibility', 'hidden'); 4625 } 4626 } 4627 }, 4628 menuScrollOver: function menuScrollOver($sub, e) { 4629 if (mouse) { 4630 if (!/^scroll-(up|down)/.test(e.target.className) && this.getClosestMenu(e.target) == $sub[0]) { 4631 this.menuScrollRefreshData($sub); 4632 var data = $sub.dataSM('scroll'); 4633 $sub.dataSM('scroll-arrows').eq(0).css('margin-top', data.upEnd).end().eq(1).css('margin-top', data.downEnd + data.subH - data.arrowDownH).end().css('visibility', 'visible'); 4634 } 4635 } 4636 }, 4637 menuScrollRefreshData: function menuScrollRefreshData($sub) { 4638 var data = $sub.dataSM('scroll'), 4639 $win = $(window), 4640 vportY = $win.scrollTop() - $sub.dataSM('parent-a').offset().top - data.itemH; 4641 $.extend(data, { 4642 upEnd: vportY, 4643 downEnd: vportY + this.getViewportHeight() - data.subH 4644 }); 4645 }, 4646 menuScrollStop: function menuScrollStop($sub) { 4647 if (this.scrollTimeout) { 4648 clearTimeout(this.scrollTimeout); 4649 this.scrollTimeout = 0; 4650 $.extend($sub.dataSM('scroll'), { 4651 step: 1, 4652 velocity: 0 4653 }); 4654 return true; 4655 } 4656 }, 4657 menuScrollTouch: function menuScrollTouch($sub, e) { 4658 e = e.originalEvent; 4659 if (isTouchEvent(e)) { 4660 var touchPoint = this.getTouchPoint(e); 4661 // neglect event if we touched a visible deeper level sub menu 4662 if (this.getClosestMenu(touchPoint.target) == $sub[0]) { 4663 var data = $sub.dataSM('scroll'); 4664 if (/(start|down)$/i.test(e.type)) { 4665 if (this.menuScrollStop($sub)) { 4666 // if we were scrolling, just stop and don't activate any link on the first touch 4667 e.preventDefault(); 4668 this.isTouchScrolling = true; 4669 } else { 4670 this.isTouchScrolling = false; 4671 } 4672 // update scroll data since the user might have zoomed, etc. 4673 this.menuScrollRefreshData($sub); 4674 // extend it with the touch properties 4675 $.extend(data, { 4676 touchY: touchPoint.pageY, 4677 touchTimestamp: e.timeStamp, 4678 velocity: 0 4679 }); 4680 } else if (/move$/i.test(e.type)) { 4681 var prevY = data.touchY; 4682 if (prevY !== undefined && prevY != touchPoint.pageY) { 4683 this.isTouchScrolling = true; 4684 $.extend(data, { 4685 up: prevY < touchPoint.pageY, 4686 touchY: touchPoint.pageY, 4687 touchTimestamp: e.timeStamp, 4688 velocity: data.velocity + Math.abs(touchPoint.pageY - prevY) * 0.5 4689 }); 4690 this.menuScroll($sub, true, Math.abs(data.touchY - prevY)); 4691 } 4692 e.preventDefault(); 4693 } else { 4694 // touchend/pointerup 4695 if (data.touchY !== undefined) { 4696 // check if we need to scroll 4697 if (e.timeStamp - data.touchTimestamp < 120 && data.velocity > 0) { 4698 data.velocity *= 0.5; 4699 this.menuScrollStop($sub); 4700 this.menuScroll($sub); 4701 e.preventDefault(); 4702 } 4703 delete data.touchY; 4704 } 4705 } 4706 } 4707 } 4708 }, 4709 menuShow: function menuShow($sub) { 4710 if (!$sub.dataSM('beforefirstshowfired')) { 4711 $sub.dataSM('beforefirstshowfired', true); 4712 if (this.$root.triggerHandler('beforefirstshow.smapi', $sub[0]) === false) { 4713 return; 4714 } 4715 } 4716 if (this.$root.triggerHandler('beforeshow.smapi', $sub[0]) === false) { 4717 return; 4718 } 4719 this.menuFixLayout($sub); 4720 $sub.stop(true, true); 4721 if (!$sub.is(':visible')) { 4722 // set z-index 4723 $sub.css('z-index', this.zIndexInc = (this.zIndexInc || this.get
4723StartZIndex()) + 1); 4724 // highlight parent item 4725 if (this.opts.keepHighlighted || this.isCollapsible()) { 4726 $sub.dataSM('parent-a').addClass('highlighted'); 4727 } 4728 // min/max-width fix - no way to rely purely on CSS as all UL's are nested 4729 if (this.opts.subMenusMinWidth || this.opts.subMenusMaxWidth) { 4730 $sub.css({ width: 'auto', minWidth: '', maxWidth: '' }).addClass('sm-nowrap'); 4731 if (this.opts.subMenusMinWidth) { 4732 $sub.css('min-width', this.opts.subMenusMinWidth); 4733 } 4734 if (this.opts.subMenusMaxWidth) { 4735 var noMaxWidth = this.getWidth($sub); 4736 $sub.css('max-width', this.opts.subMenusMaxWidth); 4737 if (noMaxWidth > this.getWidth($sub)) { 4738 $sub.removeClass('sm-nowrap').css('width', this.opts.subMenusMaxWidth); 4739 } 4740 } 4741 } 4742 this.menuPosition($sub); 4743 // insert IE iframe shim 4744 if ($sub.dataSM('ie-shim')) { 4745 $sub.dataSM('ie-shim').insertBefore($sub); 4746 } 4747 var complete = function complete() { 4748 // fix: "overflow: hidden;" is not reset on animation complete in jQuery < 1.9.0 in Chrome when global "box-sizing: border-box;" is used 4749 $sub.css('overflow', ''); 4750 }; 4751 // if sub is collapsible (mobile view) 4752 if (this.isCollapsible()) { 4753 if (this.opts.collapsibleShowFunction) { 4754 this.opts.collapsibleShowFunction.call(this, $sub, complete); 4755 } else { 4756 $sub.show(this.opts.collapsibleShowDuration, complete); 4757 } 4758 } else { 4759 if (this.opts.showFunction) { 4760 this.opts.showFunction.call(this, $sub, complete); 4761 } else { 4762 $sub.show(this.opts.showDuration, complete); 4763 } 4764 } 4765 // save new sub menu for this level 4766 this.visibleSubMenus[$sub.dataSM('level') - 1] = $sub; 4767 this.$root.triggerHandler('show.smapi', $sub[0]); 4768 } 4769 }, 4770 popupHide: function popupHide(noHideTimeout) { 4771 if (this.hideTimeout) { 4772 clearTimeout(this.hideTimeout); 4773 this.hideTimeout = 0; 4774 } 4775 var self = this; 4776 this.hideTimeout = setTimeout(function () { 4777 self.menuHideAll(); 4778 }, noHideTimeout ? 1 : this.opts.hideTimeout); 4779 }, 4780 popupShow: function popupShow(left, top) { 4781 if (!this.opts.isPopup) { 4782 alert('SmartMenus jQuery Error:\n\nIf you want to show this menu via the "popupShow" method, set the isPopup:true option.'); 4783 return; 4784 } 4785 if (this.hideTimeout) { 4786 clearTimeout(this.hideTimeout); 4787 this.hideTimeout = 0; 4788 } 4789 this.menuFixLayout(this.$root); 4790 this.$root.stop(true, true); 4791 if (!this.$root.is(':visible')) { 4792 this.$root.css({ left: left, top: top }); 4793 // IE iframe shim 4794 this.menuIframeShim(this.$root); 4795 if (this.$root.dataSM('ie-shim')) { 4796 this.$root.dataSM('ie-shim').css({ zIndex: this.$root.css('z-index'), width: this.getWidth(this.$root), height: this.getHeight(this.$root), left: left, top: top }).insertBefore(this.$root); 4797 } 4798 // show menu 4799 var self = this, 4800 complete = function complete() { 4801 self.$root.css('overflow', ''); 4802 }; 4803 if (this.opts.showFunction) { 4804 this.opts.showFunction.call(this, this.$root, complete); 4805 } else { 4806 this.$root.show(this.opts.showDuration, complete); 4807 } 4808 this.visibleSubMenus[0] = this.$root; 4809 } 4810 }, 4811 refresh: function refresh() { 4812 this.menuHideAll(); 4813 this.$root.find('ul').each(function () { 4814 var $this = $(this); 4815 if ($this.dataSM('scroll-arrows')) { 4816 $this.dataSM('scroll-arrows').remove(); 4817 } 4818 }).removeDataSM('in-mega').removeDataSM('shown-before').removeDataSM('ie-shim').removeDataSM('scroll-arrows').removeDataSM('parent-a').removeDataSM('level').removeDataSM('beforefirstshowfired'); 4819 this.$root.find('a.has-submenu').removeClass('has-submenu').parent().removeDataSM('sub'); 4820 if (this.opts.subIndicators) { 4821 this.$root.find('span.sub-arrow').remove(); 4822 } 4823 if (this.opts.markCurrentItem) { 4824 this.$root.find('a.current').removeClass('current'); 4825 } 4826 this.subMenus = []; 4827 this.init(true); 4828 }, 4829 rootOut: function rootOut(e) { 4830 if (!this.handleEvents() || this.isTouchMode() || e.target == this.$root[0]) { 4831 return; 4832 } 4833 if (this.hideTimeout) { 4834 clearTimeout(this.hideTimeout); 4835 this.hideTimeout = 0; 4836 } 4837 if (!this.opts.showOnClick || !this.opts.hideOnClick) { 4838 var self = this; 4839 this.hideTimeout = setTimeout(function () { 4840 self.menuHideAll(); 4841 }, this.opts.hideTimeout); 4842 } 4843 }, 4844 rootOver: function rootOver(e) { 4845 if (!this.handleEvents() || this.isTouchMode() || e.target == this.$root[0]) { 4846 return; 4847 } 4848 if (this.hideTimeout) { 4849 clearTimeout(this.hideTimeout); 4850 this.hideTimeout = 0; 4851 } 4852 }, 4853 winResize: function winResize(e) { 4854 if (!this.handleEvents()) { 4855 // we still need to resize the disable overlay if it's visible 4856 if (this.$disableOverlay) { 4857 var pos = this.$root.offset(); 4858 this.$disableOverlay.css({ 4859 top: pos.top, 4860 left: pos.left, 4861 width: this.$root.outerWidth(), 4862 height: this.$root.outerHeight() 4863 }); 4864 } 4865 return; 4866 } 4867 // hide sub menus on resize - on mobile do it only on orientation change 4868 if (!this.isCollapsible() && (!('onorientationchange' in window) || e.type == 'orientationchange')) { 4869 if (this.activatedItems.length) { 4870 this.activatedItems[this.activatedItems.length - 1][0].blur(); 4871 } 4872 this.menuHideAll(); 4873 } 4874 } 4875 } 4876 }); 4877 4878 $.fn.dataSM = function (key, val) { 4879 if (val) { 4880 return this.data(key + '_smartmenus', val); 4881 } 4882 return this.data(key + '_smartmenus'); 4883 }; 4884 4885 $.fn.removeDataSM = function (key) { 4886 return this.removeData(key + '_smartmenus'); 4887 }; 4888 4889 $.fn.smartmenus = function (options) { 4890 if (typeof options == 'string') { 4891 var args = arguments, 4892 method = options; 4893 Array.prototype.shift.call(args); 4894 return this.each(function () { 4895 var smartmenus = $(this).data('smartmenus'); 4896 if (smartmenus && smartmenus[method]) { 4897 smartmenus[method].apply(smartmenus, args); 4898 } 4899 }); 4900 } 4901 var opts = $.extend({}, $.fn.smartmenus.defaults, options); 4902 return this.each(function () { 4903 new $.SmartMenus(this, opts); 4904 }); 4905 }; 4906 4907 // default settings 4908 $.fn.smartmenus.defaults = { 4909 isPopup: false, // is this a popup menu (can be shown via the popupS
4909how/popupHide methods) or a permanent menu bar 4910 mainMenuSubOffsetX: 0, // pixels offset from default position 4911 mainMenuSubOffsetY: 0, // pixels offset from default position 4912 subMenusSubOffsetX: 0, // pixels offset from default position 4913 subMenusSubOffsetY: 0, // pixels offset from default position 4914 subMenusMinWidth: '10em', // min-width for the sub menus (any CSS unit) - if set, the fixed width set in CSS will be ignored 4915 subMenusMaxWidth: '20em', // max-width for the sub menus (any CSS unit) - if set, the fixed width set in CSS will be ignored 4916 subIndicators: true, // create sub menu indicators - creates a SPAN and inserts it in the A 4917 subIndicatorsPos: 'prepend', // position of the SPAN relative to the menu item content ('prepend', 'append') 4918 subIndicatorsText: '+', // [optionally] add text in the SPAN (e.g. '+') (you may want to check the CSS for the sub indicators too) 4919 scrollStep: 30, // pixels step when scrolling long sub menus that do not fit in the viewport height 4920 scrollInterval: 30, // interval between each scrolling step 4921 scrollAccelerate: true, // accelerate scrolling or use a fixed step 4922 showTimeout: 250, // timeout before showing the sub menus 4923 hideTimeout: 500, // timeout before hiding the sub menus 4924 showDuration: 0, // duration for show animation - set to 0 for no animation - matters only if showFunction:null 4925 showFunction: null, // custom function to use when showing a sub menu (the default is the jQuery 'show') 4926 // don't forget to call complete() at the end of whatever you do 4927 // e.g.: function($ul, complete) { $ul.fadeIn(250, complete); } 4928 hideDuration: 0, // duration for hide animation - set to 0 for no animation - matters only if hideFunction:null 4929 hideFunction: function hideFunction($ul, complete) { 4930 $ul.fadeOut(200, complete); 4931 }, // custom function to use when hiding a sub menu (the default is the jQuery 'hide') 4932 // don't forget to call complete() at the end of whatever you do 4933 // e.g.: function($ul, complete) { $ul.fadeOut(250, complete); } 4934 collapsibleShowDuration: 0, // duration for show animation for collapsible sub menus - matters only if collapsibleShowFunction:null 4935 collapsibleShowFunction: function collapsibleShowFunction($ul, complete) { 4936 $ul.slideDown(200, complete); 4937 }, // custom function to use when showing a collapsible sub menu 4938 // (i.e. when mobile styles are used to make the sub menus collapsible) 4939 collapsibleHideDuration: 0, // duration for hide animation for collapsible sub menus - matters only if collapsibleHideFunction:null 4940 collapsibleHideFunction: function collapsibleHideFunction($ul, complete) { 4941 $ul.slideUp(200, complete); 4942 }, // custom function to use when hiding a collapsible sub menu 4943 // (i.e. when mobile styles are used to make the sub menus collapsible) 4944 showOnClick: false, // show the first-level sub menus onclick instead of onmouseover (matters only for mouse input) 4945 hideOnClick: true, // hide the sub menus on click/tap anywhere on the page 4946 keepInViewport: true, // reposition the sub menus if needed to make sure they always appear inside the viewport 4947 keepHighlighted: true, // keep all ancestor items of the current sub menu highlighted (adds the 'highlighted' class to the A's) 4948 markCurrentItem: false, // automatically add the 'current' class to the A element of the item linking to the current URL 4949 markCurrentTree: true, // add the 'current' class also to the A elements of all ancestor items of the current item 4950 rightToLeftSubMenus: false, // right to left display of the sub menus (check the CSS for the sub indicators' position) 4951 bottomToTopSubMenus: false, // bottom to top display of the sub menus 4952 overlapControlsInIE: true // make sure sub menus appear on top of special OS controls in IE (i.e. SELECT, OBJECT, EMBED, etc.) 4953 }; 4954 })(jQuery); 4955 /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(2))) 4956 4957/***/ }, 4958 4959/***/ 213: 4960/***/ function(module, exports, __webpack_require__) { 4961 4962 /* WEBPACK VAR INJECTION */(function(jQuery) {'use strict'; 4963 4964 /*! 4965 * SmartMenus jQuery Plugin Keyboard Addon - v0.1.0 - August 25, 2014 4966 * http://www.smartmenus.org/ 4967 * 4968 * Copyright 2014 Vasil Dinkov, Vadikom Web Ltd. 4969 * http://vadikom.com 4970 * 4971 * Licensed MIT 4972 */ 4973 4974 (function ($) { 4975 4976 function getFirstItemLink($ul) { 4977 return $ul.find('> li > a:not(.disabled)').eq(0); 4978 } 4979 function getLastItemLink($ul) { 4980 return $ul.find('> li > a:not(.disabled)').eq(-1); 4981 } 4982 function getNextItemLink($li, noLoop) { 4983 var $a = $li.nextAll('li').children('a:not(.disabled)').eq(0); 4984 return noLoop || $a.length ? $a : getFirstItemLink($li.parent()); 4985 } 4986 function getPreviousItemLink($li, noLoop) { 4987 var $a = $li.prevAll('li').children('a:not(.disabled)').eq(0); 4988 return noLoop || $a.length ? $a : getLastItemLink($li.parent()); 4989 } 4990
4991 // jQuery's .focus() is unreliable in some versions, so we're going to call the links' native JS focus method 4992 $.fn.focusSM = function () { 4993 if (this.length && this[0].focus) { 4994 this[0].focus(); 4995 } 4996 return this; 4997 }; 4998 4999 $.extend($.SmartMenus.Keyboard = {}, { 5000 docKeydown: function docKeydown(e) { 5001 var keyCode = e.keyCode; 5002 if (!/(27|37|38|39|40)/.test(keyCode)) { 5003 return; 5004 } 5005 var $root = $(this), 5006 obj = $root.data('smartmenus'), 5007 $target = $(e.target); 5008 if (!obj || !$target.is('a')) { 5009 return; 5010 } 5011 var $li = $target.parent(), 5012 $ul = $li.parent(), 5013 level = $ul.dataSM('level'); 5014 // exit it if this is an A inside a mega drop-down 5015 if (!level) { 5016 return; 5017 } 5018 // swap left & right keys 5019 if (obj.opts.rightToLeftSubMenus) { 5020 if (keyCode == 37) { 5021 keyCode = 39; 5022 } else if (keyCode == 39) { 5023 keyCode = 37; 5024 } 5025 } 5026 switch (keyCode) { 5027 case 27: 5028 // Esc 5029 if (obj.visibleSubMenus[level]) { 5030 obj.menuHide(obj.visibleSubMenus[level]); 5031 } else if (level == 1) { 5032 if (obj.opts.isPopup) { 5033 obj.menuHideAll(); 5034 } 5035 if (obj.opts.keyboardEscapeFocus) { 5036 try { 5037 obj.opts.keyboardEscapeFocus.focusSM(); 5038 } catch (e) {}; 5039 // focus next focusable page element 5040 } else { 5041 var $lastMenuFocusable = $root.find('a, input, select, button, textarea').eq(-1), 5042 $allFocusables = $('a, input, select, button, textarea'), 5043 nextFocusableIndex = $allFocusables.index($lastMenuFocusable[0]) + 1; 5044 $allFocusables.eq(nextFocusableIndex).focusSM(); 5045 } 5046 } else { 5047 $ul.dataSM('parent-a').focusSM(); 5048 obj.menuHide(obj.visibleSubMenus[level - 1]); 5049 } 5050 break; 5051 case 37: 5052 // Left 5053 if (obj.isCollapsible()) { 5054 break; 5055 } 5056 if (level > 2 || level == 2 && $root.hasClass('sm-vertical')) { 5057 obj.activatedItems[level - 2].focusSM(); 5058 // move to previous non-disabled parent item (make sure we cycle so it might be the last item) 5059 } else if (!$root.hasClass('sm-vertical')) { 5060 getPreviousItemLink(obj.activatedItems[0].parent()).focusSM(); 5061 } 5062 break; 5063 case 38: 5064 // Up 5065 if (obj.isCollapsible()) { 5066 var $firstItem; 5067 // if this is the first item of a sub menu, move to the parent item 5068 if (level > 1 && ($firstItem = getFirstItemLink($ul)).length && $target[0] == $firstItem[0]) { 5069 obj.activatedItems[level - 2].focusSM(); 5070 } else { 5071 getPreviousItemLink($li).focusSM(); 5072 } 5073 } else { 5074 if (level == 1 && !$root.hasClass('sm-vertical') && obj.visibleSubMenus[level] && obj.opts.bottomToTopSubMenus) { 5075 getLastItemLink(obj.visibleSubMenus[level]).focusSM(); 5076 } else if (level > 1 || $root.hasClass('sm-vertical')) { 5077 getPreviousItemLink($li).focusSM(); 5078 } 5079 } 5080 break; 5081 case 39: 5082 // Right 5083 if (obj.isCollapsible()) { 5084 break; 5085 } 5086 // move to next non-disabled parent item (make sure we cycle so it might be the last item) 5087 if ((level == 1 || !obj.visibleSubMenus[level]) && !$root.hasClass('sm-vertical')) { 5088 getNextItemLink(obj.activatedItems[0].parent()).focusSM(); 5089 } else if (obj.visibleSubMenus[level] && !obj.visibleSubMenus[level].hasClass('mega-menu')) { 5090 getFirstItemLink(obj.visibleSubMenus[level]).focusSM(); 5091 } 5092 break; 5093 case 40: 5094 // Down 5095 if (obj.isCollapsible()) { 5096 var $firstSubItem, $lastItem; 5097 // move to sub menu if appropriate 5098 if (obj.visibleSubMenus[level] && !obj.visibleSubMenus[level].hasClass('mega-menu') && ($firstSubItem = getFirstItemLink(obj.visibleSubMenus[level])).length) { 5099 $firstSubItem.focusSM(); 5100 // if this is the last item of a sub menu, move to the next parent item 5101 } else if (level > 1 && ($lastItem = getLastItemLink($ul)).length && $target[0] == $lastItem[0]) { 5102 var $parentItem = obj.activatedItems[level - 2].parent(), 5103 $nextParentItem = null; 5104 while ($parentItem.is('li')) { 5105 if (($nextParentItem = getNextItemLink($parentItem, true)).length) { 5106 break; 5107 } 5108 $parentItem = $parentItem.parent().parent(); 5109 } 5110 $nextParentItem.focusSM(); 5111 } else { 5112 getNextItemLink($li).focusSM(); 5113 } 5114 } else { 5115 if (level == 1 && !$root.hasClass('sm-vertical') && obj.visibleSubMenus[level] && !obj.opts.bottomToTopSubMenus) { 5116 getFirstItemLink(obj.visibleSubMenus[level]).focusSM(); 5117 } else if (level > 1 || $root.hasClass('sm-vertical')) { 5118 getNextItemLink($li).focusSM(); 5119 } 5120 } 5121 break; 5122 } 5123 e.stopPropagation(); 5124 e.preventDefault(); 5125 } 5126 }); 5127 5128 // hook it 5129 $(document).delegate('ul.sm', 'keydown.smartmenus', $.SmartMenus.Keyboard.docKeydown); 5130 5131 $.extend($.SmartMenus.prototype, {
5132 keyboardSetEscapeFocus: function keyboardSetEscapeFocus($elm) { 5133 this.opts.keyboardEscapeFocus = $elm; 5134 }, 5135 keyboardSetHotkey: function keyboardSetHotkey(keyCode, modifiers) { 5136 var self = this; 5137 $(document).bind('keydown.smartmenus' + this.rootId, function (e) { 5138 if (keyCode == e.keyCode) { 5139 var procede = true; 5140 if (modifiers) { 5141 if (typeof modifiers == 'string') { 5142 modifiers = [modifiers]; 5143 } 5144 $.each(['ctrlKey', 'shiftKey', 'altKey', 'metaKey'], function (index, value) { 5145 if ($.inArray(value, modifiers) >= 0 && !e[value] || $.inArray(value, modifiers) < 0 && e[value]) { 5146 procede = false; 5147 return false; 5148 } 5149 }); 5150 } 5151 if (procede) { 5152 getFirstItemLink(self.$root).focusSM(); 5153 e.stopPropagation(); 5154 e.preventDefault(); 5155 } 5156 } 5157 }); 5158 } 5159 }); 5160 })(jQuery); 5161 /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(2))) 5162 5163/***/ }, 5164 5165/***/ 215: 5166/***/ function(module, exports, __webpack_require__) { 5167 5168 /* WEBPACK VAR INJECTION */(function(jQuery) {'use strict'; 5169 5170 (function ($) { 5171 5172 $.fn.wishlistButton = function (options) { 5173 5174 var wishlistBtn = this; 5175 wishlistBtn.settings = {}; 5176 5177 // Merge options with defaults 5178 wishlistBtn.settings = $.extend({ 5179 productFormSelector: '.product__form' 5180 }, options); 5181 5182 // Init the cart plugin 5183 var init = function init() { 5184 5185 wishlistBtn.click(function () { 5186 if (wishlistBtn.hasClass('disabled')) { 5187 $.growl({ message: wishlistBtn.data('disabled-msg'), type: 'info' }); 5188 } else { 5189 $.post("/ajax/onskeliste", $(wishlistBtn.settings.productFormSelector).serialize(), function () { 5190 $.growl({ message: wishlistBtn.data('success') }); 5191 trackAddToWishlist(); 5192 }); 5193 return false; 5194 } 5195 }); 5196 }; 5197 5198 var trackAddToWishlist = function trackAddToWishlist() { 5199 if ('ga' in window) { 5200 window.ga('send', 'event', { 5201 eventCategory: 'Wishlist', 5202 eventAction: 'Added product to wishlist', 5203 eventLabel: $('.product__title').text() + ', id ' + $('input[name="id"]').val() 5204 }); 5205 } 5206 }; 5207 5208 init(); 5209 }; 5210 })(jQuery); 5211 /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(2))) 5212 5213/***/ }, 5214 5215/***/ 217: 5216/***/ function(module, exports, __webpack_require__) { 5217 5218 /* WEBPACK VAR INJECTION */(function($) {'use strict'; 5219 5220 $(function () { 5221 var navOpenButton = $('#nav-open-btn'); 5222 var navOpenCheckbox = $('#nav-open-checkbox'); 5223 var html = $('html'); 5224 var navClass = 'js-nav'; 5225 5226 html.addClass('js-ready'); 5227 5228 if (navOpenButton.length > 0) { 5229 navOpenButton.click(function (event) { 5230 event.preventDefault(); 5231 html.toggleClass(navClass); 5232 }); 5233 } else { 5234 if (navOpenCheckbox.length > 0) { 5235 navOpenCheckbox.change(function () { 5236 html.toggleClass(navClass); 5237 }); 5238 } 5239 } 5240 5241 $('#nav-close-btn').click(function (event) { 5242 event.preventDefault(); 5243 html.toggleClass(navClass); 5244 5245 if (navOpenCheckbox.length > 0) { 5246 navOpenCheckbox.prop('checked', false); 5247 } 5248 }); 5249 }); 5250 /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(2))) 5251 5252/***/ }, 5253 5254/***/ 218: 5255/***/ function(module, exports, __webpack_require__) { 5256 5257 /* WEBPACK VAR INJECTION */(function(jQuery, $) {'use strict'; 5258 5259 // Version three of the sincos script collection 5260 /* jshint esversion: 6 */ 5261 /* global Foundation, Modernizr, jQuery, $ */ 5262 5263 if (!window.sincos) window.sincos = { 'settings': {}, 'functions': {}, 'behaviors': {}, 'themes': {}, 'locale': {} }; 5264 var sincos = window.sincos; 5265 sincos.jsEnabled = true; 5266 5267 sincos.attachBehaviors = function (context) { 5268 context = context || document; 5269 jQuery.each(sincos.behaviors, function () { 5270 this(context); 5271 }); 5272 }; 5273 5274 // Slider 5275 sincos.behaviors.bxslider = function () {
5276 var slider_selector = '.js-product-image-slider'; 5277 var prod_img_slider = $(slider_selector).bxSlider({ 5278 captions: true, 5279 adaptiveHeight: true, 5280 adaptiveHeightSpeed: 200, 5281 speed: 300, 5282 pagerCustom: '#js-product-image-slider-thumbs', 5283 onSliderLoad: function onSliderLoad(currentIndex) { 5284 // set tabindex=0 for the current slide 5285 $(slider_selector + ' > :not(.bx-clone):eq(' + currentIndex + ') > .bx-slide').attr('tabindex', 0); 5286 $('.product__images').addClass('slider-loaded'); 5287 }, 5288 onSlideAfter: function onSlideAfter(elem) { 5289 // set tabindex=0 for active slide, -1 for others 5290 elem.find('.bx-slide').attr('tabindex', 0); 5291 elem.siblings().find('.bx-slide').attr('tabindex', -1); 5292 } 5293 }); 5294 5295 // Add keybord navigation if we have only one slider on the page 5296 // and if focus is not in another item that uses arrow key navigation 5297 if (prod_img_slider.length === 1) { 5298 $('html').keydown(function (e) { 5299 if (e.keyCode === 39 || e.keyCode === 37) { 5300 if ($(':focus').parents('.js-arrow-key-nav').length === 0 && $(':focus').parents('form').length === 0 && !$('.fancybox-wrap').is(':visible')) { 5301 if (e.keyCode === 39) { 5302 prod_img_slider.goToNextSlide(); 5303 } else if (e.keyCode === 37) { 5304 prod_img_slider.goToPrevSlide(); 5305 } 5306 } 5307 } 5308 }); 5309 } 5310 }; 5311 5312 // See jquery.cart.js 5313 sincos.behaviors.cart = function () { 5314 var cart_btn = $('.cart-button'); 5315 cart_btn.cart(); 5316 sincos.cart = cart_btn.data('cart'); 5317 }; 5318 5319 sincos.behaviors.addToCart = function () { 5320 $('.js-product__buy-button').one("click", function (e) { 5321 var parent = $(this).parents('[itemtype="http://schema.org/Product"]'); 5322 var productId = parent.find("[data-product-id]").data("product-id"); 5323 var price = parent.find('meta[itemprop="price"]').attr("content"); 5324 var currency = parent.find('.offers').find('meta[itemprop="priceCurrency"]').attr("content"); 5325 5326 $(document).trigger("productAddedToCart", [productId, price, currency]); 5327 }); 5328 }; 5329 5330 sincos.behaviors.addBundleToCartOne = function () { 5331 $('.js-bundle__buy-button').one("click", function (e) { 5332 var parent = $(this).parents('[itemtype="http://schema.org/Product"]'); 5333 var productId = parent.find("[data-product-id]").data("product-id"); 5334 var price = parent.find('meta[itemprop="price"]').attr("content"); 5335 var currency = parent.find('.offers').find('meta[itemprop="priceCurrency"]').attr("content"); 5336 5337 $(document).trigger("productAddedToCart", [productId, price, currency]); 5338 }); 5339 }; 5340 5341 // Init smartmenus 5342 if (typeof $.fn.smartmenus == "function") { 5343 sincos.behaviors.smartmenus = function () { 5344 var context = arguments.length <= 0 || arguments[0] === undefined ? document : arguments[0]; 5345 var selector = arguments.length <= 1 || arguments[1] === undefined ? '#main-menu' : arguments[1]; 5346 var dynamic = arguments[2]; 5347 var mediumUp = arguments[3]; 5348 5349 //@TODO rewrite to use $menu.smartmenus('refresh'); instead of dom cloning toggling display 5350 if (dynamic !== false) { 5351 var label = $(selector).data('mer') || 'Mer'; 5352 var submenu = $('<li class="main-nav__item parent level-0 main-nav__item--more"><a href="#">' + label + '</a><ul class="main-nav__submenu level-1"></ul></li>'); 5353 var clones = $(selector + ' > li').clone(); 5354 submenu.find('.main-nav__submenu.level-1').append(clones); 5355 submenu.find('li').each(function (key, el) { 5356 var $el = $(el); 5357 var level = $(el).parents('ul').length; 5358 5359 $el.removeClass('level-' + (level - 1)).addClass('level-' + level); 5360 $el.children('ul').removeClass('level-' + level).addClass('level-' + (level + 1)); 5361 }); 5362 $(selector).append(submenu); 5363 } 5364 5365 $(selector).smartmenus({ 5366 'subIndicators': false, 5367 'subMenusMinWidth': false, 5368 'subMenusMaxWidth': false, 5369 'keepInViewport': true, 5370 'hideDuration': 300, 5371 'hideTimeout': 600, 5372 'hideOnClick': false //Only needed when menus are shown on click, not :hover 5373 }); 5374 // Prevent crash edge cases on slower iOS devices 5375 $(document).off('touchstart.smartmenus_mouse'); 5376 5377 var refreshThrottle, 5378 menu = $(selector), 5379 section = menu.parent(), 5380 lastChild = menu.children().not('.main-nav__item--more').filter(':last').addClass('main-nav__item--last-child'), 5381 handleResize = function handleResize(e) { 5382 // Only do this when we're not in tablet mode or mobile 5383 if (window.Foundation && !Foundation.utils[mediumUp ? 'is_medium_up' : 'is_large_up']()) { 5384 menu.children().css('display', ''); 5385 menu.find('.main-nav__item--more').hide(); 5386 5387 return e; 5388 } 5389 5390 var getOuterWidth = function getOuterWidth(el) { 5391 return el[0] && el.outerWidth(true) || 0; 5392 }; 5393 5394 var moreMenuWidth = getOuterWidth(menu.find('.main-nav__item--more')); 5395 var offsetPadding = getOuterWidth(menu.find('li:visible > .main-nav__frontpage-link')); 5396 var availableWidth = menu.innerWidth(); 5397 5398 var growing = 0; 5399 5400 var startedHiding = false;
5401 menu.children().each(function (key, el) { 5402 var $el = $(el); 5403 if ($el.is('.main-nav__item--more')) return; 5404 5405 var width = $el.is(':first-child:not(:visible)') ? 0 : getOuterWidth($el); 5406 growing += width; 5407 // Add a 5px margin of error 5408 if (growing + 5 >= availableWidth) { 5409 $el.hide(); 5410 menu.find('.main-nav__item--more > ul').children(':eq(' + key + ')').css('display', ''); 5411 5412 // Check if there is not enough room to render the More button 5413 if (availableWidth < growing + 5 - width + moreMenuWidth && !startedHiding) { 5414 $el.prev().hide(); 5415 menu.find('.main-nav__item--more > ul').children(':eq(' + (key - 1) + ')').css('display', ''); 5416 startedHiding = true; 5417 } 5418 } else { 5419 $el.css('display', ''); 5420 menu.find('.main-nav__item--more > ul').children(':eq(' + key + ')').hide(); 5421 } 5422 }); 5423 5424 menu.find('.main-nav__item--more').css({ 5425 'display': menu.find('.main-nav__item--more > ul').children(':not([style*="display: none"])').length === 0 ? 'none' : '' 5426 }).toggleClass('selected', menu.find('.main-nav__item--more .selected:not([style*="display: none"])').length > 0); 5427 5428 // Refresh throttle 5429 clearTimeout(refreshThrottle); 5430 refreshThrottle = setTimeout(function () { 5431 menu.smartmenus('refresh'); 5432 }, 3000); 5433 }; 5434 5435 if (dynamic !== false) { 5436 $(window).on('resize load sticky_nav_change', handleResize); 5437 handleResize(); 5438 } 5439 }; 5440 } 5441 5442 // Ajax product search - Disabled for now 5443 sincos.behaviors.productsearch = function () { 5444 var product_search_field = $('.js-product-search'); 5445 product_search_field.productsearch(); 5446 sincos.productsearch = product_search_field.data('productsearch'); 5447 }; 5448 5449 // Easier styling of search inputs with focus states than pure css :focus 5450 sincos.behaviors.searchsugar = function () { 5451 $('input.search-box__input').on({ 5452 focus: function focus() { 5453 $(this).addClass('active'); 5454 }, 5455 blur: function blur() { 5456 var value = this.value.trim(); 5457 if (!value.length || value === this.defaultValue) $(this).removeClass('active'); 5458 } 5459 }); 5460 }; 5461 5462 sincos.behaviors.fancybox = function () { 5463 // Use fancybox for product image popup big medium screens and up 5464 if (window.Modernizr && window.Foundation && Modernizr.mq(Foundation.media_queries.medium)) { 5465 // Avoid including clones in the gallery, which are created by the bxslider 5466 $('.js-fancybox-gallery > li:not(.bx-clone) > .product__main-images__link').fancybox(); 5467 } else { 5468 $('.product__main-images__link').click(function (event) { 5469 event.preventDefault(); 5470 }); 5471 } 5472 5473 // Use fancybox for the login popup in the checkout 5474 $(".js-login-popup").fancybox({ 5475 padding: 20, 5476 minWidth: 250, 5477 maxWidth: 400, 5478 fitToView: true, 5479 autoSize: true, 5480 closeClick: false, 5481 scrolling: 'no', 5482 openEffect: 'none', 5483 closeEffect: 'none' 5484 }); 5485 5486 $('.js-checkout-login-close').click(function () { 5487 $.fancybox.close(); 5488 }); 5489 }; 5490 5491 // Initialize tabs 5492 sincos.behaviors.tabs = function () { 5493 $('.js-tabs').easyResponsiveTabs(); 5494 }; 5495 5496 // See jquery.wishlist.js 5497 sincos.behaviors.onskeliste = function () { 5498 $('.product__wishlist-button').wishlistButton(); 5499 }; 5500 5501 // Handle ajax submissions on product review forms 5502 sincos.behaviors.review_form = function (context) { 5503 $('.js-review-form .button', context).each(function () { 5504 $(this).click(function () { 5505 $.post("/ajax/produktanmeldelse", $(".js-review-form").serialize(), function (data) { 5506 $('.js-review-form').html(data); 5507 $('#produkt_anmeldelser_form_validert').each(function () { 5508 $('.js-review-form .button').hide(); 5509 $('.comments-guidelines').hide(); 5510 }); 5511 }); 5512 return false;
5513 }); 5514 }); 5515 }; 5516 5517 // Close the parent element when clicking .close buttons 5518 sincos.behaviors.close = function () { 5519 $('body').on('click', '.close', function () { 5520 $(this).parent().slideUp('fast'); 5521 }); 5522 }; 5523 5524 /** 5525 * Toggle visibility of element(s) 5526 * @return {void} [description] 5527 */ 5528 sincos.behaviors.showHide = function () { 5529 $('.js-toggle-visibility').click(function (event) { 5530 var btn = $(this); 5531 if (btn.prop('tagName') === 'A') { 5532 event.preventDefault(); 5533 } 5534 5535 var toggle_toggler_class = btn.data('toggle-toggler-class') || 'toggled'; 5536 5537 if (btn.data('close') !== 'undefined') { 5538 $(btn.data('close')).slideUp('fast'); 5539 } 5540 5541 sincos.functions.showHide(btn.data('toggle')); 5542 btn.toggleClass(toggle_toggler_class); 5543 5544 if (btn.data('toggle-close-label') !== 'undefined') { 5545 var temp = btn.html(); 5546 btn.html(btn.data('toggle-close-label')); 5547 btn.data('toggle-close-label', temp); 5548 } 5549 }); 5550 }; 5551 5552 sincos.behaviors.stateful = function () { 5553 var stateful_forms = $('.js-stateful'); 5554 5555 $.each(stateful_forms, function (index, value) { 5556 var form = $(value); 5557 var form_submit = form.find('[type="submit"]'); 5558 var form_state = form.serialize(); 5559 form_submit.attr('disabled', true); 5560 5561 form.find('select, input, textarea').on('change keyup', function () { 5562 if (form.serialize() !== form_state) { 5563 form_submit.attr('disabled', false); 5564 } else { 5565 form_submit.attr('disabled', true); 5566 } 5567 }); 5568 }); 5569 }; 5570 5571 sincos.behaviors.byttmva = function (context) { 5572 $('.bytt_mva').click(function (event) { 5573 event.preventDefault(); 5574 $("#bytt_mva_form").submit(); 5575 }); 5576 }; 5577 5578 sincos.behaviors.cookie_notice = function () { 5579 $('#cookie_notice_remove').click(function () { 5580 document.cookie = 'cookie_notice=0; path=/; max-age=' + 60 * 60 * 24 * 365; 5581 $('.cookie_notice').hide(); 5582 return false; 5583 }); 5584 }; 5585 5586 document.cookie = 'javascript=1; path=/'; 5587 5588 sincos.functions.showHide = function (selector) { 5589 $(selector).animate({ 5590 height: 'toggle', 5591 opacity: 'toggle' 5592 }, 200).toggleClass('toggled'); 5593 }; 5594 5595 sincos.functions.cancel_login = function () { 5596 $('.kasse_one_logginn_cancel').click(function () { 5597 $.fancybox.close(); 5598 }); 5599 }; 5600 5601 /** 5602 * Debounce, for throttling function calls 5603 * @param {object} fn function oblect 5604 * @param {int} delay ms delay 5605 * @return {object} function 5606 */ 5607 sincos.functions.debounce = function (fn, delay_input) { 5608 var timer = null; 5609 var delay = delay_input || 500; 5610 return function () { 5611 var context = this, 5612 args = arguments; 5613 clearTimeout(timer); 5614 timer = setTimeout(function () { 5615 fn.apply(context, args); 5616 }, delay); 5617 }; 5618 }; 5619 5620 // Attach all behaviors. 5621 $(function () { 5622 sincos.attachBehaviors(window); 5623 }); 5624 /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(2), __webpack_require__(2))) 5625 5626/***/ }, 5627 5628/***/ 219: 5629/***/ function(module, exports, __webpack_require__) { 5630 5631 /* WEBPACK VAR INJECTION */(function(jQuery) {'use strict'; 5632 5633 // Easy Responsive Tabs Plugin 5634 // Author: Samson.Onna <Email : [email protected]> 5635 // https://github.com/samsono/Easy-Responsive-Tabs-to-Accordion/ 5636 (function ($) { 5637 $.fn.extend({ 5638 easyResponsiveTabs: function easyResponsiveTabs(options) { 5639 //Set the default values, use comma to separate the settings, example: 5640 var defaults = { 5641 type: 'default', //default, vertical, accordion; 5642 width: 'auto', 5643 fit: true, 5644 closed: false, 5645 activate: function activate() {} 5646 }; 5647 5648 //Variables 5649 var options = $.extend(defaults, options); 5650 var opt = options, 5651 jtype = opt.type, 5652 jfit = opt.fit, 5653 jwidth = opt.width, 5654 vtabs = 'vertical', 5655 accord = 'accordion'; 5656 var hash = window.location.hash; 5657 var historyApi = !!(window.history && history.replaceState); 5658 5659 //Events 5660 $(this).bind('tabactivate', function (e, currentTab) { 5661 if (typeof options.activate === 'function') { 5662 options.activate.call(currentTab, e); 5663 } 5664 }); 5665 5666 //Main function 5667 this.each(function () { 5668 var $respTabs = $(this); 5669 var $respTabsList = $respTabs.find('ul.resp-tabs-list'); 5670 var respTabsId = $respTabs.attr('id'); 5671 $respTabs.find('ul.resp-tabs-list li').addClass('resp-tab-item'); 5672 $respTabs.css({ 5673 'display': 'block', 5674 'width': jwidth 5675 }); 5676 5677 $respTabs.find('.resp-tabs-container > div').addClass('resp-tab-content'); 5678 jtab_options(); 5679 //Properties Function 5680 function jtab_options() { 5681 if (jtype == vtabs) { 5682 $respTabs.addClass('resp-vtabs'); 5683 } 5684 if (jfit == true) { 5685 $respTabs.css({ width: '100%', margin: '0px' }); 5686 } 5687 if (jtype == accord) { 5688 $respTabs.addClass('resp-easy-accordion'); 5689 $respTabs.find('.resp-tabs-list').css('display', 'none'); 5690 } 5691 } 5692 5693 //Assigning the h2 markup to accordion title 5694 var $tabItemh2; 5695 $respTabs.find('.resp-tab-content').before("<h2 class='resp-accordion' tabindex='0' role='tab'><span class='resp-arrow'></span></h2>"); 5696 5697 var itemCount = 0; 5698 $respTabs.find('.resp-accordion').each(function () { 5699 $tabItemh2 = $(this); 5700 var $tabItem = $respTabs.find('.resp-tab-item:eq(' + itemCount + ')'); 5701 var $accItem = $respTabs.find('.resp-accordion:eq(' + itemCount + ')'); 5702 $accItem.append($tabItem.html()); 5703 $accItem.data($tabItem.data()); 5704 $tabItemh2.attr('aria-controls', 'tab_item-' + itemCount); 5705 itemCount++; 5706 }); 5707 5708 //Assigning the 'aria-controls' to Tab items 5709 var count = 0; 5710 $respTabs.find('.resp-tab-item').each(function () { 5711 var $tabItem = $(this); 5712 $tabItem.attr('aria-controls', 'tab_item-' + count); 5713 $tabItem.attr('role', 'tab'); 5714 5715 //Assigning the 'aria-labelledby' attr to tab-content 5716 var tabcount = 0; 5717 $respTabs.find('.resp-tab-content').each(function () { 5718 var $tabContent = $(this); 5719 $tabContent.attr('aria-labelledby', 'tab_item-' + tabcount); 5720 tabcount++; 5721 }); 5722 count++; 5723 }); 5724 5725 // Show correct content area 5726 var tabNum = 0; 5727 if (hash != '') { 5728 var matches = hash.match(new RegExp(respTabsId + "([0-9]+)")); 5729 if (matches !== null && matches.length === 2) { 5730 tabNum = parseInt(matches[1], 10) - 1; 5731 if (tabNum > count) { 5732 tabNum = 0; 5733 } 5734 } 5735 } 5736 5737 //Active correct tab 5738 $($respTabs.find('.resp-tab-item')[tabNum]).addClass('resp-tab-active'); 5739 5740 //keep closed if option = 'closed' or option is 'accordion' and the element is in accordion mode 5741 if (options.closed !== true && !(options.closed === 'accordion' && !$respTabsList.is(':visible')) && !(options.closed === 'tabs' && $respTabsList.is(':visible'))) { 5742 $($respTabs.find('.resp-accordion')[tabNum]).addClass('resp-tab-active'); 5743 $($respTabs.find('.resp-tab-content')[tabNum]).addClass('resp-tab-content-active').attr('style', 'display:block'); 5744 } 5745 //assign proper classes for when tabs mode is activated before making a selection in accordion mode 5746 else { 5747 $($respTabs.find('.resp-tab-content')[tabNum]).addClass('resp-tab-content-active resp-accordion-closed'); 5748 } 5749 5750 //Tab Click action function 5751 $respTabs.find("[role=tab]").each(function () { 5752 5753 var $currentTab = $(this); 5754 5755 $currentTab.keypress(function (e) { 5756 if (e.keyCode == 13 || e.keyCode == 32) { 5757 $currentTab.click(); 5758 } 5759 }); 5760 5761 $currentTab.click(function () { 5762 5763 var $currentTab = $(this); 5764 var $tabAria = $currentTab.attr('aria-controls'); 5765 5766 if ($currentTab.hasClass('resp-accordion') && $currentTab.hasClass('resp-tab-active')) { 5767 $respTabs.find('.resp-tab-content-active').slideUp('', function () { 5768 $(this).addClass('resp-accordion-closed'); 5769 }); 5770 $currentTab.removeClass('resp-tab-active'); 5771 return false;
5772 } 5773 if (!$currentTab.hasClass('resp-tab-active') && $currentTab.hasClass('resp-accordion')) { 5774 $respTabs.find('.resp-tab-active').removeClass('resp-tab-active'); 5775 $respTabs.find('.resp-tab-content-active').slideUp().removeClass('resp-tab-content-active resp-accordion-closed'); 5776 $respTabs.find("[aria-controls=" + $tabAria + "]").addClass('resp-tab-active'); 5777 5778 $respTabs.find('.resp-tab-content[aria-labelledby = ' + $tabAria + ']').slideDown().addClass('resp-tab-content-active'); 5779 } else { 5780 $respTabs.find('.resp-tab-active').removeClass('resp-tab-active'); 5781 $respTabs.find('.resp-tab-content-active').removeAttr('style').removeClass('resp-tab-content-active').removeClass('resp-accordion-closed'); 5782 $respTabs.find("[aria-controls=" + $tabAria + "]").addClass('resp-tab-active'); 5783 $respTabs.find('.resp-tab-content[aria-labelledby = ' + $tabAria + ']').addClass('resp-tab-content-active').attr('style', 'display:block'); 5784 } 5785 //Trigger tab activation event 5786 $currentTab.trigger('tabactivate', $currentTab); 5787 5788 //Update Browser History 5789 if (historyApi) { 5790 var currentHash = window.location.hash; 5791 var newHash = respTabsId + (parseInt($tabAria.substring(9), 10) + 1).toString(); 5792 if (currentHash != "") { 5793 var re = new RegExp(respTabsId + "[0-9]+"); 5794 if (currentHash.match(re) != null) { 5795 newHash = currentHash.replace(re, newHash); 5796 } else { 5797 newHash = currentHash + "|" + newHash; 5798 } 5799 } else { 5800 newHash = '#' + newHash; 5801 } 5802 5803 history.replaceState(null, null, newHash); 5804 } 5805 }); 5806 }); 5807 5808 //Window resize function 5809 $(window).resize(function () { 5810 $respTabs.find('.resp-accordion-closed').removeAttr('style'); 5811 }); 5812 }); 5813 } 5814 }); 5815 })(jQuery); 5816 /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(2))) 5817 5818/***/ }, 5819 5820/***/ 253: 5821/***/ function(module, exports, __webpack_require__) { 5822 5823 'use strict'; 5824 5825 // Keyboard navigation for the menu on large screens 5826 if (window.Modernizr && window.Foundation && Modernizr.mq(Foundation.media_queries.large)) { 5827 // Load the smartmenus keyboard only when needed, keeping the main theme.checkout.js small 5828 //require.ensure([], function(){ 5829 __webpack_require__(213); 5830 //}, 'jquery.smartmenus_keyboard'); 5831 } 5832 5833 // Polyfill for equal height column grid 5834 if (window.Modernizr && !Modernizr.flexbox) { 5835 // Load the smartmenus keyboard only when needed, keeping the main theme.checkout.js small 5836 //require.ensure([], function(){ 5837 __webpack_require__(202); 5838 //}, 'equal_height_columns'); 5839 } 5840 5841 // If on product page, load thumb connector script 5842 if (document.location.pathname.indexOf("/produkt/") === 0 && window.FEATURES.get('thumb_attribute_connection')) { 5843 __webpack_require__.e/* nsure */(3, function () { 5844 __webpack_require__(123); 5845 }); 5846 } 5847 5848 // Load RCT tag tracking 5849 if (window.FEATURES.get('abandoncart_email')) { 5850 __webpack_require__.e/* nsure */(1, function () { 5851 __webpack_require__(474); 5852 }); 5853 } 5854 5855 if (window.FEATURES.get('facebook_dpa')) { 5856 __webpack_require__.e/* nsure */(2, function () { 5857 __webpack_require__(473); 5858 }); 5859 } 5860 5861 // Fastclick for touch screens 5862 /* Deactivated until we can prevent double click events from happening 5863 if(Modernizr.touch) { 5864 require.ensure([], function(){ 5865 var FastClick = require('assets/fastclick'); 5866 jQuery(function() { 5867 FastClick.attach(document.body); 5868 }); 5869 }, 'fastclick'); 5870 } 5871 //*/ 5872 5873/***/ } 5874 5875}); 5876//# sourceMappingURL=theme.js.map
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.