1(function($) { 2 $(document).ready(function() { 3 // 4 // Comparison Table 5 // 6 var $compTables = $('.js-comp_table'), 7 $compTablesLength = $compTables.length, 8 $compMoreButtons = $('.js-comp_table_more'), 9 allTableRows = [], 10 initTableRowLevel = function() { 11 if ( layoutView != 'small' && layoutView != 'medium' ) { 12 $compTables.imagesLoaded(function() { 13 for ( var i = 0; i < $compTablesLength; i++ ) { 14 var $curTable = $($compTables[i]); 15 $tableHeaders = $curTable.find('.js-comp_table_title'), 16 tableRows = [], 17 $tableLists = $curTable.find('.js-comp_table_list'), 18 tableListsLength = $tableLists.length; 19 for ( curListKey = 0; curListKey < tableListsLength; curListKey++ ) { 20 var $curList = $($tableLists[curListKey]), 21 $curListItems = $curList.find('.js-comp_table_cell'), 22 curListItemsLength = $curListItems.length; 23 for ( curCellKey = 0; curCellKey < curListItemsLength; curCellKey++ ) { 24 var $curListItem = $($curListItems[curCellKey]); 25 if ( typeof tableRows[curCellKey] == 'undefined' ) tableRows[curCellKey] = []; 26 tableRows[curCellKey].push($curListItem[0]); 27 } 28 } 29 tableRows.push($tableHeaders); 30 allTableRows = allTableRows.concat(tableRows);
31 var tableRowsLength = tableRows.length; 32 for ( var curTableRowKey = 0; curTableRowKey < tableRowsLength; curTableRowKey++ ) { 33 var $curRow = $(tableRows[curTableRowKey]); 34 levelHeight($curRow); 35 if ( $($curRow[0]).hasClass('js-comp_table_more_cell') ) { 36 $curRow.each(function() { 37 $(this).addClass('closed'); 38 }); 39 } 40 } 41 } 42 setMoreButtonPosition(); 43 }); 44 } 45 }, 46 setMoreButtonPosition = function() { 47 if ( layoutView == 'large' || layoutView == 'xlarge') { 48 for ( var i = 0; i < $compTablesLength; i++ ) { 49 var $curTable = $($compTables[i]), 50 $moreButtons = $curTable.find('.js-comp_table_more'); 51 if ( $moreButtons.length > 0 ) { 52 var $curLargeButton = $($moreButtons[0]), 53 $buttonLocation = $($moreButtons[1]), 54 buttonLocationOffset = $buttonLocation.offset(), 55 tableOffset = $curTable.find('.co-comp_table_box').offset(), 56 buttonTop = buttonLocationOffset.top - tableOffset.top; 57 $curLargeButton.css({top: buttonTop}); 58 } 59 } 60 } 61 }, 62 tableHeightSetting; 63 resetTabelRowLevels = function() { 64 setMoreButtonPosition(); 65 if ( layoutView == 'large' || layoutView == 'xlarge' ) { 66 tableHeightSetting = levelHeight; 67 } else { 68 tableHeightSetting = resetHeights; 69 }
70 var tableRowsLength = allTableRows.length; 71 for ( var i = 0; i < tableRowsLength; i++ ) { 72 tableHeightSetting(allTableRows[i]); 73 } 74 } 75 var toggleCompMore = function(x) { 76 var $x = $(x), 77 parentSelector = ''; 78 if ( layoutView == 'large' || layoutView == 'xlarge') { 79 // if at the larger layout toggle all of the rows 80 parentSelector = '.co-comp_table_box'; 81 } else { 82 // if at smaller layout toggle just this column 83 parentSelector = '.co-comp_table'; 84 } 85 var $itemsToToggle = $x.parents(parentSelector).find('.js-comp_table_more_cell'); 86 if ( $x.hasClass('closed') ) { 87 $itemsToToggle.removeClass('closed'); 88 $x.removeClass('closed'); 89 } else { 90 $itemsToToggle.addClass('closed'); 91 $x.addClass('closed'); 92 } 93 }, 94 redrawComparisonSlider = function($tabPanel) { 95 var $childSlider = $tabPanel.find('.bx-wrapper .co-comp_table_wrap'); 96 if ( $childSlider.length ) { 97 $childSlider = $childSlider.data('slider'); 98 $childSlider.redrawSlider(); 99 } 100 }, 101 getCompTableSliderFromNav = function(x) { 102 return $(x) 103 .parents('.co-flex_row') 104 .find('.bx-wrapper .co-comp_table_wrap') 105 .data('slider'); 106 }, 107 prevCompTableSlide = function(x) { 108 var curSlider = getCompTableSliderFromNav(x); 109 curSlider.goToPrevSlide(); 110 }, 111 nextCompTableSlide = function(x) { 112 var curSlider = getCompTableSliderFromNav(x); 113 curSlider.goToNextSlide(); 114 } 115 initCompTableCarousel = function() { 116 checkLayout(); 117 if ( layoutView == 'small' || layoutView == 'medium' ) { 118 var $compTableSliders = $('.js-comp_table'), 119 compTableSlidersLength = $compTableSliders.length; 120 for ( var i = 0; i < compTableSlidersLength; i++ ) { 121 var $curTable = $($compTableSliders[i]), 122 sliderSettings = { 123 useCSS: false, 124 pager: false, 125 infiniteLoop: false, 126 adaptiveHeight: true, 127 slideSelector: '.co-comp_table:not(.co-comp_table__key_0)', 128 controls: false, 129 preventDefaultSwipeY: false, 130 onSliderLoad: function() { 131 $(this[0]).data('slider', this); 132 } 133 }, 134 curSlider = $curTable 135 .find('.co-comp_table_wrap') 136 .bxSlider(sliderSettings); 137 } 138 } 139 }; 140 $compMoreButtons.click(function() { 141 if ( layoutView == 'large' || layoutView == 'xlarge' ) { 142 toggleCompMore(this); 143 } 144 }); 145 $compMoreButtons.on('touchstart', function(){ 146 if ( layoutView == 'small' || layoutView == 'medium' ) { 147 toggleCompMore(this); 148 } 149 }); 150 $('.js-comp_table_prev').click(function() { 151 prevCompTableSlide(this); 152 }); 153 $('.js-comp_table_next').click(function() { 154 nextCompTableSlide(this); 155 }); 156 initTableRowLevel(); 157 initCompTableCarousel(); 158 }); 159 160 // 161 // Scroll Button and Dot Navigation and Accordion functionality 162 // 163 $('.co-comp_table-mobile-section').each(function() { 164 const $table_scroll_section = $(this); 165 const $table_scroll_container = $table_scroll_section.find('.scrollContainer'); 166 const $table_scroll_button = $table_scroll_section.find('.scrollBtn'); 167 const $dot_navs = $table_scroll_section.find('.table-mobile-dot-nav'); 168 var scrollRight = true; 169 170 // Check if two-columns class is present and hide navigation elements 171 const $mobileTable = $table_scroll_section.find('.co-comp_table-mobile'); 172 if ($mobileTable.hasClass('co-comp_table-mobile-two-columns')) { 173 $table_scroll_section.find('.co-comp_table-mobile--scroll_button').hide(); 174 $table_scroll_section.find('.co-comp_table-mobile--dots').hide(); 175 } 176 177 // Calculate scrollStep based on accordion column width 178 function getScrollStep() { 179 const $firstAccordionColumn = $table_scroll_section.find('.co-comp_table-mobile--accordion_column').first(); 180 if ($firstAccordionColumn.length > 0) { 181 return $firstAccordionColumn.outerWidth(true) + 20; // Include margin and padding 182 } 183 return 150; // Fallback to original value if no columns found 184 } 185 186 // Function to update scroll button state 187 function updateScrollButtonState() { 188 const scrollLeft = $table_scroll_container.scrollLeft(); 189 const containerWidth = $table_scroll_container.outerWidth(); 190 const scrollWidth = $table_scroll_container[0].scrollWidth; 191 //const maxScroll = scrollWidth - containerWidth; 192 193 const atEnd = scrollLeft + containerWidth >= scrollWidth - 1; 194 const atStart = scrollLeft <= 0; 195 196 // Update scroll button state 197 if (atEnd) { 198 scrollRight = false;
199 $table_scroll_button.css('transform', 'scaleX(-1)'); 200 } else if (atStart) { 201 scrollRight = true; 202 $table_scroll_button.css('transform', 'scaleX(1)'); 203 } 204 205 // Update dot navigation state 206 $dot_navs.removeClass('active'); 207 if (atStart) { 208 $dot_navs.filter('[data-position="start"]').addClass('active'); 209 } else if (atEnd) { 210 $dot_navs.filter('[data-position="end"]').addClass('active'); 211 } else { 212 $dot_navs.filter('[data-position="middle"]').addClass('active'); 213 } 214 } 215 216 // Function to scroll to position 217 function scrollToPosition(position) { 218 const containerWidth = $table_scroll_container.outerWidth(); 219 const scrollWidth = $table_scroll_container[0].scrollWidth; 220 const maxScroll = scrollWidth - containerWidth; 221 let targetScroll; 222 223 switch(position) { 224 case 'start': 225 targetScroll = 0; 226 break; 227 case 'end': 228 targetScroll = maxScroll; 229 break; 230 case 'middle': 231 targetScroll = maxScroll / 2; 232 break; 233 } 234 235 $table_scroll_container.animate({ 236 scrollLeft: targetScroll 237 }, 300, function() { 238 updateScrollButtonState(); 239 }); 240 } 241 242 // Listen for manual scrolling 243 $table_scroll_container.on('scroll', function() { 244 updateScrollButtonState(); 245 }); 246 247 // Handle dot navigation clicks 248 $dot_navs.on('click', function() { 249 const position = $(this).data('position'); 250 scrollToPosition(position); 251 }); 252 253 $table_scroll_button.on('click', function (e) { 254 e.preventDefault(); 255 const scrollStep = getScrollStep(); 256 const newScroll = scrollRight ? scrollStep : -scrollStep; 257 258 $table_scroll_container.animate({ 259 scrollLeft: $table_scroll_container.scrollLeft() + newScroll 260 }, 300, function () { 261 updateScrollButtonState(); 262 }); 263 }); 264 265 // 266 // Accordion functionality 267 // 268 const $accordionItems = $table_scroll_section.find('.co-comp_table-mobile--accordion_item'); 269 270 // Add click handler to accordion titles 271 $accordionItems.each(function() { 272 const $item = $(this); 273 const $title = $item.find('.co-comp_table-mobile--accordion_title'); 274 const $title_wrap = $item.find('.co-comp_table-mobile--accordion_title-text-wrap'); 275 const $content = $item.find('.co-comp_table-mobile--accordion_columns_wrap'); 276 277 // Add indicator span 278 $title_wrap.append('<span class="accordion-indicator">-</span>'); 279 280 // Add click handler to title 281 $title.on('click', function() { 282 const isExpanded = $item.hasClass('expanded'); 283 284 // Toggle current item 285 $item.toggleClass('expanded'); 286 $content.slideToggle(300); 287 288 // Update indicator 289 $title.find('.accordion-indicator').text(isExpanded ? '+' : '-'); 290 291 // Update aria attributes 292 $title.attr('aria-expanded', !isExpanded); 293 }); 294 295 // Set initial state 296 $item.addClass('expanded'); 297 $title.attr('aria-expanded', 'true'); 298 $title.attr('role', 'button'); 299 $title.attr('tabindex', '0'); 300 }); 301 302 // 303 // Handle hide more button visibility 304 // 305 const $allAccordionItems = $table_scroll_section.find('.co-comp_table-mobile--accordion_item'); 306 const $itemsWithMoreButton = $allAccordionItems.filter(function() { 307 return $(this).find('.co-comp_table--more_button').length > 0; 308 }); 309 if ($itemsWithMoreButton.length > 0) { 310 $itemsWithMoreButton.hide(); 311 } 312 313 // 314 // Handle show differences checkbox 315 // 316 const $showDifferencesCheckbox = $table_scroll_section.find('.co-comp_table-mobile-show-differences'); 317 318 // Function to get content hash for a single column 319 function getColumnContentHash($column) { 320 // Get the exact HTML content of the column 321 return $column.html().trim(); 322 } 323 324 // Function to check if all columns in an accordion have identical content 325 function allColumnsIdentical($accordionItem) { 326 const $columns = $accordionItem.find('.co-comp_table-mobile--accordion_column'); 327 if ($columns.length <= 1) { 328 return false; // Don't collapse if there's only one column 329 } 330 331 const firstColumnContent = getColumnContentHash($columns.first()); 332 333 // Check if all columns have the same content as the first column 334 return $columns.toArray().every(function(column) { 335 return getColumnContentHash($(column)) === firstColumnContent; 336 }); 337 } 338
339 // Function to find accordions where all columns have identical content 340 function findAccordionsWithIdenticalColumns() { 341 const accordionsToCollapse = []; 342 343 $accordionItems.each(function() { 344 const $item = $(this); 345 if (allColumnsIdentical($item)) { 346 accordionsToCollapse.push($item); 347 } 348 }); 349 350 return accordionsToCollapse; 351 } 352 353 $showDifferencesCheckbox.on('change', function() { 354 const isChecked = $(this).is(':checked'); 355 356 if (isChecked) { 357 // Find and collapse accordions where all columns have identical content 358 const accordionsToCollapse = findAccordionsWithIdenticalColumns(); 359 360 accordionsToCollapse.forEach($item => { 361 const $title = $item.find('.co-comp_table-mobile--accordion_title'); 362 const $content = $item.find('.co-comp_table-mobile--accordion_columns_wrap'); 363 const $indicator = $title.find('.accordion-indicator'); 364 365 $item.removeClass('expanded'); 366 $content.slideUp(300); 367 $indicator.text('+'); 368 $title.attr('aria-expanded', 'false'); 369 }); 370 } else { 371 // Expand all accordions 372 $accordionItems.each(function() { 373 const $item = $(this); 374 const $title = $item.find('.co-comp_table-mobile--accordion_title'); 375 const $content = $item.find('.co-comp_table-mobile--accordion_columns_wrap'); 376 const $indicator = $title.find('.accordion-indicator'); 377 378 $item.addClass('expanded'); 379 $content.slideDown(300); 380 $indicator.text('-'); 381 $title.attr('aria-expanded', 'true'); 382 }); 383 } 384 }); 385 386 // 387 // Handle pin-to-compare select functionality 388 // 389 const $pinToCompareSelect = $table_scroll_section.find('.co-comp_table-mobile-pin-to-compare'); 390 391 // Function to reorder columns based on selected value 392 function reorderColumns(selectedValue) { 393 const $titlesContainer = $table_scroll_section.find('.co-comp_table-mobile--titles'); 394 const $allTitles = $titlesContainer.find('.co-comp_table-mobile--title'); 395 396 if (selectedValue === 'all') { 397 // Reset to original order - sort titles by their key number 398 const titlesArray = $allTitles.toArray(); 399 titlesArray.sort(function(a, b) { 400 const aKey = parseInt($(a).attr('class').match(/comp_table-mobile--title__key_(\d+)/)?.[1] || 0); 401 const bKey = parseInt($(b).attr('class').match(/comp_table-mobile--title__key_(\d+)/)?.[1] || 0); 402 return aKey - bKey; 403 }); 404 405 // Clear container and append in sorted order 406 $titlesContainer.empty(); 407 titlesArray.forEach(function(title) { 408 $titlesContainer.append(title); 409 }); 410 411 // Remove sticky class when showing all 412 $table_scroll_section.removeClass('has-pinned-column'); 413 } else { 414 // Find the selected column and move it to the first position 415 const $selectedTitle = $titlesContainer.find('.comp_table-mobile--title__key_' + selectedValue); 416 417 if ($selectedTitle.length > 0) { 418 // Move the selected title to the beginning 419 $titlesContainer.prepend($selectedTitle); 420 421 // Add sticky class when a specific column is pinned 422 $table_scroll_section.addClass('has-pinned-column'); 423 } 424 } 425 426 // Also reorder the accordion columns to match 427 reorderAccordionColumns(selectedValue); 428 429 // Reset horizontal scroll to the left after reordering 430 $table_scroll_container.animate({ 431 scrollLeft: 0 432 }, 300, function() { 433 updateScrollButtonState(); 434 }); 435 } 436 437 // Function to reorder accordion columns to match the title order 438 function reorderAccordionColumns(selectedValue) { 439 $accordionItems.each(function() { 440 const $item = $(this); 441 const $columnsWrap = $item.find('.co-comp_table-mobile--accordion_columns_wrap'); 442 const $allColumns = $columnsWrap.find('.co-comp_table-mobile--accordion_column'); 443 444 if (selectedValue === 'all') { 445 // Reset to original order - sort columns by their key number 446 const columnsArray = $allColumns.toArray(); 447 columnsArray.sort(function(a, b) { 448 const aKey = parseInt($(a).attr('class').match(/comp_table-mobile--accordion_column__key_(\d+)/)?.[1] || 0); 449 const bKey = parseInt($(b).attr('class').match(/comp_table-mobile--accordion_column__key_(\d+)/)?.[1] || 0); 450 return aKey - bKey; 451 }); 452 453 // Clear container and append in sorted order 454 $columnsWrap.empty(); 455 columnsArray.forEach(function(column) { 456 $columnsWrap.append(column); 457 }); 458 } else { 459 // Find the selected column and move it to the first position 460 const $selectedColumn = $columnsWrap.find('.comp_table-mobile--accordion_column__key_' + selectedValue); 461 462 if ($selectedColumn.length > 0) { 463 // Move the selected column to the beginning 464 $columnsWrap.prepend($selectedColumn); 465 } 466 } 467 }); 468 } 469 470 // Handle select change event 471 $pinToCompareSelect.on('change', function() { 472 const selectedValue = $(this).val(); 473 reorderColumns(selectedValue); 474 }); 475 }); 476 477 function syncAutoLoanRatesPills($root, $snap) { 478 const w = $snap.outerWidth(); 479 if (!w) { 480 return; 481 } 482 const idx = Math.round($snap.scrollLeft() / w); 483 const $pills = $root.find('.co-auto_loan_rates-mobile--pill_tablist [role="tab"]'); 484 $pills.removeClass('is-active').attr('aria-selected', 'false').attr('tabindex', '-1'); 485 const $active = $pills.filter('[data-panel-index="' + idx + '"]'); 486 if ($active.length) { 487 $active.addClass('is-active').attr('aria-selected', 'true').attr('tabindex', '0'); 488 } 489 } 490 491 $('.js-auto_loan_rates_root').each(function() { 492 const $root = $(this); 493 const $snap = $root.find('.js-auto_loan_panels_snap'); 494 if (!$snap.length) { 495 return; 496 } 497 const $pills = $root.find('.co-auto_loan_rates-mobile--pill_tablist [role="tab"]'); 498 $pills.on('click', function() { 499 const idx = parseInt($(this).data('panel-index'), 10); 500 const w = $snap.outerWidth(); 501 $snap.animate({ scrollLeft: idx * w }, 300, function() { 502 syncAutoLoanRatesPills($root, $snap); 503 }); 504 }); 505 let scrollTimer; 506 $snap.on('scroll', function() { 507 clearTimeout(scrollTimer); 508 scrollTimer = setTimeout(function() { 509 syncAutoLoanRatesPills($root, $snap); 510 }, 80); 511 }); 512 $(window).on('resize', function() { 513 syncAutoLoanRatesPills($root, $snap); 514 }); 515 syncAutoLoanRatesPills($root, $snap); 516 }); 517})(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.