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