Skip to content

Instantly share code, notes, and snippets.

@DennisdeBest
Created August 1, 2018 15:51
Show Gist options
  • Save DennisdeBest/3910c7816ec3d32f93503bd801e36855 to your computer and use it in GitHub Desktop.
Save DennisdeBest/3910c7816ec3d32f93503bd801e36855 to your computer and use it in GitHub Desktop.
sticky search filters
//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