1/** 2 * Unfold Content component. 3 * 4 * @author Htmlstream 5 * @version 1.0 6 */ 7; 8(function ($) { 9 'use strict'; 10 11 $.HSCore.components.HSUnfold = { 12 13 /** 14 * Base configuration of the component. 15 * 16 * @private 17 */ 18 _baseConfig: { 19 unfoldEvent: 'click', 20 unfoldType: 'simple', 21 unfoldDuration: 300, 22 unfoldEasing: 'linear', 23 unfoldAnimationIn: 'fadeIn', 24 unfoldAnimationOut: 'fadeOut', 25 unfoldHideOnScroll: true, 26 unfoldHideOnBlur: false, 27 unfoldDelay: 350, 28 unfoldOpenedElement: 'init', 29 unfoldOverlay: false, 30 afterOpen: function (invoker) { 31 }, 32 beforeClose: function (invoker) { 33 }, 34 afterClose: function (invoker) { 35 } 36 }, 37 38 /** 39 * Collection of all initialized items on the page. 40 * 41 * @private 42 */ 43 _pageCollection: $(), 44 45 /** 46 * Initialization. 47 * 48 * @param {jQuery} collection 49 * @param {Object} config 50 * 51 * @public 52 * @return {jQuery} 53 */ 54 init: function (collection, config) { 55 56 var self; 57 58 if (!collection || !collection.length) return; 59 60 self = this; 61 62 var fieldsQty; 63 64 collection.each(function (i, el) { 65 66 var $this = $(el), itemConfig; 67 68 if ($this.data('HSUnfold')) return; 69 70 itemConfig = config && $.isPlainObject(config) ? 71 $.extend(true, {}, self._baseConfig, config, $this.data()) : 72 $.extend(true, {}, self._baseConfig, $this.data()); 73 74 switch (itemConfig.unfoldType) { 75 76 case 'css-animation' : 77 78 $this.data('HSUnfold', new UnfoldCSSAnimation($this, itemConfig)); 79 80 break; 81 82 case 'jquery-slide' : 83 84 $this.data('HSUnfold', new UnfoldJSlide($this, itemConfig)); 85 86 break; 87 88 default : 89 90 $this.data('HSUnfold', new UnfoldSimple($this, itemConfig)); 91 92 } 93 94 self._pageCollection = self._pageCollection.add($this); 95 self._bindEvents($this, itemConfig.unfoldEvent, itemConfig.unfoldDelay); 96 var UnFold = $(el).data('HSUnfold'); 97 98 fieldsQty = $(UnFold.target).find('input, textarea').length; 99 100 if ($(UnFold.target).find('[data-unfold-target]').length) { 101 102 $this.addClass('target-of-invoker-has-unfolds'); 103 104 } 105 106 }); 107 108 $(document).on('click touchstart', 'body', function (e) { 109 110 if (e.target.id === self._baseConfig.unfoldOpenedElement) return; 111 112 if ($(e.target).closest('#' + self._baseConfig.unfoldOpenedElement).length) return; 113 114 self._pageCollection.each(function (i, el) { 115 116 var windW = window.innerWidth, 117 optIsMobileOnly = Boolean($(el).data('is-mobile-only')); 118 119 if (!optIsMobileOnly) { 120 121 $(el).data('HSUnfold').hide(); 122 123 } else if (optIsMobileOnly && windW < 769) { 124 125 $(el).data('HSUnfold').hide(); 126 127 } 128 129 if ($(el).data('HSUnfold').config.unfoldOverlay) { 130 131 $(el).data('HSUnfold').config.unfoldDelay = setTimeout(function () { 132 133 $('.' + $(el).data('HSUnfold').config.unfoldOverlay.className).fadeOut($(el).data('HSUnfold').config.unfoldOverlay.animationSpeed ? $(el).data('HSUnfold').config.unfoldOverlay.animationSpeed : 200); 134 135 }, $(el).data('HSUnfold').config.unfoldDelay) 136 137 } 138 139 $(el).data('HSUnfold').config.beforeClose.call(self.target, self.element); 140 141 }); 142 143 }); 144 145 $(window).on('scroll.HSUnfold', function () { 146 147 self._pageCollection.each(function (i, el) { 148 149 var UnFold = $(el).data('HSUnfold'); 150 151 if (UnFold.getOption('unfoldHideOnScroll') && fieldsQty === 0) { 152 153 UnFold.hide(); 154 155 } else if (UnFold.getOption('unfoldHideOnScroll') && !(/iPhone|iPad|iPod/i.test(navigator.userAgent))) { 156 157 UnFold.hide(); 158 159 } 160 161 }); 162 163 }); 164 165 $(window).on('resize.HSUnfold', function () { 166 167 if (self._resizeTimeOutId) clearTimeout(self._resizeTimeOutId); 168 169 self._resizeTimeOutId = setTimeout(function () { 170 171 self._pageCollection.each(function (i, el) { 172 173 var UnFold = $(el).data('HSUnfold'); 174
175 UnFold.smartPosition(UnFold.target); 176 177 }); 178 179 }, 50); 180 181 }); 182 183 $(document).on('keydown.HSUnfold', function (e) { 184 185 if ($('body').hasClass('u-unfold-opened')) { 186 187 if (e.keyCode && e.keyCode === 38 || e.keyCode && e.keyCode === 40) { 188 189 e.preventDefault(); 190 191 } 192 193 if (e.keyCode && e.keyCode === 27) { 194 195 self._pageCollection.each(function (i, el) { 196 197 $(el).data('HSUnfold').hide(); 198 199 }); 200 201 $('body').removeClass('u-unfold-opened'); 202 203 } 204 205 } 206 207 }); 208 209 return collection; 210 211 }, 212 213 /** 214 * Binds necessary events. 215 * 216 * @param {jQuery} $invoker 217 * @param {String} eventType 218 * @param {Number} delay 219 * @private 220 */ 221 _bindEvents: function ($invoker, eventType, delay) { 222 223 var self = this, 224 $unfold = $($invoker.data('unfold-target')); 225 226 if (eventType === 'hover' && !_isTouch()) { 227 228 $invoker.on('mouseenter.HSUnfold', function () { 229 230 var $invoker = $(this), 231 HSUnfold = $invoker.data('HSUnfold'); 232 233 if (!HSUnfold) return; 234 235 if (HSUnfold.unfoldTimeOut) clearTimeout(HSUnfold.unfoldTimeOut); 236 HSUnfold.show(); 237 $('body').addClass('u-unfold-opened'); 238 239 }) 240 .on('mouseleave.HSUnfold', function () { 241 242 var $invoker = $(this), 243 HSUnfold = $invoker.data('HSUnfold'); 244 245 if (!HSUnfold) return; 246 247 HSUnfold.unfoldTimeOut = setTimeout(function () { 248 249 HSUnfold.hide(); 250 $('body').removeClass('u-unfold-opened'); 251 252 }, delay); 253 254 }); 255 256 if ($unfold.length) { 257 258 $unfold.on('mouseenter.HSUnfold', function () { 259 260 var HSUnfold = $invoker.data('HSUnfold'); 261 262 if (HSUnfold.unfoldTimeOut) clearTimeout(HSUnfold.unfoldTimeOut); 263 HSUnfold.show(); 264 265 }) 266 .on('mouseleave.HSUnfold', function () { 267 268 var HSUnfold = $invoker.data('HSUnfold'); 269 270 HSUnfold.unfoldTimeOut = setTimeout(function () { 271 HSUnfold.hide(); 272 }, delay); 273 274 }); 275 } 276 277 } else { 278 279 $invoker.on('click.HSUnfold', function (e) { 280 281 var $curInvoker = $(this), 282 $unfoldNotHasInnerUnfolds = $('[data-unfold-target].active:not(.target-of-invoker-has-unfolds)'), 283 $unfoldHasInnerUnfold = $('[data-unfold-target].active.target-of-invoker-has-unfolds'); 284 285 self._baseConfig.unfoldOpenedElement = $curInvoker.data('HSUnfold').target[0].id; 286 287 if (!$curInvoker.data('HSUnfold')) return; 288 289 if (!$curInvoker.hasClass('target-of-invoker-has-unfolds')) { 290 291 if ($unfoldNotHasInnerUnfolds.length) { 292 293 $unfoldNotHasInnerUnfolds.data('HSUnfold').toggle(); 294 295 } 296 297 } else { 298 299 if ($unfoldHasInnerUnfold.length) { 300 301 $unfoldHasInnerUnfold.data('HSUnfold').toggle(); 302 303 } 304 305 } 306 307 $curInvoker.data('HSUnfold').toggle(); 308 $('body').toggleClass('u-unfold-opened'); 309 310 e.stopPropagation(); 311 312 e.preventDefault(); 313 314 }); 315 316 if (Boolean($invoker.data('unfold-target-is-menu'))) { 317 318 var $target = $($invoker.data('unfold-target')), 319 $targetItems = $target.children(); 320 321 $targetItems.on('click', function () { 322 323 $invoker.data('HSUnfold').toggle(); 324 325 }); 326 327 } 328 329 } 330 331 } 332 }; 333 334 function _isTouch() { 335 return 'ontouchstart' in window; 336 } 337 338 /** 339 * Abstract Unfold class. 340 * 341 * @param {jQuery} element 342 * @param {Object} config 343 * @abstract 344 */ 345 function AbstractUnfold(element, config) { 346 347 var $self = this; 348 349 if (!element.length) return false; 350 351 $self.element = element; 352 $self.config = config; 353 354 $self.target = $($self.element.data('unfold-target')); 355 356 $self.allInvokers = $('[data-unfold-target="' + $self.element.data('unfold-target') + '"]'); 357 358 $self.toggle = function () { 359 if (!$self.target.length) return $self; 360 361 var dataset = $self.element[0].dataset, 362 overlay = dataset.unfoldOverlay ? JSON.parse(dataset.unfoldOverlay) : false;
363 364 if ($self.defaultState) { 365 366 if (dataset.unfoldOverlay) { 367 368 if (!$('.' + overlay.className).length) { 369 370 $('<div class="' + overlay.className + '" style="background-color: ' + overlay.background + '"></div>').prependTo('body'); 371 372 } 373 374 if ($('.' + overlay.className).length) { 375 376 $('.' + overlay.className).fadeIn(overlay.animationSpeed ? overlay.animationSpeed : 200); 377 378 } 379 380 } 381 382 $self.show(); 383 384 } else { 385 386 if ($('.' + overlay.className).length) { 387 388 $self.config.unfoldTimeOut = setTimeout(function () { 389 390 $('.' + overlay.className).fadeOut(overlay.animationSpeed ? overlay.animationSpeed : 200); 391 392 }, $self.config.unfoldDelay) 393 394 } 395 396 $self.hide(); 397 398 } 399 400 return $self; 401 }; 402 403 this.smartPosition = function (target) { 404 405 if (target.data('baseDirection')) { 406 target.css( 407 target.data('baseDirection').direction, 408 target.data('baseDirection').value 409 ); 410 } 411 412 target.removeClass('u-unfold--reverse-y'); 413 414 var $w = $(window), 415 styles = getComputedStyle(target.get(0)), 416 direction = Math.abs(parseInt(styles.left, 10)) < 40 ? 'left' : 'right', 417 targetOuterGeometry = target.offset(); 418 419 // horizontal axis 420 if (direction === 'right') { 421 422 if (!target.data('baseDirection')) target.data('baseDirection', { 423 direction: 'right', 424 value: parseInt(styles.right, 10) 425 }); 426 427 if (targetOuterGeometry.left < 0) { 428 429 target.css( 430 'right', 431 (parseInt(target.css('right'), 10) - (targetOuterGeometry.left - 10)) * -1 432 ); 433 434 } 435 436 } else { 437 438 if (!target.data('baseDirection')) target.data('baseDirection', { 439 direction: 'left', 440 value: parseInt(styles.left, 10) 441 }); 442 443 if (targetOuterGeometry.left + target.outerWidth() > $w.width()) { 444 445 target.css( 446 'left', 447 (parseInt(target.css('left'), 10) - (targetOuterGeometry.left + target.outerWidth() + 10 - $w.width())) 448 ); 449 450 } 451 452 } 453 454 // vertical axis 455 if (targetOuterGeometry.top + target.outerHeight() - $w.scrollTop() > $w.height()) { 456 457 target.addClass('u-unfold--reverse-y'); 458 459 } 460 461 }; 462 463 this.getOption = function (option) { 464 return this.config[option] ? this.config[option] : null; 465 }; 466 467 return true; 468 } 469 470 471 /** 472 * UnfoldSimple constructor. 473 * 474 * @param {jQuery} element 475 * @param {Object} config 476 * @constructor 477 */ 478 function UnfoldSimple(element, config) { 479 if (!AbstractUnfold.call(this, element, config)) return; 480 481 Object.defineProperty(this, 'defaultState', { 482 get: function () { 483 return this.target.hasClass('u-unfold--hidden'); 484 } 485 }); 486 487 this.target.addClass('u-unfold--simple'); 488 489 this.hide(); 490 } 491 492 /** 493 * UnfoldCSSAnimation constructor. 494 * 495 * @param {jQuery} element 496 * @param {Object} config 497 * @constructor 498 */ 499 function UnfoldCSSAnimation(element, config) { 500 if (!AbstractUnfold.call(this, element, config)) return; 501 502 var self = this; 503 504 this.target 505 .addClass('u-unfold--css-animation u-unfold--hidden') 506 .css('animation-duration', self.config.unfoldDuration + 'ms'); 507 508 Object.defineProperty(this, 'defaultState', { 509 get: function () { 510 return this.target.hasClass('u-unfold--hidden'); 511 } 512 }); 513 514 if (this.target.length) { 515 516 this.target.on('webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend', function (e) { 517 518 if (self.target.hasClass(self.config.unfoldAnimationOut)) { 519 520 self.target.removeClass(self.config.unfoldAnimationOut) 521 .addClass('u-unfold--hidden'); 522 523 524 if (self.allInvokers.length) self.allInvokers.attr('aria-expanded', 'false'); 525 526 self.config.afterClose.call(self.target, self.element); 527 } 528 529 if (self.target.hasClass(self.config.unfoldAnimationIn)) { 530 531 if (self.allInvokers.length) self.allInvokers.attr('aria-expanded', 'true'); 532 533 self.config.afterOpen.call(self.target, self.element); 534 } 535 536 e.preventDefault(); 537 e.stopPropagation(); 538 }); 539 540 } 541 } 542 543 /** 544 * UnfoldSlide constructor. 545 * 546 * @param {jQuery} element 547 * @param {Object} config 548 * @constructor 549 */ 550 function UnfoldJSlide(element, config) { 551 if (!AbstractUnfold.call(this, element, config)) return; 552 553 this.target.addClass('u-unfold--jquery-slide u-unfold--hidden').hide(); 554 555 Object.defineProperty(this, 'defaultState', { 556 get: function () { 557 return this.target.hasClass('u-unfold--hidden'); 558 } 559 }); 560 } 561 562 /** 563 * Shows Unfold. 564 * 565 * @public 566 * @return {UnfoldSimple} 567 */ 568 UnfoldSimple.prototype.show = function () { 569 570 var activeEls = $(this)[0].config.unfoldTarget; 571 572 $('[data-unfold-target="' + activeEls + '"]').addClass('active'); 573 574 this.smartPosition(this.target); 575 576 this.target.removeClass('u-unfold--hidden'); 577 if (this.allInvokers.length) this.allInvokers.attr('aria-expanded', 'true'); 578 this.config.afterOpen.call(this.target, this.element); 579 580 return this; 581 }; 582 583 /** 584 * Hides Unfold. 585 * 586 * @public 587 * @return {UnfoldSimple} 588 */ 589 UnfoldSimple.prototype.hide = function () { 590 591 var activeEls = $(this)[0].config.unfoldTarget; 592 593 $('[data-unfold-target="' + activeEls + '"]').removeClass('active'); 594 595 this.target.addClass('u-unfold--hidden'); 596 if (this.allInvokers.length) this.allInvokers.attr('aria-expanded', 'false'); 597 this.config.afterClose.call(this.target, this.element); 598 599 return this; 600 }; 601 602 /** 603 * Shows Unfold. 604 * 605 * @public 606 * @return {UnfoldCSSAnimation} 607 */ 608 UnfoldCSSAnimation.prototype.show = function () { 609 610 var self = this, 611 activeEls = $(self)[0].config.unfoldTarget; 612 613 $('[data-unfold-target="' + activeEls + '"]').addClass('active'); 614 615 self.smartPosition(self.target); 616 617 self.target.removeClass('u-unfold--hidden') 618 .removeClass(self.config.unfoldAnimationOut); 619 620 if (!self.config.unfoldOverlay) { 621 622 self.target.addClass(self.config.unfoldAnimationIn); 623 624 } else { 625 626 setTimeout(function () { 627 628 self.target.addClass(self.config.unfoldAnimationIn); 629 630 }); 631 632 } 633 634 self.config.afterOpen.call(self.target, self.element); 635 636 }; 637 638 /** 639 * Hides Unfold. 640 * 641 * @public 642 * @return {UnfoldCSSAnimation} 643 */ 644 UnfoldCSSAnimation.prototype.hide = function () { 645 646 var activeEls = $(this)[0].config.unfoldTarget; 647 648 $('[data-unfold-target="' + activeEls + '"]').removeClass('active'); 649 650 this.target.removeClass(this.config.unfoldAnimationIn) 651 .addClass(this.config.unfoldAnimationOut); 652 653 }; 654 655 /** 656 * Shows Unfold. 657 * 658 * @public 659 * @return {UnfoldJSlide} 660 */ 661 UnfoldJSlide.prototype.show = function () { 662 663 var self = this; 664
665 var activeEls = $(this)[0].config.unfoldTarget; 666 667 $('[data-unfold-target="' + activeEls + '"]').addClass('active'); 668 669 this.smartPosition(this.target); 670 671 this.target.removeClass('u-unfold--hidden').stop().slideDown({ 672 duration: self.config.unfoldDuration, 673 easing: self.config.unfoldEasing, 674 complete: function () { 675 self.config.afterOpen.call(self.target, self.element); 676 } 677 }); 678 679 }; 680 681 /** 682 * Hides Unfold. 683 * 684 * @public 685 * @return {UnfoldJSlide} 686 */ 687 UnfoldJSlide.prototype.hide = function () { 688 689 var self = this; 690 691 var activeEls = $(this)[0].config.unfoldTarget; 692 693 $('[data-unfold-target="' + activeEls + '"]').removeClass('active'); 694 695 this.target.slideUp({ 696 duration: self.config.unfoldDuration, 697 easing: self.config.unfoldEasing, 698 complete: function () { 699 self.config.afterClose.call(self.target, self.element); 700 self.target.addClass('u-unfold--hidden'); 701 } 702 }); 703 704 } 705 706})(jQuery);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.