1(function ($, Drupal) { 2 "use strict"; 3 Drupal.behaviors.myBehavior = { 4 weight: 50, 5 attach: function (context, settings) { 6 7 // Internet Explorer 6-11 8 var isIE = /*@cc_on!@*/ false || !!document.documentMode; 9 10 11 //////////////////////////////////////////////////////////////////////// 12 // add/remove 'shrinked-header' class on scroll 13 14 // $(window, context).once('shrink-header').each(function () { 15 // const shrinkOn = 90; //$header-height - $shrinked-header-height 16 // var shrinked = false; 17 // //console.log(shrinked + ' ' + Date.now()); 18 19 // $(this).scroll(function () { 20 // var curScrollPos = $(this).scrollTop(); 21 // if (curScrollPos > shrinkOn && !shrinked) { 22 // $('#main-body').addClass("shrinked-header"); 23 // shrinked = true; 24 // //console.log('sh+: ' + Date.now()); 25 // } else if (curScrollPos <= shrinkOn && shrinked) { 26 // $('#main-body').removeClass("shrinked-header"); 27 // shrinked = false; 28 // //console.log('sh-: ' + Date.now()); 29 // } 30 // }); 31 // }); 32 33 //////////////////////////////////////////////////////////////////////// 34 // cookie 35 36 37 function setCookie(name, value, days) { 38 var expires = ""; 39 if (days) { 40 var date = new Date(); 41 date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000)); 42 expires = "; expires=" + date.toUTCString(); 43 } 44 document.cookie = name + "=" + (value || "") + expires + "; path=/"; 45 } 46 47 function getCookie(name) { 48 var nameEQ = name + "="; 49 var ca = document.cookie.split(';'); 50 for (var i = 0; i < ca.length; i++) { 51 var c = ca[i]; 52 while (c.charAt(0) == ' ') c = c.substring(1, c.length); 53 if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length); 54 } 55 return null; 56 } 57 58 function eraseCookie(name) { 59 document.cookie = name + '=; Path=/; Expires=Thu, 01 Jan 1970 00:00:01 GMT;'; 60 } 61 62 //////////////////////////////////////////////////////////////////////// 63 // color 64 65 // var urlParams = new URLSearchParams(window.location.search); 66 67 68 // if (urlParams.has('color')) { 69 // if (urlParams.get('color') == 1) { 70 // console.log(getCookie('test_color')); 71 // setCookie('test_color', 1, 3); 72 // $('#main-body').removeClass('bw'); 73 // } else { 74 // console.log('sf'); 75 // eraseCookie('test_color'); 76 // } 77 // } else { 78 // if (getCookie('test_color')) { 79 // $('#main-body').removeClass('bw'); 80 // } 81 // } 82 83 // if (getCookie('color_site')) { 84 // $('#main-body').removeClass('bw'); 85 // } 86 87 // $('.changeColor').click(function (e) { 88 // e.preventDefault(); 89 // if (getCookie('color_site')) { 90 // eraseCookie('color_site'); 91 // $('#main-body').addClass('bw'); 92 // } else { 93 // $('#main-body').removeClass('bw'); 94 // setCookie('color_site', 1, 365); 95 // } 96 // ym(56495734,'reachGoal','color'); 97 // }); 98 99 //////////////////////////////////////////////////////////////////////// 100 // show/hide extended search bar 101 102 $("#main-body", context).once("search-block").each(function () { 103 const search = $("#search-block"); 104 var extended = false; 105 //console.log(extended + ' ' + Date.now()); 106 107 $(this).click(function (e) { 108 // if the target of the click isn't the container 109 // and nor a descendant of the container 110 if (extended && !search.is(e.target) && search.has(e.target).length === 0) { 111 search.removeClass('extended'); 112 extended = false; 113 //console.log('ext-: ' + Date.now()); 114 } 115 }); 116 search.click(function () { 117 if (!extended) { 118 $(this).addClass("extended"); 119 $(this).find("input").focus(); 120 extended = true; 121 //console.log('ext+: ' + Date.now()); 122 } 123 }); 124 }); 125
126 //////////////////////////////////////////////////////////////////////// 127 // toggle-menu 128 129 $("#toggle-menu", context).once("toggle-menu").click(function () { 130 $("#header-nav-secondary, #mainmenu").toggleClass("show"); 131 $(this).toggleClass("is-active"); 132 }); 133 134 //////////////////////////////////////////////////////////////////////// 135 // side-menu 136 137 $('.local-menu-wrapper', context).once('side-menu').click(function () { 138 $(this).toggleClass('collapsed'); 139 }); 140 141 //////////////////////////////////////////////////////////////////////// 142 // Smooth scrolling when clicking an anchor link 143 144 // $('a[href^="#"]').click(function () { 145 // $('html, body').animate({ 146 // scrollTop: $('[name="' + $.attr(this, 'href').substr(1) + '"]').offset().top 147 // }, 500); 148 // return false; 149 // }); 150 151 //////////////////////////////////////////////////////////////////////// 152 // 153 154 $("#block-2fakultety," + 155 "#block-2departments," + 156 "#block-departments-ru-eng," + 157 "#block-menu-block-international," + 158 "#block-menu-block-international-en," + 159 "#block-menu-block-university," + 160 "#block-menu-university-en," + 161 "#block-menu-research," + 162 "#block-menu-research-en," + 163 "#block-3issledovaniya," + 164 "#block-3issledovaniya-en," + 165 "#block-menu-block-admissions," + 166 "#block-menu-block-additional," + 167 "#block-menu-block-additional-en", context 168 ).children(".menu-switcher").click(function () { 169 $(this).parent().children('.menu').toggleClass("show"); 170 }); 171 172 $("#block-main-events-filters," + 173 "#block-main-news-filters," + 174 "#block-main-announcements-filters," + 175 "#block-electronic-resources-filters," + 176 "#block-raskrytayaformasearchpage-1", context 177 ).children(".block-title").click(function () { 178 $(this).parent().children('.block-content').toggleClass("hidden"); 179 }); 180 181 function jump(h) { 182 var top = document.getElementById(h).offsetTop; 183 window.scrollTo(0, top); 184 } 185 186 //////////////////////////////////////////////////////////////////////// 187 // selectpiker auto-trigger 188 189 $('.selectpicker.auto-trigger', context).change(function () { 190 var currentValue = $(this).val(); 191 var url = window.location.protocol + "//" + window.location.host + window.location.pathname 192 var urlParams = new URLSearchParams(window.location.search); 193 $(this).closest('form').find('[id^="edit-submit-"]').trigger('click'); 194 urlParams.set('section', currentValue); 195 window.history.replaceState(null, null, url + '?' + urlParams); 196 }); 197 198 // END: selectpiker auto-trigger 199 //////////////////////////////////////////////////////////////////////// 200 201 //////////////////////////////////////////////////////////////////////// 202 // News Rubrics to Title 203 var validURLs = ['/news', '/en/news']; 204 if (!isIE && $.inArray(window.location.pathname, validURLs) > -1) { 205 206 //console.log(window.location.pathname); 207 208 var titleID = '#euheader-section'; 209 var baseTitle = $(titleID, context).find('h1').text(); 210 var formID = '#views-exposed-form-news-main-news'; 211 var submitButtonSelector = '[id^="edit-submit-news"]'; 212 var dataSelector = formID + ' select[data-drupal-selector="edit-rubric"]'; 213 214 //add initial rubric to title 215 $(titleID, context).each(function () { 216 var initialValue = $(dataSelector).val(); 217 //console.log(initialValue); 218 if (initialValue != 'All') { 219 var additionalTitle = $(dataSelector).find('option:selected').text(); 220 $(this).find('h1').text(baseTitle + ": " + additionalTitle); 221 } 222 }); 223 224 // add rubric to title on chenge 225 $(dataSelector, context).change(function () { 226 var url = window.location.protocol + "//" + window.location.host + window.location.pathname
227 var urlParams = new URLSearchParams(window.location.search); 228 var additionalTitle = ''; 229 var currentValue = $(this).val(); 230 if (currentValue != 'All') { 231 additionalTitle = ': ' + $(this).find('option:selected').text(); 232 } 233 $(titleID).find('h1').text(baseTitle + additionalTitle); 234 urlParams.set('rubric', currentValue); 235 window.history.replaceState(null, null, url + '?' + urlParams); 236 $(submitButtonSelector).trigger('click'); 237 }); 238 239 } 240 // END: News Rubrics to Title 241 //////////////////////////////////////////////////////////////////////// 242 243 244 //////////////////////////////////////////////////////////////////////// 245 // EUSP Online Views Exposed Filters 246 // Autosubmit on change any filters 247 248 if (isIE) { 249 250 $('#eu-online-controls', context).hide(); 251 $('.view-euonline .view-filters').show(); 252 253 } else { 254 255 if (window.location.pathname == '/online' || window.location.pathname == '/en/online') { 256 257 //console.log(window.location.pathname); 258 259 var url = window.location.protocol + "//" + window.location.host + window.location.pathname 260 var urlParams = new URLSearchParams(window.location.search); 261 262 //console.log('eee'); 263 264 var euOnlineFormID = '#views-exposed-form-euonline-euonline-bydate'; 265 var sortByOrigSelector = euOnlineFormID + ' select[data-drupal-selector="edit-sort-by"]'; 266 var sectionOrigSelector = euOnlineFormID + ' select[data-drupal-selector="edit-section"]'; 267 var sectionEnOrigSelector = euOnlineFormID + ' select[data-drupal-selector="edit-section-en"]'; 268 var textOrigSelector = euOnlineFormID + ' input[data-drupal-selector="edit-text"]'; 269 var submitButtonSelector = '[id^="edit-submit-euonline"]'; 270 271 //apply initial values to custom filters elements 272 $('#eu-online-controls', context).each(function () { 273 274 var submit = false; 275 276 //console.log(context); 277 278 // custom buttons for sort by 279 var sortbyInitialValue = $(sortByOrigSelector).val(); 280 if (urlParams.get('sort_by') && sortbyInitialValue != urlParams.get('sort_by')) { 281 var sortbyInitialValue = urlParams.get('sort_by'); 282 $(sortByOrigSelector).val(sortbyInitialValue).change(); 283 submit = true; 284 } else { 285 $('#' + sortbyInitialValue).parent().addClass('active'); 286 } 287 console.log('sortby: ' + submit); 288 289 // custom select for sections 290 var sectionInitialValue = $(sectionOrigSelector).val(); 291 if (urlParams.get('section') && sectionInitialValue != urlParams.get('section')) { 292 var sectionInitialValue = urlParams.get('section'); 293 $(sectionOrigSelector).val(sectionInitialValue).change(); 294 submit = true; 295 } else { 296 $('#eu-online-section-control').val(sectionInitialValue).change(); 297 } 298 console.log('section: ' + submit); 299 300 // custom select for sections en 301 var sectionEnInitialValue = $(sectionEnOrigSelector).val(); 302 if (urlParams.get('section_en') && sectionEnInitialValue != urlParams.get('section_en')) { 303 var sectionEnInitialValue = urlParams.get('section_en'); 304 $(sectionEnOrigSelector).val(sectionEnInitialValue).change(); 305 submit = true; 306 } else { 307 $('#eu-online-section-en-control').val(sectionEnInitialValue).change(); 308 } 309 console.log('sectionEn: ' + submit); 310 311 // custom search for text search 312 var textInitialValue = $(textOrigSelector).val(), 313 textFromUrlParams = urlParams.get('text'); 314 if (textFromUrlParams && textInitialValue != textFromUrlParams) { 315 $(textOrigSelector).val(textFromUrlParams); 316 submit = true; 317 } else { 318 $('#eu-online-text-control').val(textInitialValue).change(); 319 } 320 console.log('text: ' + submit); 321 322 // submit initial values 323 if (submit) $(submitButtonSelector).trigger('click'); 324 }); 325 326 // Autosubmit: Sort By 327 $('#eu-online-sort-by-control :input', context).change(function () { 328 var sortByCurrentValue = $(this).attr('id'); 329 $(sortByOrigSelector).val(sortByCurrentValue).change(); 330 $(submitButtonSelector).trigger('click');
331 urlParams.set('sort_by', sortByCurrentValue); 332 window.history.replaceState(null, null, url + '?' + urlParams); 333 }) 334 335 // Autosubmit: Section 336 $('#eu-online-section-control', context).change(function () { 337 var sectionCurrentValue = $(this).val(); 338 $(sectionOrigSelector).val(sectionCurrentValue).change(); 339 $(submitButtonSelector).trigger('click'); 340 urlParams.set('section', sectionCurrentValue); 341 window.history.replaceState(null, null, url + '?' + urlParams); 342 }); 343 344 // Autosubmit: Section en 345 $('#eu-online-section-en-control', context).change(function () { 346 var sectionEnCurrentValue = $(this).val(); 347 $(sectionEnOrigSelector).val(sectionEnCurrentValue).change(); 348 $(submitButtonSelector).trigger('click'); 349 urlParams.set('section_en', sectionEnCurrentValue); 350 window.history.replaceState(null, null, url + '?' + urlParams); 351 }); 352 353 // Autosubmit: Text search 354 var thread = null; 355 356 function textSearch(textCurrentValue) { 357 $(textOrigSelector).val(textCurrentValue); 358 $(submitButtonSelector).trigger('click'); 359 urlParams.set('text', textCurrentValue); 360 window.history.replaceState(null, null, url + '?' + urlParams); 361 } 362 363 $('#eu-online-text-control', context).on('keyup', function () { 364 clearTimeout(thread); 365 var $this = $(this); 366 thread = setTimeout(function () { 367 textSearch($this.val()) 368 }, 1000); 369 }); 370 371 } 372 373 } 374 // END: EUSP Online Views Exposed Filters 375 //////////////////////////////////////////////////////////////////////// 376 377 378 //////////////////////////////////////////////////////////////////////// 379 // Programs Views Exposed Filters 380 // Autosubmit on change any filters 381 382 if (isIE) { 383 384 $('#programs-controls', context).hide(); 385 $('.view-programs .view-filters').show(); 386 387 } else { 388 389 if (['/programs', '/programs/', '/en/programs', '/en/programs/', '/programs/cards'].includes(window.location.pathname)) { 390 391 //console.log(window.location.pathname); 392 393 var url = window.location.protocol + "//" + window.location.host + window.location.pathname 394 var urlParams = new URLSearchParams(window.location.search); 395 396 //console.log('eee'); 397 398 399 // if (window.location.pathname == '/programs/cards') { 400 // var programsFormID = '#views-exposed-form-programs-all-programs-cards'; 401 // } else { 402 // var programsFormID = '#views-exposed-form-programs-all-programs'; 403 // } 404 var programsFormID = '#views-exposed-form-programs-all-programs-cards'; 405 var plangOrigSelector = programsFormID + ' select[data-drupal-selector="edit-plang"]'; 406 var typeOrigSelector = programsFormID + ' select[data-drupal-selector="edit-type"]'; 407 var directionOrigSelector = programsFormID + ' select[data-drupal-selector="edit-direction"]'; 408 var textOrigSelector = programsFormID + ' input[data-drupal-selector="edit-text"]'; 409 var submitButtonSelector = '[id^="edit-submit-programs"]'; 410 411 //apply initial values to custom filters elements 412 $('#programs-controls', context).each(function () { 413 414 var submit = false; 415 416 //console.log(context); 417 418 // custom buttons for plang 419 var plangInitialValue = $(plangOrigSelector).val(); 420 if (urlParams.get('plang') && plangInitialValue != urlParams.get('plang')) { 421 var plangInitialValue = urlParams.get('plang'); 422 $(plangOrigSelector).val(plangInitialValue).change(); 423 submit = true; 424 } else { 425 $('#plang_' + plangInitialValue).parent().addClass('active'); 426 } 427 428 // custom buttons for type 429 var typeInitialValue = $(typeOrigSelector).val(); 430 if (urlParams.get('type') && typeInitialValue != urlParam
430s.get('type')) { 431 var typeInitialValue = urlParams.get('type'); 432 $(typeOrigSelector).val(typeInitialValue).change(); 433 submit = true; 434 } else { 435 $('#type_' + typeInitialValue).parent().addClass('active'); 436 } 437 438 // custom select for direction 439 var directionInitialValue = $(directionOrigSelector).val(); 440 if (urlParams.get('direction') && directionInitialValue != urlParams.get('direction')) { 441 var directionInitialValue = urlParams.get('direction'); 442 $(directionOrigSelector).val(directionInitialValue).change(); 443 submit = true; 444 } else { 445 $('#programs-direction-control').val(directionInitialValue).change(); 446 } 447 448 // custom search for text search 449 var textInitialValue = $(textOrigSelector).val(), 450 textFromUrlParams = urlParams.get('text'); 451 if (textFromUrlParams && textInitialValue != textFromUrlParams) { 452 $(textOrigSelector).val(textFromUrlParams); 453 submit = true; 454 } else { 455 $('#programs-text-control').val(textInitialValue).change(); 456 } 457 458 // submit initial values 459 if (submit) $(submitButtonSelector).trigger('click'); 460 }); 461 462 // Autosubmit: plang 463 $('#plang-control :input', context).change(function () { 464 var plangCurrentValue = $(this).attr('id').substring(6); 465 $(plangOrigSelector).val(plangCurrentValue).change(); 466 $(submitButtonSelector).trigger('click'); 467 urlParams.set('plang', plangCurrentValue); 468 window.history.replaceState(null, null, url + '?' + urlParams); 469 }) 470 471 // Autosubmit: Type 472 $('#programs-type-control :input', context).change(function () { 473 var typeCurrentValue = $(this).attr('id').substring(5); 474 $(typeOrigSelector).val(typeCurrentValue).change(); 475 $(submitButtonSelector).trigger('click'); 476 urlParams.set('type', typeCurrentValue); 477 window.history.replaceState(null, null, url + '?' + urlParams); 478 }) 479 480 // Autosubmit: Section 481 $('#programs-direction-control', context).change(function () { 482 var directionCurrentValue = $(this).val(); 483 $(directionOrigSelector).val(directionCurrentValue).change(); 484 $(submitButtonSelector).trigger('click'); 485 urlParams.set('direction', directionCurrentValue); 486 window.history.replaceState(null, null, url + '?' + urlParams); 487 }); 488 489 // Autosubmit: Text search 490 var thread = null; 491 492 function textSearch(textCurrentValue) { 493 $(textOrigSelector).val(textCurrentValue); 494 $(submitButtonSelector).trigger('click'); 495 urlParams.set('text', textCurrentValue); 496 window.history.replaceState(null, null, url + '?' + urlParams); 497 } 498 499 $('#programs-text-control', context).on('keyup', function () { 500 clearTimeout(thread); 501 var $this = $(this); 502 thread = setTimeout(function () { 503 textSearch($this.val()) 504 }, 1000); 505 }); 506 507 } 508 509 } 510 // END: Programs Views Exposed Filters 511 //////////////////////////////////////////////////////////////////////// 512 513 514 //////////////////////////////////////////////////////////////////////// 515 // EUSP Donation form 516 517 if (window.location.pathname == '/make-donation' || window.location.pathname == '/en/make-donation') { 518 519 $('.webform-submission-podderzhat-universitet-form').once('donation-form').each(function () { 520 521 var nameHidden = $(this).find('input[data-drupal-selector="edit-name-hidden"]', context); 522 var name = $(this).find('input[data-drupal-selector="edit-name"]', context); 523 524 var amountHidden = $(this).find('input[data-drupal-selector="edit-amount-hidden"]', context); 525 var amount = $(this).find('select[data-drupal-selector="edit-amount-select"]', context); 526 var amountOther = $(this).find('input[data-drupal-selector="edit-amount-other"]', context); 527 528 var targetHidden = $(this).find('input[data-drupal-selector="edit-target-hidden"]', context); 529 var target = $(this).find('select[data-drupal-selector="edit-target"]', context); 530 531 var recurrentHidden = $(this).find('input[data-drupal-selector="edit-recurrent-hidden"]', context); 532 var recurrent = $(this).find('input[data-drupal-selector="edit-recurrent"]', context); 533 534 var emailHidden = $(this).find('input[data-drupal-selector="edit-donor-email-hidden"]', context); 535 var email = $(this).find('input[data-drupal-selector="edit-donor-email"]', context); 536 537 var iamHidden = $(this).find('input[data-drupal-selector="edit-i-am-hidden"]', context); 538 var iam = $(this).find('select[data-drupal-selector="edit-i-am"]', context); 539 540 var donationCompleted = $(this).find('input[data-drupal-selector="edit-donation-is-completed"]', context); 541 542 var step = $(this).find('.form-wrapper[data-webform-key]', context); 543 var stepValue = ''; 544 if (step.length > 0) stepValue = step.data('webform-key'); 545 console.log('Step: ' + stepValue); 546
547 //////////////////////////////////////////////////// 548 // 1st step: donation form 549 if (stepValue == 'donation_form') { 550 551 /////////////////// Name 552 nameHidden.val(name.val()); //console.log(nameHidden.val()); 553 name.on('focusout', function () { 554 nameHidden.val($(this).val()); 555 }); 556 557 /////////////////// Amount 558 var newAmountValue = amount.val(); 559 if (newAmountValue != '_other_') { 560 amountHidden.val(newAmountValue); 561 amountOther.val(newAmountValue); 562 //console.log(amountHidden.val()); 563 } 564 amount.change(function () { 565 newAmountValue = $(this).val(); 566 if (newAmountValue != '_other_') amountHidden.val(newAmountValue); 567 }); 568 amountOther.on('focusout', function () { 569 newAmountValue = $(this).val(); 570 if (newAmountValue && newAmountValue >= 100) amountHidden.val(newAmountValue); 571 }); 572
573 /////////////////// Target 574 targetHidden.val(target.val()); //console.log(targetHidden.val()); 575 target.change(function () { 576 targetHidden.val($(this).val()); 577 }); 578 579 /////////////////// Recurrent? 580 recurrentHidden.val(recurrent.is(":checked")); //console.log(recurrentHidden.val()); 581 recurrent.change(function () { 582 recurrentHidden.val($(this).is(":checked")); 583 console.log(recurrentHidden.val()); 584 }); 585 586 /////////////////// e-mail 587 emailHidden.val(email.val()); //console.log(emailHidden.val()); 588 email.on('focusout', function () { 589 emailHidden.val($(this).val()); 590 }); 591 592 /////////////////// I am 593 iamHidden.val(iam.val()); //console.log(iamHidden.val()); 594 iam.change(function () { 595 iamHidden.val($(this).val()); 596 }); 597 598 //////////////////////////////////////////////////// 599 // 2nd step: payment 600 } else if (stepValue == 'payment') { 601 602 //console.log(Date.now()); 603 604 function donation() { 605 var widget = new cp.CloudPayments(); 606 var data = { 607 name: nameHidden.val(), 608 donor: iamHidden.val() 609 }; 610 var amountValue = parseFloat(amountHidden.val()); 611 var target = "ÐожеÑÑвование на поддеÑжкÑ: " + targetHidden.val(); 612 var accountId = emailHidden.val(); 613 if (recurrentHidden.val() == 'true') { 614 data.cloudPayments = { 615 recurrent: { 616 interval: 'Month', 617 period: 1 618 } 619 } 620 console.log(Date.now()); 621 } 622 widget.charge({ 623 publicId: 'pk_4b122180185ad23bba1fbfe2cd9c7', 624 description: target, 625 amount: amountValue, 626 currency: 'RUB', 627 accountId: accountId, 628 email: accountId, 629 data: data 630 }, 631 function (options) { // success 632 //дейÑÑвие пÑи ÑÑпеÑной оплаÑе 633 jump('donation-bottom'); 634 jump('main-content'); 635 $('input[data-drupal-selector="edit-donation-is-completed"]', context).prop("checked", true); 636 $('[id^="edit-actions-submit"]', context).trigger('click'); 637 console.log('success'); 638 }, 639 function (reason, options) { // fail 640 //дейÑÑвие пÑи неÑÑпеÑной оплаÑе 641 console.log(reason); 642 }); 643 } 644 645 donation(); 646 647 } 648 649 }); 650 651 } 652 653 // END: EUSP Donation form 654 //////////////////////////////////////////////////////////////////////// 655 656 657 //////////////////////////////////////////////////////////////////////// 658 // VDNKH temp 659 660 // if (window.location.pathname == '/events/xiv-obscherossiyskaya-nauchnaya-konferenciya-vdnkh' || window.location.pathname == '/events/xiv-obscherossiyskaya-nauchnaya-konferenciya-vdnkh/') { 661 // setTimeout(function(){ 662 // $('div.ckeditor-accordion-container', context).each(function () { 663 // $(this).find('dt.active').removeClass('active'); 664 // $(this).find('dd.active').removeClass('active').hide(); 665 // }); 666 // }, 1000); 667 // } 668 669 // END: VDNKH temp 670 //////////////////////////////////////////////////////////////////////// 671 672 673 //////////////////////////////////////////////////////////////////////// 674 // Main with Side Slideshow synchronization 675 676 $('.slideshow.main-with-side', context).once('main-with-side-slideshow').each(function() { 677 var $wrapper = $(this); 678 var $mainSlider = $wrapper.find('.slideshow-main .slick-slider'); 679 var $sideContainer = $wrapper.find('.slideshow-side'); 680 var $sideElements = $sideContainer.find('.slideshow-element'); 681 682 // Ðдем иниÑиализаÑии главного Slick ÑлайдеÑа 683 var checkSlick = setInterval(function() { 684 if ($mainSlider.hasClass('slick-initialized')) { 685 clearInterval(checkSlick); 686 initMainWithSideSlideshow($mainSlider, $sideContainer, $sideElements); 687 } 688 }, 100); 689 }); 690 691 function initMainWithSideSlideshow($mainSlider, $sideContainer, $sideElements) { 692 // УÑÑанавливаем пеÑвÑй Ñлайд как акÑивнÑй пÑи загÑÑзке 693 $sideElements.first().addClass('active'); 694 695 // Ð¡Ð¸Ð½Ñ ÑонизаÑиÑ: клик на боковом Ñлайде пеÑеклÑÑÐ°ÐµÑ Ð³Ð»Ð°Ð²Ð½Ñй 696 $sideElements.on('click', function(e) { 697 e.preventDefault(); 698 var slideIndex = $(this).index(); 699 if (slideIndex !== undefined && slideIndex >= 0) { 700 $mainSlider.slick('slickGoTo', slideIndex); 701 } 702 }); 703 704 // Ð¡Ð¸Ð½Ñ ÑонизаÑиÑ: пÑи изменении главного Ñлайда обновлÑем акÑивнÑй боковой 705 $mainSlider.on('afterChange', function(event, slick, currentSlide) { 706 $sideElements.removeClass('active'); 707 $sideElements.eq(currentSlide).addClass('active'); 708 }); 709 } 710 711 // END: Main with Side Slideshow synchronization
712 //////////////////////////////////////////////////////////////////////// 713 714 //////////////////////////////////////////////////////////////////////// 715 // Main with Side Slideshow for View (FlexSlider) 716 717 $('.slideshow-block.main-with-side', context).once('main-with-side-view-slideshow').each(function() { 718 var $wrapper = $(this); 719 var $flexslider = $wrapper.find('.flexslider'); 720 721 $flexslider.on('init', function() { 722 var $slider = $(this); 723 var flexslider = $slider.data('flexslider'); 724 stopFlexsliderAutoplay(flexslider); 725 resetFlexsliderSlideStyles($slider); 726 }); 727 728 var checkFlexslider = setInterval(function() { 729 if ($flexslider.data('flexslider')) { 730 clearInterval(checkFlexslider); 731 initMainWithSideViewSlideshow($flexslider); 732 } 733 }, 10); 734 }); 735 736 function stopFlexsliderAutoplay(flexslider) { 737 if (!flexslider) { 738 return; 739 } 740 if (typeof flexslider.pause === 'function') { 741 flexslider.pause(); 742 } 743 if (flexslider.animatedSlides) { 744 clearInterval(flexslider.animatedSlides); 745 flexslider.animatedSlides = false; 746 } 747 if (flexslider.vars) { 748 flexslider.vars.slideshow = false; 749 } 750 if (typeof flexslider.animating !== 'undefined') { 751 flexslider.animating = false; 752 } 753 } 754 755 function resetFlexsliderSlideStyles($flexslider) { 756 $flexslider.find('.slides > li').each(function() { 757 $(this).css({ 758 marginRight: '', 759 float: '', 760 width: '', 761 opacity: '', 762 zIndex: '', 763 display: '', 764 position: '', 765 left: '', 766 top: '' 767 }); 768 }); 769 } 770 771 function initMainWithSideViewSlideshow($flexslider) { 772 if ($flexslider.data('mainWithSideReady')) { 773 return; 774 } 775 $flexslider.data('mainWithSideReady', true); 776 777 var $wrapper = $flexslider.closest('.slideshow-block.main-with-side'); 778 var flexslider = $flexslider.data('flexslider'); 779 stopFlexsliderAutoplay(flexslider); 780 781 var $slidesContainer = $flexslider.find('.slides'); 782 var slidesArray = $slidesContainer.find('> li').toArray(); 783 var totalSlides = slidesArray.length; 784 if (!totalSlides) { 785 return; 786 } 787 788 slidesArray.forEach(function(slide, i) { 789 $(slide).attr('data-original-index', i); 790 }); 791 792 var currentIndex = 0; 793 var autoRotateInterval = null; 794 var slideDuration = 15000; 795 var mobileQuery = window.matchMedia('(max-width: 768px)'); 796 var $mobileControls = null; 797 var touchStartX = 0; 798 var touchStartY = 0; 799 800 function isMobile() { 801 return mobileQuery.matches; 802 } 803 804 function updateSlidesDisplay() { 805 var mainIndex = currentIndex % totalSlides; 806 var side1Index = (currentIndex + 1) % totalSlides; 807 var side2Index = (currentIndex + 2) % totalSlides; 808 809 var orderedSlides = [ 810 slidesArray[mainIndex], 811 side1Index !== mainIndex ? slidesArray[side1Index] : null, 812 side2Index !== mainIndex && side2Index !== side1Index ? slidesArray[side2Index] : null 813 ].filter(function(slide) { 814 return slide !== null; 815 }); 816 817 // prepend в обÑаÑном поÑÑдке: main, side1, side2 оказÑваÑÑÑÑ Ð¿ÐµÑвÑми в DOM 818 // (append оÑпÑавлÑл Ð¸Ñ Ð² конеÑ, и CSS :nth-child(1-3) показÑвал не Ñе ÑлайдÑ) 819 for (var i = orderedSlides.length - 1; i >= 0; i--) { 820 $slidesContainer.prepend(orderedSlides[i]); 821 } 822 823 resetFlexsliderSlideStyles($flexslider); 824 updateMobileNav(); 825 } 826 827 function goToSlide(index) { 828 if (index < 0 || index >= totalSlides || index === currentIndex) { 829 return; 830 } 831 currentIndex = index; 832 updateSlidesDisplay(); 833 restartAutoplay(); 834 } 835 836 function nextSlide() { 837 goToSlide((currentIndex + 1) % totalSlides); 838 } 839 840 function prevSlide() { 841 goToSlide((currentIndex - 1 + totalSlides) % totalSlides); 842 } 843 844 function restartAutoplay() { 845 if (autoRotateInterval) { 846 clearInterval(autoRotateInterval); 847 } 848 autoRotateInterval = setInterval(nextSlide, slideDuration); 849 } 850 851 function updateMobileNav() { 852 if (!$mobileControls || !$mobileControls.length) { 853 return; 854 } 855 $mobileControls.find('.slideshow-mobile-dots button') 856 .removeClass('is-active') 857 .attr('aria-selected', 'false') 858 .eq(currentIndex) 859 .addClass('is-active') 860 .attr('aria-selected', 'true'); 861 } 862 863 function syncMobileControlsVisibility() { 864 if (!$mobileControls || !$mobileControls.length) { 865 return; 866 } 867 var showControls = isMobile() && totalSlides > 1;
868 $mobileControls.toggle(showControls); 869 $flexslider.toggleClass('has-mobile-swipe', showControls); 870 } 871 872 function buildMobileNav() { 873 if (totalSlides <= 1 || $wrapper.find('.slideshow-mobile-controls').length) { 874 return; 875 } 876 877 $mobileControls = $('<div class="slideshow-mobile-controls" aria-label="ÐавигаÑÐ¸Ñ Ð¿Ð¾ баннеÑам"></div>'); 878 var $dots = $('<ol class="slideshow-mobile-dots" role="tablist"></ol>'); 879 880 for (var i = 0; i < totalSlides; i++) { 881 $dots.append( 882 $('<li role="presentation"><button type="button" role="tab" aria-label="Слайд ' + (i + 1) + '" data-slide-index="' + i + '"></button></li>') 883 ); 884 } 885 886 $mobileControls.append($dots); 887 $wrapper.append($mobileControls); 888 889 $dots.on('click', 'button', function(e) { 890 e.preventDefault(); 891 var idx = parseInt($(this).attr('data-slide-index'), 10); 892 if (!isNaN(idx)) { 893 goToSlide(idx); 894 } 895 }); 896 897 syncMobileControlsVisibility(); 898 updateMobileNav(); 899 } 900 901 $flexslider.on('click', '.slides > li:nth-child(2), .slides > li:nth-child(3)', function(e) { 902 e.preventDefault(); 903 var clickedIndex = parseInt($(this).attr('data-original-index'), 10); 904 if (!isNaN(clickedIndex)) { 905 goToSlide(clickedIndex); 906 } 907 }); 908 909 $flexslider.on('touchstart', function(e) { 910 if (!isMobile() || totalSlides <= 1) { 911 return; 912 } 913 touchStartX = e.originalEvent.touches[0].clientX; 914 touchStartY = e.originalEvent.touches[0].clientY; 915 }); 916 917 $flexslider.on('touchend', function(e) { 918 if (!isMobile() || totalSlides <= 1) { 919 return; 920 } 921 var touch = e.originalEvent.changedTouches[0]; 922 var deltaX = touch.clientX - touchStartX; 923 var deltaY = touch.clientY - touchStartY; 924 if (Math.abs(deltaX) < 50 || Math.abs(deltaX) < Math.abs(deltaY)) { 925 return; 926 } 927 if (deltaX < 0) { 928 nextSlide(); 929 } else { 930 prevSlide(); 931 } 932 }); 933 934 if (typeof mobileQuery.addEventListener === 'function') { 935 mobileQuery.addEventListener('change', syncMobileControlsVisibility); 936 } else if (typeof mobileQuery.addListener === 'function') { 937 mobileQuery.addListener(syncMobileControlsVisibility); 938 } 939 940 buildMobileNav(); 941 updateSlidesDisplay(); 942 $flexslider.addClass('main-with-side-initialized'); 943 $wrapper.addClass('main-with-side-ready'); 944 restartAutoplay(); 945 946 $flexslider.on('mouseenter', function() { 947 if (autoRotateInterval) { 948 clearInterval(autoRotateInterval); 949 autoRotateInterval = null; 950 } 951 }); 952 953 $flexslider.on('mouseleave', function() { 954 restartAutoplay(); 955 }); 956 } 957 958 // END: Main with Side Slideshow for View (FlexSlider) 959 //////////////////////////////////////////////////////////////////////// 960 961 // Programs Carousel - ÑепеÑÑ Ð¸Ð½Ð¸ÑиализиÑÑеÑÑÑ ÑеÑез модÑÐ»Ñ Slick в админке 962 // JavaScript иниÑиализаÑÐ¸Ñ Ð±Ð¾Ð»ÑÑе не нÑжна, Ñак как модÑÐ»Ñ Slick Ð´ÐµÐ»Ð°ÐµÑ ÑÑо авÑомаÑиÑеÑки 963 //////////////////////////////////////////////////////////////////////// 964 965 // Program filters: reset button and AJAX handling 966 //////////////////////////////////////////////////////////////////////// 967 $(context).find('.program-filters').once('programFilters').each(function() { 968 var $filters = $(this); 969 var $form = $filters.closest('form'); 970 971 // Ðнопка ÑбÑоÑа ÑилÑÑÑа 972 $filters.find('.filter-reset-btn').on('click', function(e) { 973 e.preventDefault(); 974 975 // СбÑаÑÑваем вÑе ÑекбокÑÑ/Ñадиокнопки 976 $filters.find('input[type="checkbox"]:checked, input[type="radio"]:checked').prop('checked', false); 977 978 // ÐÑли еÑÑÑ select, ÑбÑаÑÑваем его 979 $filters.find('select').val('').trigger('change'); 980 981 // СбÑаÑÑваем кнопки select (еÑли они бÑли ÑозданÑ) 982 $filters.find('.filter-button-select').removeClass('active'); 983 984 // ÐÑпÑавлÑем ÑоÑÐ¼Ñ 985 if ($form.length) { 986 // ÐÑли AJAX вклÑÑен, иÑполÑзÑем его 987 if ($form.hasClass('views-ajax-form') || $form.data('ajax-submit')) { 988 $form.trigger('submit'); 989 } else { 990 // ÐнаÑе обÑÑÐ½Ð°Ñ Ð¾ÑпÑавка 991 $form.submit(); 992 } 993 } 994 }); 995 996 // ÐбÑабоÑка клика по ÑилÑÑÑам без пеÑезагÑÑзки (еÑли AJAX вклÑÑен) 997 $filters.find('input[type="checkbox"], input[type="radio"]').on('change', function() { 998 if ($form.hasClass('views-ajax-form') || $form.data('ajax-submit')) { 999 // ÐеболÑÑÐ°Ñ Ð·Ð°Ð´ÐµÑжка Ð´Ð»Ñ AJAX 1000 clearTimeout(window.filterTimeout); 1001 window.filterTimeout = setTimeout(function() { 1002 $form.trigger('submit'); 1003 }, 300); 1004 } 1005 }); 1006 }); 1007 1008 // Convert select to buttons for program filters
1009 //////////////////////////////////////////////////////////////////////// 1010 $(context).find('.program-filters select').once('convertSelectToButtons').each(function() { 1011 var $select = $(this); 1012 var $container = $select.closest('.filter-buttons'); 1013 1014 if ($container.length === 0) { 1015 $container = $select.parent(); 1016 } 1017 1018 // Create buttons container 1019 var $buttonsContainer = $('<div class="select-buttons"></div>'); 1020 1021 // Create button for each option 1022 $select.find('option').each(function() { 1023 var $option = $(this); 1024 var value = $option.val(); 1025 var text = $option.text(); 1026 1027 if (value === '' || value === '_none') { 1028 return; // Skip empty option 1029 } 1030 1031 var $button = $('<button type="button" class="filter-button-select" data-value="' + value + '">' + text + '</button>'); 1032 1033 // Mark as active if selected 1034 if ($option.prop('selected')) { 1035 $button.addClass('active'); 1036 } 1037 1038 // Click handler 1039 $button.on('click', function(e) { 1040 e.preventDefault(); 1041 1042 // Update select 1043 $select.val(value).trigger('change'); 1044 1045 // Update button states 1046 $buttonsContainer.find('.filter-button-select').removeClass('active'); 1047 $button.addClass('active'); 1048 1049 // Submit form (with AJAX if available) 1050 var $form = $select.closest('form'); 1051 if ($form.hasClass('views-ajax-form') || $form.data('ajax-submit')) { 1052 $form.trigger('submit'); 1053 } else { 1054 $form.submit(); 1055 } 1056 }); 1057 1058 $buttonsContainer.append($button); 1059 }); 1060 1061 // Hide select and show buttons 1062 $select.hide().after($buttonsContainer); 1063 }); 1064 // END: Convert select to buttons 1065 //////////////////////////////////////////////////////////////////////// 1066 1067 //////////////////////////////////////////////////////////////////////// 1068 // Horizontal scroll with mouse wheel for programs carousel 1069 //////////////////////////////////////////////////////////////////////// 1070 $(context).find('.programs-carousel:not(.slick-initialized)').once('programsCarouselWheel').each(function() { 1071 var $carousel = $(this); 1072 1073 // Horizontal scroll with mouse wheel 1074 $carousel.on('wheel', function(e) { 1075 // Only if not at the edges 1076 var scrollLeft = this.scrollLeft; 1077 var scrollWidth = this.scrollWidth; 1078 var clientWidth = this.clientWidth; 1079 1080 // Check if we can scroll in the direction of the wheel 1081 if ((e.originalEvent.deltaY > 0 && scrollLeft < scrollWidth - clientWidth) || 1082 (e.originalEvent.deltaY < 0 && scrollLeft > 0)) { 1083 e.preventDefault(); 1084 this.scrollLeft += e.originalEvent.deltaY; 1085 } 1086 }); 1087 }); 1088 // END: Horizontal scroll with mouse wheel 1089 //////////////////////////////////////////////////////////////////////// 1090 1091 //////////////////////////////////////////////////////////////////////// 1092 // Scroll affordance for homepage program carousels (desktop gradient) 1093 //////////////////////////////////////////////////////////////////////// 1094 $(context).find('.programs-main-section .view-content').once('programsScrollAffordance').each(function() { 1095 var $container = $(this); 1096 var $section = $container.closest('.programs-main-section'); 1097 var $carousel = $container.find('.programs-carousel:not(.slick-initialized)'); 1098 1099 if ($carousel.length === 0) { 1100 return; 1101 } 1102 1103 function updateScrollState() { 1104 var el = $carousel[0]; 1105 var scrollLeft = el.scrollLeft; 1106 var scrollWidth = el.scrollWidth; 1107 var clientWidth = el.clientWidth; 1108 var atEnd = scrollLeft >= scrollWidth - clientWidth - 5; 1109 var canScroll = scrollWidth > clientWidth + 5; 1110 1111 $section.toggleClass('is-scrolled-end', atEnd); 1112 $section.toggleClass('has-scroll', canScroll); 1113 } 1114 1115 setTimeout(updateScrollState, 100); 1116 $carousel.on('scroll', updateScrollState); 1117 $(window).on('resize', updateScrollState); 1118 }); 1119 // END: Scroll affordance
1120 //////////////////////////////////////////////////////////////////////// 1121 1122 //////////////////////////////////////////////////////////////////////// 1123 // Navigation arrows for programs carousel (desktop) - динамиÑеÑкие ÑÑÑелки 1124 // ÐÑименÑем ко вÑем блокам пÑогÑамм: магиÑÑÑаÑÑÑа, аÑпиÑанÑÑÑа, ÐÐÐ 1125 //////////////////////////////////////////////////////////////////////// 1126 $(context).find('.programs-main-section .view-content, .program-section .view-content, .view-programmy .view-content').once('programsCarouselArrows').each(function() { 1127 var $container = $(this); 1128 1129 // Ðа главной иÑполÑзÑем ÐºÐ½Ð¾Ð¿ÐºÑ Â«ÑмоÑÑеÑÑ Ð±Ð¾Ð»ÑÑе» вмеÑÑо ÑÑÑелок. 1130 if ($container.closest('.programs-main-section').length > 0) { 1131 return; 1132 } 1133 1134 var $carousel = $container.find('.programs-carousel:not(.slick-initialized)'); 1135 var $slickCarousel = $container.find('.slick-slider'); 1136 1137 // ÐбÑабоÑка наÑивного ÑкÑолла (без Slick) 1138 if ($carousel.length > 0) { 1139 // Create arrows if they don't exist 1140 if ($container.find('.carousel-nav-arrow').length === 0) { 1141 var $prevArrow = $('<button type="button" class="carousel-nav-arrow carousel-nav-prev" aria-label="ÐÑедÑдÑÑие"><span>â¹</span></button>'); 1142 var $nextArrow = $('<button type="button" class="carousel-nav-arrow carousel-nav-next" aria-label="СледÑÑÑие"><span>âº</span></button>'); 1143 1144 $container.css('position', 'relative'); 1145 $container.append($prevArrow); 1146 $container.append($nextArrow); 1147 1148 // Update arrow visibility based on scroll position 1149 function updateArrows() { 1150 var scrollLeft = $carousel[0].scrollLeft; 1151 var scrollWidth = $carousel[0].scrollWidth; 1152 var clientWidth = $carousel[0].clientWidth; 1153 1154 // ÐоказÑваем левÑÑ ÑÑÑÐµÐ»ÐºÑ ÑолÑко еÑли можно пÑокÑÑÑиÑÑ Ð²Ð»ÐµÐ²Ð¾ 1155 if (scrollLeft > 5) { 1156 $prevArrow.addClass('show'); 1157 } else { 1158 $prevArrow.removeClass('show'); 1159 } 1160 1161 // ÐоказÑваем пÑавÑÑ ÑÑÑÐµÐ»ÐºÑ ÑолÑко еÑли можно пÑокÑÑÑиÑÑ Ð²Ð¿Ñаво 1162 if (scrollLeft < scrollWidth - clientWidth - 5) { 1163 $nextArrow.addClass('show'); 1164 } else { 1165 $nextArrow.removeClass('show'); 1166 } 1167 } 1168 1169 // Initial check 1170 setTimeout(updateArrows, 100); 1171 1172 // Update on scroll 1173 $carousel.on('scroll', updateArrows); 1174 1175 // Update on resize 1176 $(window).on('resize', updateArrows); 1177 1178 // Click handlers 1179 $prevArrow.on('click', function() { 1180 $carousel.animate({ 1181 scrollLeft: '-=300' 1182 }, 300); 1183 }); 1184 1185 $nextArrow.on('click', function() { 1186 $carousel.animate({ 1187 scrollLeft: '+=300' 1188 }, 300); 1189 }); 1190 } 1191 } 1192 1193 // ÐбÑабоÑка Slick Carousel 1194 if ($slickCarousel.length > 0 && typeof $.fn.slick !== 'undefined') { 1195 // СкÑÑваем ÑÑандаÑÑнÑе ÑÑÑелки Slick и Ñоздаем Ñвои 1196 $slickCarousel.find('.slick-prev, .slick-next').css({ 1197 'display': 'none !important', 1198 'visibility': 'hidden', 1199 'opacity': '0' 1200 }); 1201 1202 if ($container.find('.carousel-nav-arrow').length === 0) { 1203 var $prevArrow = $('<button type="button" class="carousel-nav-arrow carousel-nav-prev" aria-label="ÐÑедÑдÑÑие"><span>â¹</span></button>'); 1204 var $nextArrow = $('<button type="button" class="carousel-nav-arrow carousel-nav-next" aria-label="СледÑÑÑие"><span>âº</span></button>'); 1205 1206 $container.css('position', 'relative'); 1207 $container.append($prevArrow); 1208 $container.append($nextArrow); 1209 1210 function updateSlickArrows() { 1211 try { 1212 var currentSlide = $slickCarousel.slick('slickCurrentSlide') || 0; 1213 var slideCount = $slickCarousel.slick('getOption', 'slidesToShow') || 4; 1214 var totalSlides = $slickCarousel.find('.slick-slide:not(.slick-cloned)').length; 1215 1216 // ÐоказÑваем левÑÑ ÑÑÑÐµÐ»ÐºÑ ÑолÑко еÑли не на пеÑвом Ñлайде 1217 if (currentSlide > 0) { 1218 $prevArrow.addClass('show'); 1219 } else { 1220 $prevArrow.removeClass('show'); 1221 } 1222 1223 // ÐоказÑваем пÑавÑÑ ÑÑÑÐµÐ»ÐºÑ ÑолÑко еÑли не на поÑледнем Ñлайде
1224 var canGoNext = currentSlide < totalSlides - slideCount; 1225 if (canGoNext) { 1226 $nextArrow.addClass('show'); 1227 } else { 1228 $nextArrow.removeClass('show'); 1229 } 1230 } catch(e) { 1231 console.log('Error updating Slick arrows:', e); 1232 } 1233 } 1234 1235 // Update on Slick events 1236 $slickCarousel.on('afterChange', updateSlickArrows); 1237 $slickCarousel.on('init', updateSlickArrows); 1238 $slickCarousel.on('reInit', updateSlickArrows); 1239 1240 // Initial check - неÑколÑко попÑÑок, Ñак как Slick Ð¼Ð¾Ð¶ÐµÑ Ð¸Ð½Ð¸ÑиализиÑоваÑÑÑÑ Ð¿Ð¾Ð·Ð¶Ðµ 1241 setTimeout(updateSlickArrows, 200); 1242 setTimeout(updateSlickArrows, 500); 1243 setTimeout(updateSlickArrows, 1000); 1244 1245 // Click handlers 1246 $prevArrow.on('click', function() { 1247 $slickCarousel.slick('slickPrev'); 1248 }); 1249 1250 $nextArrow.on('click', function() { 1251 $slickCarousel.slick('slickNext'); 1252 }); 1253 } 1254 } 1255 }); 1256 // END: Navigation arrows 1257 //////////////////////////////////////////////////////////////////////// 1258 1259 //////////////////////////////////////////////////////////////////////// 1260 // Navigation arrows for alumni carousel (desktop) 1261 //////////////////////////////////////////////////////////////////////// 1262 $(context).find('.alumni-carousel-wrapper').once('alumniCarouselArrows').each(function() { 1263 var $container = $(this); 1264 var $carousel = $container.find('.alumni-carousel'); 1265 1266 if ($carousel.length === 0) return; 1267 1268 // Create arrows if they don't exist 1269 if ($container.find('.alumni-carousel-nav').length === 0) { 1270 var $prevArrow = $('<button type="button" class="alumni-carousel-nav alumni-carousel-nav-prev" aria-label="ÐÑедÑдÑÑие"><span>â¹</span></button>'); 1271 var $nextArrow = $('<button type="button" class="alumni-carousel-nav alumni-carousel-nav-next" aria-label="СледÑÑÑие"><span>âº</span></button>'); 1272 1273 $container.css('position', 'relative'); 1274 $container.append($prevArrow); 1275 $container.append($nextArrow); 1276 1277 // Update arrow visibility based on scroll position 1278 function updateArrows() { 1279 var scrollLeft = $carousel[0].scrollLeft; 1280 var scrollWidth = $carousel[0].scrollWidth; 1281 var clientWidth = $carousel[0].clientWidth; 1282 1283 $prevArrow.toggle(scrollLeft > 0); 1284 $nextArrow.toggle(scrollLeft < scrollWidth - clientWidth - 1); 1285 } 1286 1287 // Initial check 1288 updateArrows(); 1289 1290 // Update on scroll 1291 $carousel.on('scroll', updateArrows); 1292 1293 // Update on resize 1294 $(window).on('resize', updateArrows); 1295 1296 // Click handlers 1297 $prevArrow.on('click', function() { 1298 $carousel.animate({ 1299 scrollLeft: '-=280' 1300 }, 300); 1301 }); 1302 1303 $nextArrow.on('click', function() { 1304 $carousel.animate({ 1305 scrollLeft: '+=280' 1306 }, 300); 1307 }); 1308 } 1309 }); 1310 // END: Alumni carousel navigation arrows 1311 //////////////////////////////////////////////////////////////////////// 1312 1313 //////////////////////////////////////////////////////////////////////// 1314 // Navigation dots for alumni carousel 1315 //////////////////////////////////////////////////////////////////////// 1316 $(context).find('.alumni-carousel-wrapper').once('alumniCarouselDots').each(function() { 1317 var $container = $(this); 1318 var $carousel = $container.find('.alumni-carousel'); 1319 1320 if ($carousel.length === 0) return; 1321 1322 var $alumniItems = $carousel.find('.alumni'); 1323 if ($alumniItems.length === 0) return; 1324 1325 // Calculate how many items are visible at once 1326 function getVisibleCount() { 1327 var carouselWidth = $carousel[0].clientWidth; 1328 var itemWidth = $alumniItems.first().outerWidth(true); 1329 return Math.floor(carouselWidth / itemWidth);
1330 } 1331 1332 // Calculate total number of "pages" (groups of visible items) 1333 function getTotalPages() { 1334 var visibleCount = getVisibleCount(); 1335 return Math.ceil($alumniItems.length / visibleCount); 1336 } 1337 1338 // Create dots container if it doesn't exist 1339 var $dotsContainer = $container.find('.alumni-carousel-dots'); 1340 if ($dotsContainer.length === 0) { 1341 $dotsContainer = $('<ul class="alumni-carousel-dots"></ul>'); 1342 $container.append($dotsContainer); 1343 } 1344 1345 // Update dots based on current scroll position 1346 function updateDots() { 1347 var scrollLeft = $carousel[0].scrollLeft; 1348 var carouselWidth = $carousel[0].clientWidth; 1349 var itemWidth = $alumniItems.first().outerWidth(true); 1350 var visibleCount = Math.floor(carouselWidth / itemWidth); 1351 var currentPage = Math.round(scrollLeft / (itemWidth * visibleCount)); 1352 var totalPages = Math.ceil($alumniItems.length / visibleCount); 1353 1354 // Clear and recreate dots 1355 $dotsContainer.empty(); 1356 1357 for (var i = 0; i < totalPages; i++) { 1358 var $dot = $('<li><button type="button" class="alumni-carousel-dot" data-page="' + i + '" aria-label="СÑÑаниÑа ' + (i + 1) + '"></button></li>'); 1359 if (i === currentPage) { 1360 $dot.find('button').addClass('active'); 1361 } 1362 $dotsContainer.append($dot); 1363 } 1364 } 1365 1366 // Scroll to specific page 1367 function scrollToPage(page) { 1368 var carouselWidth = $carousel[0].clientWidth; 1369 var itemWidth = $alumniItems.first().outerWidth(true); 1370 var visibleCount = Math.floor(carouselWidth / itemWidth); 1371 var scrollPosition = page * itemWidth * visibleCount; 1372 1373 $carousel.animate({ 1374 scrollLeft: scrollPosition 1375 }, 300); 1376 } 1377 1378 // Click handler for dots 1379 $dotsContainer.on('click', '.alumni-carousel-dot', function() { 1380 var page = parseInt($(this).attr('data-page')); 1381 scrollToPage(page); 1382 }); 1383 1384 // Update dots on scroll 1385 $carousel.on('scroll', updateDots); 1386 1387 // Update dots on resize 1388 $(window).on('resize', function() { 1389 updateDots(); 1390 }); 1391 1392 // Initial dots creation 1393 updateDots(); 1394 }); 1395 // END: Alumni carousel navigation dots 1396 //////////////////////////////////////////////////////////////////////// 1397 1398 //////////////////////////////////////////////////////////////////////// 1399 // Testimonials carousel on main page 1400 //////////////////////////////////////////////////////////////////////// 1401 $(context).find('.testimonials-main-section .testimonials-carousel').once('testimonialsCarousel').each(function () { 1402 var $carousel = $(this); 1403 // ÐлеменÑÑ ÐºÐ°ÑÑÑели: ÑнаÑала иÑем .testimonial-item, еÑли Ð¸Ñ Ð½ÐµÑ â беÑем .views-row 1404 var $items = $carousel.find('.testimonial-item'); 1405 if ($items.length === 0) { 1406 $items = $carousel.find('.views-row'); 1407 } 1408 var totalTestimonials = $items.length; 1409 if (!totalTestimonials) { 1410 return; 1411 } 1412 1413 var currentTestimonial = 0; 1414 var autoplayInterval = 20000; // 15 ÑекÑнд Ð¼ÐµÐ¶Ð´Ñ Ñлайдами 1415 var autoplayTimer = null; 1416 1417 // ÐонÑÐµÐ¹Ð½ÐµÑ Ñ ÑоÑками ÑÑдом Ñ ÑекÑÑей каÑÑÑелÑÑ 1418 var $section = $carousel.closest('.testimonials-main-section'); 1419 var $dotsContainer = $section.find('.testimonials-dots'); 1420 $dotsContainer.empty(); 1421 1422 for (var i = 0; i < totalTestimonials; i++) { 1423 var $dot = $('<button type="button" class="testimonials-dot"></button>'); 1424 $dot.attr('data-index', i); 1425 if (i === 0) { 1426 $dot.addClass('active'); 1427 } 1428 $dotsContainer.append($dot); 1429 } 1430 1431 function showTestimonial(index) { 1432 $items.hide(); 1433 $items.eq(index).fadeIn(300); 1434 1435 $dotsContainer.find('.testimonials-dot').removeClass('active'); 1436 $dotsContainer.find('.testimonials-dot').eq(index).addClass('active'); 1437 1438 currentTestimonial = index; 1439 } 1440 1441 function startAutoplay() { 1442 if (autoplayTimer) { 1443 clearInterval(autoplayTimer); 1444 } 1445 autoplayTimer = setInterval(function () { 1446 var nextIndex = (currentTestimonial + 1) % totalTestimonials; 1447 showTestimonial(nextIndex); 1448 }, autoplayInterval); 1449 } 1450 1451 // Ðоказ пеÑвого оÑзÑва и запÑÑк авÑопÑокÑÑÑки 1452 showTestimonial(0); 1453 startAutoplay(); 1454 1455 // ÐавигаÑÐ¸Ñ ÑÑÑелками Ð´Ð»Ñ ÑекÑÑей ÑекÑии 1456 $section.find('.testimonials-nav-arrow.prev').on('click', function () { 1457 var prevIndex = (currentTestimonial - 1 + totalTestimonials) % totalTestimonials; 1458 showTestimonial(prevIndex); 1459 startAutoplay(); 1460 }); 1461 1462 $section.find('.testimonials-nav-arrow.next').on('click', function () { 1463 var nextIndex = (currentTestimonial + 1) % totalTestimonials; 1464 showTestimonial(nextIndex); 1465 startAutoplay(); 1466 }); 1467 1468 // ÐавигаÑÐ¸Ñ ÑоÑками 1469 $dotsContainer.on('click', '.testimonials-dot', function () { 1470 var index = parseInt($(this).attr('data-index'), 10); 1471 if (!isNaN(index)) { 1472 showTestimonial(index); 1473 startAutoplay(); 1474 } 1475 }); 1476 }); 1477 // END: Testimonials carousel
1478 //////////////////////////////////////////////////////////////////////// 1479 1480 // СÑÑаниÑа «РÐвÑопейÑком»: ÑÑÑÐµÑ Ð¿Ð¾Ñле блоков лÑдей, аккоÑÐ´ÐµÐ¾Ð½Ñ ÑолÑко на ÑелеÑÐ¾Ð½Ð°Ñ . 1481 $('body.path-european_univers, body.path-en-european_univers', context).once('eu-univers-layout').each(function () { 1482 var $footer = $('#unit-footer'); 1483 var $peopleBlocks = $( 1484 '.block-views-blockpeople-block-1, ' + 1485 '.block-views-blockpeople-block-2, ' + 1486 '.block-views-blockpeople-block-3, ' + 1487 '.block-views-blockpeople-block-4' 1488 ); 1489 if ($footer.length && $peopleBlocks.length) { 1490 $footer.insertAfter($peopleBlocks.last()); 1491 } 1492 }); 1493 1494 var euPeopleBlockSelector = 1495 'body.path-european_univers .block-views-blockpeople-block-1, ' + 1496 'body.path-european_univers .block-views-blockpeople-block-2, ' + 1497 'body.path-european_univers .block-views-blockpeople-block-3, ' + 1498 'body.path-european_univers .block-views-blockpeople-block-4, ' + 1499 'body.path-en-european_univers .block-views-blockpeople-block-1, ' + 1500 'body.path-en-european_univers .block-views-blockpeople-block-2, ' + 1501 'body.path-en-european_univers .block-views-blockpeople-block-3, ' + 1502 'body.path-en-european_univers .block-views-blockpeople-block-4'; 1503 1504 function isEuUniversMobileAccordion() { 1505 return window.matchMedia('(max-width: 767px)').matches; 1506 } 1507 1508 function teardownEuPeopleAccordion($block) { 1509 if (!$block.hasClass('eu-people-section--ready')) { 1510 return; 1511 } 1512 1513 var $panel = $block.find('.eu-people-accordion-panel').first(); 1514 var $teaser = $panel.children('.people-teaser').first(); 1515 if ($teaser.length) { 1516 $panel.before($teaser); 1517 $panel.remove(); 1518 } 1519 1520 $block.find('.eu-people-block-header').remove(); 1521 1522 var $title = $block.find('.eu-people-block-content h2').first(); 1523 if ($title.length) { 1524 $title 1525 .addClass('block-title') 1526 .removeClass('eu-people-accordion-toggle collapsed') 1527 .removeAttr('data-toggle href aria-expanded aria-controls role'); 1528 $block.prepend($title); 1529 } 1530 1531 $block.removeClass('eu-people-section eu-people-section--ready eu-people-section--accordion'); 1532 } 1533 1534 function setupEuPeopleAccordion($block, index) { 1535 if ($block.hasClass('eu-people-section--ready')) { 1536 return; 1537 } 1538 1539 var $title = $block.children('h2.block-title').first(); 1540 var $peopleTeaser = $block.find('.people-teaser').first(); 1541 if (!$title.length || !$peopleTeaser.length) { 1542 return; 1543 } 1544 1545 var collapseId = 'eu-people-section-' + index; 1546 $block.addClass('eu-people-section eu-people-section--ready eu-people-section--accordion'); 1547 1548 $title.detach().removeClass('eu-people-accordion-toggle collapsed'); 1549 1550 var $header = $('<div class="eu-people-block-header structure-block-header"></div>'); 1551 var $contentWrap = $('<div class="eu-people-block-content structure-block-content"></div>'); 1552 $contentWrap.append($title); 1553 1554 var $toggle = $('<a class="eu-people-block-toggle structure-block-toggle collapsed"></a>') 1555 .attr({ 1556 'data-toggle': 'collapse', 1557 href: '#' + collapseId, 1558 'aria-expanded': 'false', 1559 'aria-controls': collapseId, 1560 role: 'button' 1561 }) 1562 .append($('<div class="structure-block-arrow">â¼</div>')); 1563 1564 $header.append($contentWrap).append($toggle); 1565 1566 $peopleTeaser.wrap( 1567 '<div class="collapse eu-people-accordion-panel structure-block-details" id="' + collapseId + '"></div>' 1568 ); 1569 $header.insertBefore($block.find('.eu-people-accordion-panel').first()); 1570 } 1571 1572 function refreshEuPeopleAccordions(accordionContext) { 1573 var $blocks = $(euPeopleBlockSelector, accordionContext); 1574 if (!$blocks.length) { 1575 return; 1576 } 1577 1578 if (isEuUniversMobileAccordion()) { 1579 $blocks.each(function (index) { 1580 teardownEuPeopleAccordion($(this)); 1581 setupEuPeopleAccordion($(this), index); 1582 }); 1583 } 1584 else { 1585 $blocks.each(function () { 1586 teardownEuPeopleAccordion($(this)); 1587 }); 1588 } 1589 } 1590 1591 $('body.path-european_univers, body.path-en-european_univers', context).once('eu-people-accordion-init').each(function () { 1592 refreshEuPeopleAccordions(context); 1593 }); 1594 1595 $(window, context).once('eu-people-accordion-resize').on('resize.euPeopleAccordion', function () { 1596 refreshEuPeopleAccordions(document); 1597 }); 1598 1599 } 1600 } 1601})(jQuery, Drupal);
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.