Created
August 1, 2018 15:51
-
-
Save DennisdeBest/3910c7816ec3d32f93503bd801e36855 to your computer and use it in GitHub Desktop.
sticky search filters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//Apply filter behaviour after the document is finished loading | |
$(document).on('as4-After-Document-Ready', () => { | |
new Filters() | |
}); | |
/** | |
* Controls the bevahiour of the filter container | |
*/ | |
class Filters { | |
constructor() { | |
this.container = this.getContainer(); | |
this.groups = this.getGroups(); | |
this.bottom_anchor = this.getBottomAnchor(); | |
this.top_anchor = this.getTopAnchor(); | |
this.offset_top = this.top_anchor.offset().top - 175; //This has to be calculated upon initialization | |
this.offset_bottom = 350; | |
this.bindActions(); | |
} | |
/** | |
* Container that will containthe filters and that will be moving on scroll | |
* @returns {*|jQuery|HTMLElement} | |
*/ | |
getContainer() { | |
return $('.PM_ASBlockOutput') | |
} | |
/** | |
* Fixed element used to determine when to start container scroll | |
* @returns {*|jQuery|HTMLElement} | |
*/ | |
getTopAnchor() { | |
return $('#left_column'); | |
} | |
/** | |
* Fixed element used to determine when to stop the container scroll | |
* @returns {*|jQuery|HTMLElement} | |
*/ | |
getBottomAnchor() { | |
return $('#reinsurance_block'); | |
} | |
/** | |
* Use top and bottom anchors with the container height and the offset to get the maximum margin for the filters | |
* To debug add the following console.log : | |
* console.log(this.bottom_anchor.offset().top, this.top_anchor.offset().top, this.container.height(), this.offset_bottom, | |
* parseInt(this.bottom_anchor.offset().top - this.top_anchor.offset().top - this.container.height() - this.offset_bottom)) | |
* @returns {number} | |
*/ | |
getMaxMarginForContainer() { | |
return parseInt(this.bottom_anchor.offset().top - this.top_anchor.offset().top - this.container.height() - this.offset_bottom); | |
} | |
/** | |
* Get the filter groups | |
* @returns {jQuery} | |
*/ | |
getGroups() { | |
return $('.PM_ASCriterionsGroupTitle').toArray(); | |
} | |
/** | |
* Bind the click actions for the filter groups and the scroll action on the window object | |
* to calculate the relative position of the container | |
*/ | |
bindActions() { | |
this.groups.forEach((item, key) => { | |
item.addEventListener("click", (e) => { | |
this.clickGroupTitleAction(e, key) | |
}) | |
}); | |
window.addEventListener("scroll", (e) => { | |
this.scrollAction(e) | |
}) | |
} | |
/** | |
* Use the current scroll position and the position of the container | |
* to dynamically set the top margin | |
*/ | |
scrollAction() { | |
let last_known_scroll_position = window.scrollY; | |
let ticking = false; | |
let $container = this.container; | |
let offset_top = this.offset_top; | |
//Get max margin dynamically in case the page hasn't fully finished loading when the | |
//Filters constructor is called | |
let max_margin_container = this.getMaxMarginForContainer(); | |
let margin = 0; | |
if (!ticking) { | |
window.requestAnimationFrame(function () { | |
//Difference between the current scroll position and the point at which we want the container | |
//to follow the scroll | |
let diff = offset_top - last_known_scroll_position; | |
let container_offset = parseInt(diff * (-1)); | |
//if the difference between the currant scroll position and the"trigger" position is smaller then 0 | |
if (diff < 0) { | |
//If we haven't reached the maximum offset yet | |
if (container_offset > max_margin_container) { | |
margin = max_margin_container; | |
} | |
else { | |
margin = container_offset; | |
} | |
} | |
$container.stop().animate({ | |
marginTop: margin | |
}); | |
ticking = false; | |
}); | |
ticking = true; | |
} | |
} | |
clickGroupTitleAction(e, key) { | |
//Sometimes the eventListener gets added twice which causes the filter group to open | |
//and immediately close after, the next 2 lines prevent this | |
e.preventDefault(); | |
e.stopImmediatePropagation(); | |
//When the title is clicked we need to get the complete group element | |
let $target = $(this.groups[key]).closest('.PM_ASCriterionsGroup'); | |
//This is the bit that contains the actual values of the filter | |
let $inner = $target.find('.PM_ASCriterionsGroupOuter'); | |
let visible = $inner.is(':visible'); | |
//If the current group is open close it else open it and close all others | |
if (visible) { | |
$inner.slideUp(); | |
$target.find('.filter_group_toggle_icon').html('+'); | |
$target.find('.filter_group_toggle_icon').removeClass('open'); | |
} else { | |
this.closeAllGroups(); | |
$inner.slideDown(); | |
$target.find('.filter_group_toggle_icon').html('-'); | |
$target.find('.filter_group_toggle_icon').addClass('open'); | |
} | |
} | |
closeAllGroups() { | |
this.groups.forEach((item) => { | |
let $group = $(item).closest('.PM_ASCriterionsGroup'); | |
$group.find('.PM_ASCriterionsGroupOuter').slideUp(); | |
$group.find('.filter_group_toggle_icon').html('+'); | |
$group.find('.filter_group_toggle_icon').removeClass('open'); | |
}) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment