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 $('.' + $(el).data('HSUnfold').config.unfoldOverlay.className).fadeOut($(el).data('HSUnfold').config.unfoldOverlay.animationSpeed ? $(el).data('HSUnfold').config.unfoldOverlay.animationSpeed : 200); 200 201 }); 202 203 $('body').removeClass('u-unfold-opened'); 204 205 } 206 207 } 208 209 }); 210 211 return collection; 212 213 }, 214 215 /** 216 * Binds necessary events. 217 * 218 * @param {jQuery} $invoker 219 * @param {String} eventType 220 * @param {Number} delay 221 * @private 222 */ 223 _bindEvents: function ($invoker, eventType, delay) { 224 225 var self = this, 226 $unfold = $($invoker.data('unfold-target')); 227 228 if (eventType === 'hover' && !_isTouch()) { 229 230 $invoker.on('mouseenter.HSUnfold', function () { 231 232 var $invoker = $(this), 233 HSUnfold = $invoker.data('HSUnfold'); 234 235 if (!HSUnfold) return; 236 237 if (HSUnfold.unfoldTimeOut) clearTimeout(HSUnfold.unfoldTimeOut); 238 HSUnfold.show(); 239 $('body').addClass('u-unfold-opened'); 240 241 }) 242 .on('mouseleave.HSUnfold', function () { 243 244 var $invoker = $(this), 245 HSUnfold = $invoker.data('HSUnfold'); 246 247 if (!HSUnfold) return; 248 249 HSUnfold.unfoldTimeOut = setTimeout(function () { 250 251 HSUnfold.hide(); 252 $('body').removeClass('u-unfold-opened'); 253 254 }, delay); 255 256 }); 257 258 if ($unfold.length) { 259 260 $unfold.on('mouseenter.HSUnfold', function () { 261 262 var HSUnfold = $invoker.data('HSUnfold'); 263 264 if (HSUnfold.unfoldTimeOut) clearTimeout(HSUnfold.unfoldTimeOut); 265 HSUnfold.show(); 266 267 }) 268 .on('mouseleave.HSUnfold', function () { 269 270 var HSUnfold = $invoker.data('HSUnfold'); 271 272 HSUnfold.unfoldTimeOut = setTimeout(function () { 273 HSUnfold.hide(); 274 }, delay); 275 276 }); 277 } 278 279 } else { 280 281 $invoker.on('click.HSUnfold', function (e) { 282 283 var $curInvoker = $(this), 284 $unfoldNotHasInnerUnfolds = $('[data-unfold-target].active:not(.target-of-invoker-has-unfolds)'), 285 $unfoldHasInnerUnfold = $('[data-unfold-target].active.target-of-invoker-has-unfolds'); 286 287 self._baseConfig.unfoldOpenedElement = $curInvoker.data('HSUnfold').target[0].id; 288 289 if (!$curInvoker.data('HSUnfold')) return; 290 291 if (!$curInvoker.hasClass('target-of-invoker-has-unfolds')) { 292 293 if ($unfoldNotHasInnerUnfolds.length) { 294 295 $unfoldNotHasInnerUnfolds.data('HSUnfold').toggle(); 296 297 } 298 299 } else { 300 301 if ($unfoldHasInnerUnfold.length) { 302 303 $unfoldHasInnerUnfold.data('HSUnfold').toggle(); 304 305 } 306 307 } 308 309 $curInvoker.data('HSUnfold').toggle(); 310 $('body').toggleClass('u-unfold-opened'); 311 312 e.stopPropagation(); 313 314 e.preventDefault(); 315 316 }); 317 318 if (Boolean($invoker.data('unfold-target-is-menu'))) { 319 320 var $target = $($invoker.data('unfold-target')), 321 $targetItems = $target.children(); 322 323 $targetItems.on('click', function () { 324 325 $invoker.data('HSUnfold').toggle(); 326 327 }); 328 329 } 330 331 } 332 333 } 334 }; 335 336 function _isTouch() { 337 return 'ontouchstart' in window; 338 } 339 340 /** 341 * Abstract Unfold class. 342 * 343 * @param {jQuery} element 344 * @param {Object} config 345 * @abstract 346 */ 347 function AbstractUnfold(element, config) { 348 349 var $self = this; 350 351 if (!element.length) return false; 352 353 $self.element = element; 354 $self.config = config; 355 356 $self.target = $($self.element.data('unfold-target')); 357 358 $self.allInvokers = $('[data-unfold-target="' + $self.element.data('unfold-target') + '"]'); 359 360 $self.toggle = function () { 361 if (!$self.target.length) return $self; 362 363 var dataset = $self.element[0].dataset,
364 overlay = dataset.unfoldOverlay ? JSON.parse(dataset.unfoldOverlay) : false; 365 366 if ($self.defaultState) { 367 368 if (dataset.unfoldOverlay) { 369 370 if (!$('.' + overlay.className).length) { 371 372 $('<div class="' + overlay.className + '" style="background-color: ' + overlay.background + '"></div>').prependTo('body'); 373 374 } 375 376 if ($('.' + overlay.className).length) { 377 378 $('.' + overlay.className).fadeIn(overlay.animationSpeed ? overlay.animationSpeed : 200); 379 380 } 381 382 } 383 384 $self.show(); 385 386 } else { 387 388 if ($('.' + overlay.className).length) { 389 390 $self.config.unfoldTimeOut = setTimeout(function () { 391 392 $('.' + overlay.className).fadeOut(overlay.animationSpeed ? overlay.animationSpeed : 200); 393 394 }, $self.config.unfoldDelay) 395 396 } 397 398 $self.hide(); 399 400 } 401 402 return $self; 403 }; 404 405 this.smartPosition = function (target) { 406 407 if (target.data('baseDirection')) { 408 target.css( 409 target.data('baseDirection').direction, 410 target.data('baseDirection').value 411 ); 412 } 413 414 target.removeClass('u-unfold--reverse-y'); 415 416 var $w = $(window), 417 styles = getComputedStyle(target.get(0)), 418 direction = Math.abs(parseInt(styles.left, 10)) < 40 ? 'left' : 'right', 419 targetOuterGeometry = target.offset(); 420 421 // horizontal axis 422 if (direction === 'right') { 423 424 if (!target.data('baseDirection')) target.data('baseDirection', { 425 direction: 'right', 426 value: parseInt(styles.right, 10) 427 }); 428 429 if (targetOuterGeometry.left < 0) { 430 431 target.css( 432 'right', 433 (parseInt(target.css('right'), 10) - (targetOuterGeometry.left - 10)) * -1 434 ); 435 436 } 437 438 } else { 439 440 if (!target.data('baseDirection')) target.data('baseDirection', { 441 direction: 'left', 442 value: parseInt(styles.left, 10) 443 }); 444 445 if (targetOuterGeometry.left + target.outerWidth() > $w.width()) { 446 447 target.css( 448 'left', 449 (parseInt(target.css('left'), 10) - (targetOuterGeometry.left + target.outerWidth() + 10 - $w.width())) 450 ); 451 452 } 453 454 } 455 456 // vertical axis 457 if (targetOuterGeometry.top + target.outerHeight() - $w.scrollTop() > $w.height()) { 458 459 target.addClass('u-unfold--reverse-y'); 460 461 } 462 463 }; 464 465 this.getOption = function (option) { 466 return this.config[option] ? this.config[option] : null; 467 }; 468 469 return true; 470 } 471 472 473 /** 474 * UnfoldSimple constructor. 475 * 476 * @param {jQuery} element 477 * @param {Object} config 478 * @constructor 479 */ 480 function UnfoldSimple(element, config) { 481 if (!AbstractUnfold.call(this, element, config)) return; 482 483 Object.defineProperty(this, 'defaultState', { 484 get: function () { 485 return this.target.hasClass('u-unfold--hidden'); 486 } 487 }); 488 489 this.target.addClass('u-unfold--simple'); 490 491 this.hide(); 492 } 493 494 /** 495 * UnfoldCSSAnimation constructor. 496 * 497 * @param {jQuery} element 498 * @param {Object} config 499 * @constructor 500 */ 501 function UnfoldCSSAnimation(element, config) { 502 if (!AbstractUnfold.call(this, element, config)) return; 503 504 var self = this; 505 506 this.target 507 .addClass('u-unfold--css-animation u-unfold--hidden') 508 .css('animation-duration', self.config.unfoldDuration + 'ms'); 509 510 Object.defineProperty(this, 'defaultState', { 511 get: function () { 512 return this.target.hasClass('u-unfold--hidden'); 513 } 514 }); 515 516 if (this.target.length) { 517 518 this.target.on('webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend', function (e) { 519 520 if (self.target.hasClass(self.config.unfoldAnimationOut)) { 521 522 self.target.removeClass(self.config.unfoldAnimationOut) 523 .addClass('u-unfold--hidden'); 524 525 526 if (self.allInvokers.length) self.allInvokers.attr('aria-expanded', 'false'); 527 528 self.config.afterClose.call(self.target, self.element); 529 } 530 531 if (self.target.hasClass(self.config.unfoldAnimationIn)) { 532 533 if (self.allInvokers.length) self.allInvokers.attr('aria-expanded', 'true'); 534 535 self.config.afterOpen.call(self.target, self.element); 536 } 537 538 e.preventDefault(); 539 e.stopPropagation(); 540 }); 541 542 } 543 } 544 545 /** 546 * UnfoldSlide constructor. 547 * 548 * @param {jQuery} element 549 * @param {Object} config 550 * @constructor 551 */ 552 function UnfoldJSlide(element, config) { 553 if (!AbstractUnfold.call(this, element, config)) return; 554 555 this.target.addClass('u-unfold--jquery-slide u-unfold--hidden').hide(); 556 557 Object.defineProperty(this, 'defaultState', { 558 get: function () { 559 return this.target.hasClass('u-unfold--hidden'); 560 } 561 }); 562 } 563 564 /** 565 * Shows Unfold. 566 * 567 * @public 568 * @return {UnfoldSimple} 569 */ 570 UnfoldSimple.prototype.show = function () { 571 572 var activeEls = $(this)[0].config.unfoldTarget; 573 574 $('[data-unfold-target="' + activeEls + '"]').addClass('active'); 575 576 this.smartPosition(this.target); 577 578 this.target.removeClass('u-unfold--hidden'); 579 if (this.allInvokers.length) this.allInvokers.attr('aria-expanded', 'true'); 580 this.config.afterOpen.call(this.target, this.element); 581 582 return this; 583 }; 584 585 /** 586 * Hides Unfold. 587 * 588 * @public 589 * @return {UnfoldSimple} 590 */ 591 UnfoldSimple.prototype.hide = function () { 592 593 var activeEls = $(this)[0].config.unfoldTarget; 594 595 $('[data-unfold-target="' + activeEls + '"]').removeClass('active'); 596 597 this.target.addClass('u-unfold--hidden'); 598 if (this.allInvokers.length) this.allInvokers.attr('aria-expanded', 'false'); 599 this.config.afterClose.call(this.target, this.element); 600 601 return this; 602 }; 603 604 /** 605 * Shows Unfold. 606 * 607 * @public 608 * @return {UnfoldCSSAnimation} 609 */ 610 UnfoldCSSAnimation.prototype.show = function () { 611 612 var self = this, 613 activeEls = $(self)[0].config.unfoldTarget; 614 615 $('[data-unfold-target="' + activeEls + '"]').addClass('active'); 616 617 self.smartPosition(self.target); 618 619 self.target.removeClass('u-unfold--hidden') 620 .removeClass(self.config.unfoldAnimationOut); 621 622 if (!self.config.unfoldOverlay) { 623 624 self.target.addClass(self.config.unfoldAnimationIn); 625 626 } else { 627 628 setTimeout(function () { 629 630 self.target.addClass(self.config.unfoldAnimationIn); 631 632 }); 633 634 } 635 636 self.config.afterOpen.call(self.target, self.element); 637 638 }; 639 640 /** 641 * Hides Unfold. 642 * 643 * @public 644 * @return {UnfoldCSSAnimation} 645 */ 646 UnfoldCSSAnimation.prototype.hide = function () { 647 648 var activeEls = $(this)[0].config.unfoldTarget; 649 650 $('[data-unfold-target="' + activeEls + '"]').removeClass('active'); 651 652 this.target.removeClass(this.config.unfoldAnimationIn) 653 .addClass(this.config.unfoldAnimationOut); 654 655 }; 656 657 /** 658 * Shows Unfold. 659 * 660 * @public 661 * @return {UnfoldJSlide} 662 */ 663 UnfoldJSlide.prototype.show = function () { 664 665 var self = this; 666
667 var activeEls = $(this)[0].config.unfoldTarget; 668 669 $('[data-unfold-target="' + activeEls + '"]').addClass('active'); 670 671 this.smartPosition(this.target); 672 673 this.target.removeClass('u-unfold--hidden').stop().slideDown({ 674 duration: self.config.unfoldDuration, 675 easing: self.config.unfoldEasing, 676 complete: function () { 677 self.config.afterOpen.call(self.target, self.element); 678 } 679 }); 680 681 }; 682 683 /** 684 * Hides Unfold. 685 * 686 * @public 687 * @return {UnfoldJSlide} 688 */ 689 UnfoldJSlide.prototype.hide = function () { 690 691 var self = this; 692 693 var activeEls = $(this)[0].config.unfoldTarget; 694 695 $('[data-unfold-target="' + activeEls + '"]').removeClass('active'); 696 697 this.target.slideUp({ 698 duration: self.config.unfoldDuration, 699 easing: self.config.unfoldEasing, 700 complete: function () { 701 self.config.afterClose.call(self.target, self.element); 702 self.target.addClass('u-unfold--hidden'); 703 } 704 }); 705 706 } 707 708})(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.