## custom.grouphubs.infintescroll ``` <#include "api_user_creds.ftl" > <#import "common_ug_properties.ftl" as commonUgPropertiesMacro> <#include "events_utility_functions.ftl" > <#assign category_id=http.request.parameters.name.get( "categoryId", "" )?html /> <#assign catHref = ""/> <#attempt> <#assign catInfo = rest("/categories/id/${category_id}?restapi.response_style=view")/> <#assign catHref = catInfo.category.@view_href/> <#recover> </#attempt> <@component id="angular-elipsis-lib" /> <div id="grouphub-main-wrapper" class="grouphub-main-wrapper" ng-app="userGroupsApp" ng-controller="userGroupController"> <div class="ug-cards-title">Groups</div> <div id="error-container"></div> <div class="mobile-filter-sec"> <div class="filter-modal-content infinite-desktop-sec"> <div class="filter-modal-main-section"> <div class="ug-sortby-location"> <label class="ug-card-label" for="existing-phases">Location</label> <div class="search-location-inputbox"> <form ng-submit="clearLocation()"> <div id='searchBoxContainer'> <input type='text' id='searchBox' aria-label="Search Location" ng-attr-placeholder="{{ userlocation.city }}" role="combobox" ng-model='locationSearchTerm' ng-blur="clearLocation()" autocomplete="off" /> <p role="alert" ng-if="isCitySelectedForGroups && selectedLocationForGroups" class="city-search-message" > Showing results within 100 mile radius </p> </div> </form> <img src="/html/assets/location-pin.svg" alt="location pin" class="location-pin"> </div> </div> </div> </div> <!-- Start mobile filter section --> <div class="infinite-mobile-filter"> <div class="mobile-filter-btn"> <button id="filter-widget-btn"></button> </div> <div id="myModal" class="filter-modal"> <div class="ug-card-filter-sectioan"> <div class="filter-modal-content"> <div class="filter-modal-header"> <h3 class="filter-modal-title">Filters</h3> <span class="close"></span> </div> <div class="filter-modal-main-section"> <div class="ug-sortby-location"> <label class="ug-card-label" for="existing-phases">Location</label> <div class="search-location-inputbox"> <form ng-submit="clearLocation()"> <div id='mobileSearchBoxContainer'> <input type='text' id="mobileSearchBox" ng-attr-placeholder="{{ userlocation.city }}" role="combobox" aria-label="Search Location" ng-model='locationSearchTerm' ng-blur="clearLocation()" autocomplete="off" /> </div> <p role="alert" ng-if="isCitySelectedForGroups && selectedLocationForGroups" class="city-search-message" > Showing results within 100 mile radius </p> </form> <div class="filters-group-btn-sec"> <button id="apply-btn" type="button" class="filters-apply-btn" >Apply</button> <button id="cancel-btn" type="button" class="filters-cancel-btn">Cancel</button> </div> <img src="/html/assets/location-pin.svg" alt="location pin" class="location-pin"> </div> <#-- <div id="searchResult" class="ug-search-results"></div> --> </div> </div> </div> </div> </div> </div> <!--End mobile filter section --> <div class="ug-card-filter-section-sortby "> <!-- <div class="ug-sortby-category"> <label class="ug-card-label" for="existing-phases">Sort by</label> <select class="form-control" ng-model="selectedValue" ng-change="sortBy()"> <option value="creationDate">Recently added</option> <option value="memberCount"> Member count, high to low</option> <option value="message_activity">Recent activity</option> </select> </div> --> <div class="m-ug-search-filter-section"> <label class="ug-card-label" for="existing-phases">Sort by</label> <div class="search-dropdown"> <button class="select" type="button" aria-expanded="false" tabindex="0" aria-controls="sortselect"> <span title="{{selectedValue}}">{{selectedValue}}</span> <div class="m-down-icon"></div> </button> <ul class="search-dropdown-menu"> <li ng-repeat="option in sortOptions" id="{{option.dataKey}}" ng-click="sortBy(option)"> <a href="javascript:void(0)" ng-attr-aria-selected="{{ option.label == selectedValue }}" > {{option.label}} </a> </li> <#-- <li id="creationDate" ng-click="sortBy('creationDate')"> <a href="javascript:void(0)">Recently added</a></li> --> <#-- <li id="memberCount" ng-click="sortBy('memberCount')"> <a href="javascript:void(0)">Member count, high to low</a></li> --> <#-- <li id="message_activity" ng-click="sortBy('message_activity')"> <a href="javascript:void(0)">Recent activity</a></li> --> </ul> </div> </div> </div> </div> <div class="ug-clear-both"></div> <div class="grouphub-result-count" ng-if="!isLoading && selectedLocationForGroups"> <p role="alert" ng-cloak aria-label="User Groups Results {{(displayList | startFrom:(currentPage-1)*pageSize | withinGeoBoundary: selectedLocationForGroups : userlocation : isCitySelectedForGroups | customSortBy: sortFromLocation: selectedValue ).length}}">Results: {{(displayList | startFrom:(currentPage-1)*pageSize | withinGeoBoundary: selectedLocationForGroups : userlocation : isCitySelectedForGroups | customSortBy: sortFromLocation: selectedValue ).length}}</p> </div> <div class="grouphub-list-widget" ng-cloak infinite-scroll='nextPage()' infinite-scroll-distance='2' infinite-scroll-use-document-bottom="true"> <div class="grouphub-spinner" ng-if="isLoading"> <div class="ug-loader"></div> <p>Loading ...</p> </div> <div ng-if="!isLoading" class="grouphubs-posts-box" ng-repeat="grouphub in displayList | startFrom:(currentPage-1)*pageSize | withinGeoBoundary: selectedLocationForGroups : userlocation : isCitySelectedForGroups | customSortBy: sortFromLocation: selectedValue | limitTo:pageSize as displayResults"> <div class="ug-card-message-img"> <img src="{{grouphub.avatar}}" alt="{{grouphub.title | decodeURIComponent}}""> </div> <div class="message-contents"> <div class="grouphub-title"> <h3 id="{{ grouphub.id}}"> <a href="{{grouphub.viewHref}}" class="title-href " data-ng-bind="grouphub.title | decodeURIComponent" data-ellipsis ></a> </h3> </div> <div class="grouphub-location"> <span data-ng-bind="grouphub.city" data-ellipsis> </span> </div> <div class="grouphub-description"> <span data-ng-bind="grouphub.description | decodeURIComponent" data-ellipsis></span> </div> <div class="grouphub-users"> <div class="grouphub-spinner" ng-if="membersLoading == true"> <div class="ug-loader"></div> </div> <div ng-if="membersLoading == false"> <div class="user-item" ng-repeat="user in grouphub.members | limitTo: 5 | orderBy: '-online_status'"> <a href="{{user.view_href}}" class="myTooltip" title="{{user.login}}"><img src="{{user.avatar.profile}}" alt="{{user.login}}" width="24" height="24"> <div class="{{user.online_status}}"> </div> </a> </div> <div class="user-item-count" ng-if="grouphub.memberCount>5">+{{grouphub.memberCount-5}}</div> </div> </div> <#-- <div class="grouphub-users"> <div ng-if="grouphub.members.length == 0">Loading...</div> <div ng-if="grouphub.members.length != 0" class="user-item" ng-repeat="user in grouphub.members | limitTo: 5 | orderBy: '-online_status'"> <a href="{{user.viewHref}}"><img src="{{user.avatar}}" alt="{{user.login}}" title="{{user.login}}" width="24" height="24"> <div class="{{user.online_status}}"> </div> </a> </div> </div> --> <div class="ug-card-bottom-section"> <div class="ug-learn-more-btn"><a href="{{grouphub.viewHref}}" id="Learn_more_{{grouphub.id}}" aria-labelledby="Learn_more_{{grouphub.id}} {{grouphub.id}}">Learn more</a></div> <#if !user.anonymous> <div class="ug-join-button"> <div ng-switch="grouphub.memberStatus" class="ug-join-button"> <div ng-switch-when="joined"><button class="btn-group disabled-state" disabled>Member</button></div> <div ng-switch-when="notJoined"><button class="btn-group" ng-click="joinOrRequest(grouphub)" aria-labelledby="tooltipug">Join now</button></div> <div ng-switch-default></div> </div> </div> </#if> </div> </div> </div> <div ng-if="displayResults.length == 0 && isLoading == false && pickedLocation " class="ug-search-empty-state"> <@commonUgPropertiesMacro.emptyStateImage /> <h4 role="alert">There are no groups in your area.</h4> <span>Get notified when new groups are added.</span> <div class="yg-seeall-btn"> <a role="button" href="https://aka.ms/NewUGNotify" target="_blank" class="button-viewmore">Get notified</a> </div> </div> <!-- <div class="custom-no-group-hubs" ng-if="showLocationEmptyContent && pickedLocation"> <p>No group hubs with this selected range</p> </div> --> <div class="ug-notified-box-wrapper" ng-if="pickedLocation && displayResults.length != 0" > <div class="ug-notified-box"> <div class="ug-notified-box-content"><p>Get notified when there’s a group in your area. New groups are added regularly.</p></div> <div class="ug-notified-button"><a role="button" href="https://aka.ms/NewUGNotify" target="_blank">Get notified</a></div> </div> </div> </div> </div> <script type="text/javascript"> var locationObj function loadMapScenario() { var prevValue ='' var latitude var longitude document.getElementById("filter-widget-btn") .addEventListener("click", function () { prevValue = document.getElementById("mobileSearchBox").value || "" console.log("trigger value for p",prevValue) }) Microsoft.Maps.loadModule('Microsoft.Maps.AutoSuggest', { callback: onLoad, errorCallback: onError }); Microsoft.Maps.loadModule('Microsoft.Maps.SpatialDataService', { callback: function () { var scope = angular .element(document.getElementById("grouphub-main-wrapper")) .scope(); scope.onInit() scope.$apply() } }); function onLoad() { var options = { maxResults: 5 }; var manager = new Microsoft.Maps.AutosuggestManager(options); function initAutoSuggest () { var searchBoxId = window.innerWidth < 680 ? "#mobileSearchBox" : "#searchBox" var searchBoxContainerId = window.innerWidth < 680 ? "#mobileSearchBoxContainer" : "#searchBoxContainer" manager.attachAutosuggest( searchBoxId, searchBoxContainerId, selectedSuggestion ); } initAutoSuggest() var isMobile = (/iphone|ipod|android|ie|blackberry|fennec/).test(navigator.userAgent.toLowerCase()); if (!isMobile){ window.addEventListener('resize',function () { manager.detachAutosuggest() initAutoSuggest() }) } if (window.innerWidth < 680){ function hidePopup () { modal.style.display = "none"; filterBtn.className = "filters-apply-btn" } var modal = document.getElementById("myModal"); var applyBtn = document.getElementById("apply-btn"); var cancelBtn = document.getElementById("cancel-btn"); applyBtn.addEventListener('click', function () { var scope = angular .element(document.getElementById("grouphub-main-wrapper")) .scope(); scope.getdest(locationObj); scope.$apply(); hidePopup() }) cancelBtn.addEventListener('click', function () { var scope = angular .element(document.getElementById("grouphub-main-wrapper")) .scope(); scope.clearLocation() scope.$apply() console.log("prev value is ", prevValue) if (prevValue){ document.getElementById("mobileSearchBox").value = prevValue } hidePopup() }) } } function onError(message) { //loadMapScenario() var containerId = "error-container" var errorElement = `<div class="location-failed-error-message" ><p>Your location failed to load. Please refresh the page.</p><span id ="location-error-snap" class="error-close-btn"></span></div>` console.log("error in loading big api " , message) document.getElementById(containerId).innerHTML = errorElement; document.getElementById("location-error-snap").addEventListener("click", function () { document.getElementById(containerId).innerHTML = ""; }) } //onError() function selectedSuggestion(suggestionResult) { lat = suggestionResult.location.latitude; lon = suggestionResult.location.longitude; city = suggestionResult.formattedSuggestion; var scope = angular .element(document.getElementById("grouphub-main-wrapper")) .scope(); if (window.innerWidth < 680){ locationObj = suggestionResult latitude= suggestionResult.location.latitude longitude = suggestionResult.location.longitude } else { scope.getdest(suggestionResult); scope.$apply(); } } } function modifyGroupsWithLocationCoordinates (groups) { return groups.map(function (eachGroup) { eachGroup.locationCoordinates = { latitude : parseFloat(eachGroup.latitude), longitude : parseFloat(eachGroup.longitude) } return eachGroup }) } <#-- function ellipseForElements(ele) { $('.grouphub-card-description-ellipse').tilesdes(); $('.grouphub-card-title-ellipse').tilesdes(); $('.grouphub-card-location-ellipse').tilesdes(); } --> var userGroupApp = angular.module('userGroupsApp', ["infinite-scroll","dibari.angular-ellipsis"]); <#-- userGroupApp.directive('repeatLast', function() { return function(scope, element, attrs) { if (scope.$last) { setTimeout(ellipseForElements, 1000, element); } else { ellipseForElements(element); } }; }); --> function setToolTip () { setTimeout(function () { $(".myTooltip").zTip(); },1000) } userGroupApp.controller('userGroupController', ['$scope', '$http', '$filter', function($scope, $http, $filter) { // start: location handling values $scope.pickedLocation = false $scope.locationSearchTerm = "" // end: location handling values $scope.sourceList = [] $scope.displayList = [] $scope.users = []; // $scope.displayList = []; $scope.pageSize = 12; $scope.currentPage = 1; $scope.groupsLength = 0; $scope.selectedValue = 'Nearby location'; $scope.isLoading = true; $scope.membersLoading = true; $scope.recentActivityResponse = [] $scope.selectedLocationForGroups = null $scope.isCitySelectedForGroups = false $scope.sortFromLocation = null $scope.sortOptions = [ { label: "Nearby location", dataKey: "distance" }, { label: "Recently added", dataKey: "creationDate" }, { label: "Member count, high to low", dataKey: "memberCount" }, { label: "Recent activity", dataKey: "message_activity" }, ] // get user location $scope.userlocation = null $scope.onInit = function () { getUserLocation( function (location) { var applyFn = function () { console.log("user is location",location ) $scope.userlocation = location $scope.sortBy($scope.sortOptions[0]) $scope.sortFromLocation = location }; if ($scope.$$phase) { applyFn(); } else { $scope.$apply(applyFn); } }) }; $http.get('${webuisupport.urls.endpoints.name.get("get-grouphubs").build()}?categoryId=${category_id}' + '&orderBy=creation_date') .then(function(response) { var modifiedGroups = modifyGroupsWithLocationCoordinates(response.data.grouphubs); $scope.isLoading = false; $scope.sourceList = modifiedGroups; $scope.displayList = modifiedGroups; console.log("total list is ", $scope.displayList) $scope.displayList.map(function(obj) { if (!obj.hasOwnProperty('distance')) { obj.distance = 0; } }) $scope.groupsLength = $scope.sourceList.length; $scope.updateGroupUsers(); }, function(error) { console.log("error", error); }); $scope.nextPage = function() { if ($scope.groupsLength > $scope.pageSize) { $scope.pageSize += $scope.pageSize setToolTip() } } $scope.clearLocation = function() { if ($scope.locationSearchTerm.length == 0) { $scope.displayList = $scope.sourceList; $scope.pickedLocation = false $scope.selectedLocationForGroups = null $scope.sortFromLocation = $scope.userlocation setToolTip() } }; $scope.sortBy = function(selectedOption) { console.log("sort called", selectedOption) $scope.selectedValue = selectedOption.label var sortField = selectedOption.dataKey $(".select").attr('aria-expanded', 'false'); $(".search-dropdown").find(".search-dropdown-menu").slideUp(300); if (sortField ==="distance") { var userlocation = $scope.sortFromLocation !== null ? $scope.sortFromLocation : $scope.userlocation var arrayWithDistance = $scope.displayList.map(function (item) { var listItemCoordinates = { latitude: item.locationCoordinates&& item.locationCoordinates.latitude , longitude: item.locationCoordinates&& item.locationCoordinates.longitude , } item.distance = distanceCal(userlocation.latitude, userlocation.longitude, listItemCoordinates.latitude, listItemCoordinates.longitude, "K") return item }) var sortedEvents = arrayWithDistance.sort(function (groupA, groupB) { var a = groupA.distance var b = groupB.distance if( !isFinite(a) && !isFinite(b) ) { return 0; } if( !isFinite(a) ) { return 1; } if( !isFinite(b) ) { return -1; } return a-b; }) console.log("after sorting is ", arrayWithDistance); $scope.displayList = sortedEvents } else if (sortField === "creationDate") { $scope.displayList = $scope.displayList.sort(function(groupA, groupB) { return moment(groupB.creationDateISOString) - moment(groupA.creationDateISOString) }) } else if (sortField === "memberCount") { $scope.displayList = $scope.sourceList.sort(function(groupA, groupB) { return groupA.memberCount > groupB.memberCount ? -1 : 1 }); } else if (sortField === "message_activity") { function handleRecentAcitivityResponse(responseArray) { return responseArray.map(function(group) { const groupObj = $scope.sourceList.find(function(g) { return g.id === group.id }) return groupObj }) } if ($scope.recentActivityResponse.length === 0) { $scope.isLoading = true; $http.get('${webuisupport.urls.endpoints.name.get("get-grouphubs").build()}?categoryId=${category_id}' + '&orderBy=message_activity.core_property_change_time') .then(function(response) { $scope.recentActivityResponse = handleRecentAcitivityResponse(response.data.grouphubs) console.log("after sort response is ", $scope.recentActivityResponse) $scope.isLoading = false; if ($scope.pickedLocation) { console.log('case with location', $scope.displayList) $scope.displayList = $scope.recentActivityResponse.filter(function(group) { var existingInDisplayListIndex = $scope.displayList.findIndex(function(i) { return i.id === group.id }) return existingInDisplayListIndex !== -1 }); setToolTip() } else { $scope.displayList = $scope.recentActivityResponse $scope.sourceList = $scope.recentActivityResponse } $scope.groupsLength = $scope.displayList.length; }, function(error) { console.log("error", error); }); } else { if ($scope.pickedLocation) { var responseCopy = Object.assign([], $scope.recentActivityResponse) $scope.displayList = responseCopy.filter(function(group) { var existingInDisplayListIndex = $scope.displayList.findIndex(function(i) { return i.id === group.id }) return existingInDisplayListIndex !== -1 }); } else { $scope.displayList = $scope.recentActivityResponse } $scope.groupsLength = $scope.sourceList.length; } } else if (sortField === "creationDate") { var displayListCopy = Object.assign([], $scope.displayList); $scope.displayList = displayListCopy.sort(function(a, b) { return new Date(b[sortField]) - new Date(a[sortField]); }); } setToolTip() }; $scope.joinOrRequest = function(node) { $http.get('${webuisupport.urls.endpoints.name.get("join-or-send-request-grouphub").query("mode","join").build()}&boardId=' + node.id) .then(function(response) { if (response.data.respStatus == "success") { node.memberStatus = "joined"; var learnMoreLink = "Learn_more_"+node.id node.memberCount += 1; toastMessage("You’re now a member of the group! ","","You can access all your groups in Your groups tab.","${catHref}?target=your_groups","Go to Your groups", null, learnMoreLink); setToolTip() } else { node.memberStatus = ""; } }, function(response) { console.log("error", response); node.memberStatus = ""; }); } $scope.updateGroupUsers = function() { var batchMaxSize = 25 var batchedGroupHubs = chunkArray($scope.sourceList, batchMaxSize) var allCopy = Object.assign([], $scope.sourceList) batchedGroupHubs.map(function (currentBatchGroups,currentBatchIndex) { recursiveFetcher(currentBatchGroups, function (response) { console.log("calling final setter ",currentBatchIndex,currentBatchIndex * batchMaxSize , (currentBatchIndex * batchMaxSize)+ batchMaxSize) var currentBatchScopedListOriginal = allCopy.slice(currentBatchIndex * batchMaxSize,(currentBatchIndex * batchMaxSize)+ batchMaxSize) var currentBatchScopedList = currentBatchScopedListOriginal.map(function(groupHub, index) { groupHub.members = response[index * 2].items; groupHub.memberCount = response[index * 2 + 1].count; return groupHub }); console.log("afterresponse is ", currentBatchScopedList) angular.forEach($scope.sourceList, function (value, itemIndex) { var foundIndex = currentBatchScopedList.findIndex(function (g) { return value.id === g.id }) var foundOne = currentBatchScopedList[foundIndex] if (itemIndex ===foundIndex) { value.members = foundOne.members; value.memberCount = foundOne.memberCount; } }) angular.forEach($scope.displayList, function (value, itemIndex) { var foundIndex = currentBatchScopedList.findIndex(function (g) { return value.id === g.id }) var foundOne = currentBatchScopedList[foundIndex] if (itemIndex ===foundIndex) { value.members = foundOne.members; value.memberCount = foundOne.memberCount; } }) $scope.membersLoading = false; setToolTip() }) }) function recursiveFetcher(batch, onEnd) { var userObj = "["; angular.forEach(batch, function(value, key) { if (userObj != "[") { userObj = userObj + ","; } userObj = userObj + '{"users": {"fields": ["id","login","view_href","online_status","avatar"],"constraints": [{"node.id": "grouphub:' + value.id + '"}]}},{"users": {"fields": ["count(*)"],"constraints": [{"node.id": "grouphub:' + value.id + '"}]}}'; }); userObj = userObj + "]"; $http({ url: '/api/2.0/search', dataType: 'json', method: 'POST', <#if user.anonymous> headers:{ 'li-api-session-key': '${sessionKey}', }, </#if> data: userObj, contentType: "application/json", }).then( function(response) { onEnd(response.data.data) }, function(error) { console.log("error", error); } ); } } $scope.getdest = function(loc) { if ($scope.locationSearchTerm.length === 0 ){ $scope.clearLocation() return } var selectionType = evalSelectionType(loc) var pickedLocation = { latitude: loc.location.latitude, longitude: loc.location.longitude, state: loc.address.adminDistrict, country: loc.address.countryRegion } $scope.isLoading = true; var applyFn = function () { $scope.isLoading = false; if (selectionType === "city"){ $scope.selectedLocationForGroups = { location: pickedLocation, bounds: null, } $scope.sortFromLocation = $scope.userlocation } else { $scope.selectedLocationForGroups = { location: pickedLocation, bounds: true, } $scope.sortFromLocation = $scope.userlocation } $scope.pickedLocation = true $scope.isCitySelectedForGroups = selectionType === "city" setToolTip() }; if ($scope.$$phase) { applyFn(); } else { $scope.$apply(applyFn); } console.log("selected type id ", selectionType) }; }]) userGroupApp.filter("customSortBy", function () { return function (oldArray, sortFromLocation, field) { console.log("sort with field ", field) if (field === "Nearby location"){ var oldArrayWithDistance = oldArray.map(function (item) { var listItemCoordinates = { latitude: item.locationCoordinates && item.locationCoordinates.latitude, longitude: item.locationCoordinates && item.locationCoordinates.longitude, } item.distance = distanceCal(sortFromLocation.latitude, sortFromLocation.longitude, listItemCoordinates.latitude, listItemCoordinates.longitude, "K") return item }) return oldArrayWithDistance.sort(function (itemA, itemB) { var a = itemA.distance var b = itemB.distance if( !isFinite(a) && !isFinite(b) ) { return 0; } if( !isFinite(a) ) { return 1; } if( !isFinite(b) ) { return -1; } return a-b; }) } else { return oldArray } } }) userGroupApp.filter('decodeURIComponent', function() { return window.decodeURIComponent; }) userGroupApp.filter('startFrom', function() { return function(input, start) { if (input) { start = +start; return input.slice(start); } return []; }; }) userGroupApp.filter('truncate', function() { return function(value, wordwise, max, tail) { if (!value) return ''; max = parseInt(max, 10); if (!max) return value; if (value.length <= max) return value; value = value.substr(0, max); if (wordwise) { var lastspace = value.lastIndexOf(' '); if (lastspace != -1) { value = value.substr(0, lastspace); } } return value + (tail || ' …'); }; }); userGroupApp.filter("withinGeoBoundary", function () { return angularFilters.withinGeoBoundary }) var MODULE_NAME = 'infinite-scroll' angular.module(MODULE_NAME, []) .value('THROTTLE_MILLISECONDS', null) .directive('infiniteScroll', [ '$rootScope', '$window', '$interval', 'THROTTLE_MILLISECONDS', function($rootScope, $window, $interval, THROTTLE_MILLISECONDS) { return { scope: { infiniteScroll: '&', infiniteScrollContainer: '=', infiniteScrollDistance: '=', infiniteScrollDisabled: '=', infiniteScrollUseDocumentBottom: '=', infiniteScrollListenForEvent: '@', }, link: function(scope, elem, attrs) { var windowElement = angular.element($window); var scrollDistance = null; var scrollEnabled = null; var checkWhenEnabled = null; var container = null; var immediateCheck = true; var useDocumentBottom = false; var unregisterEventListener = null; var checkInterval = false; function height(element) { var el = element[0] || element; if (isNaN(el.offsetHeight)) { return el.document.documentElement.clientHeight; } return el.offsetHeight; } function pageYOffset(element) { var el = element[0] || element; if (isNaN(window.pageYOffset)) { return el.document.documentElement.scrollTop; } return el.ownerDocument.defaultView.pageYOffset; } function offsetTop(element) { if (!(!element[0].getBoundingClientRect || element.css('none'))) { return element[0].getBoundingClientRect().top + pageYOffset(element); } return undefined; } // infinite-scroll specifies a function to call when the window, // or some other container specified by infinite-scroll-container, // is scrolled within a certain range from the bottom of the // document. It is recommended to use infinite-scroll-disabled // with a boolean that is set to true when the function is // called in order to throttle the function call. function defaultHandler() { var containerBottom; var elementBottom; if (container === windowElement) { containerBottom = height(container) + pageYOffset(container[0].document.documentElement); elementBottom = offsetTop(elem) + height(elem); } else { containerBottom = height(container); var containerTopOffset = 0; if (offsetTop(container) !== undefined) { containerTopOffset = offsetTop(container); } elementBottom = (offsetTop(elem) - containerTopOffset) + height(elem); } if (useDocumentBottom) { elementBottom = height((elem[0].ownerDocument || elem[0].document).documentElement); } var remaining = elementBottom - containerBottom; var shouldScroll = remaining <= (height(container) * scrollDistance) + 1; if (shouldScroll) { checkWhenEnabled = true; if (scrollEnabled) { if (scope.$$phase || $rootScope.$$phase) { scope.infiniteScroll(); } else { scope.$apply(scope.infiniteScroll); } } } else { if (checkInterval) { $interval.cancel(checkInterval); } checkWhenEnabled = false; } } // The optional THROTTLE_MILLISECONDS configuration value specifies // a minimum time that should elapse between each call to the // handler. N.b. the first call the handler will be run // immediately, and the final call will always result in the // handler being called after the `wait` period elapses. // A slimmed down version of underscore's implementation. function throttle(func, wait) { var timeout = null; var previous = 0; function later() { previous = new Date().getTime(); $interval.cancel(timeout); timeout = null; return func.call(); } function throttled() { var now = new Date().getTime(); var remaining = wait - (now - previous); if (remaining <= 0) { $interval.cancel(timeout); timeout = null; previous = now; func.call(); } else if (!timeout) { timeout = $interval(later, remaining, 1); } } return throttled; } var handler = (THROTTLE_MILLISECONDS != null) ? throttle(defaultHandler, THROTTLE_MILLISECONDS) : defaultHandler; function handleDestroy() { container.unbind('scroll', handler); if (unregisterEventListener != null) { unregisterEventListener(); unregisterEventListener = null; } if (checkInterval) { $interval.cancel(checkInterval); } } scope.$on('$destroy', handleDestroy); // infinite-scroll-distance specifies how close to the bottom of the page // the window is allowed to be before we trigger a new scroll. The value // provided is multiplied by the container height; for example, to load // more when the bottom of the page is less than 3 container heights away, // specify a value of 3. Defaults to 0. function handleInfiniteScrollDistance(v) { scrollDistance = parseFloat(v) || 0; } scope.$watch('infiniteScrollDistance', handleInfiniteScrollDistance); // If I don't explicitly call the handler here, tests fail. Don't know why yet. handleInfiniteScrollDistance(scope.infiniteScrollDistance); // infinite-scroll-disabled specifies a boolean that will keep the // infnite scroll function from being called; this is useful for // debouncing or throttling the function call. If an infinite // scroll is triggered but this value evaluates to true, then // once it switches back to false the infinite scroll function // will be triggered again. function handleInfiniteScrollDisabled(v) { scrollEnabled = !v; if (scrollEnabled && checkWhenEnabled) { checkWhenEnabled = false; handler(); } } scope.$watch('infiniteScrollDisabled', handleInfiniteScrollDisabled); // If I don't explicitly call the handler here, tests fail. Don't know why yet. handleInfiniteScrollDisabled(scope.infiniteScrollDisabled); // use the bottom of the document instead of the element's bottom. // This useful when the element does not have a height due to its // children being absolute positioned. function handleInfiniteScrollUseDocumentBottom(v) { useDocumentBottom = v; } scope.$watch('infiniteScrollUseDocumentBottom', handleInfiniteScrollUseDocumentBottom); handleInfiniteScrollUseDocumentBottom(scope.infiniteScrollUseDocumentBottom); // infinite-scroll-container sets the container which we want to be // infinte scrolled, instead of the whole window. Must be an // Angular or jQuery element, or, if jQuery is loaded, // a jQuery selector as a string. function changeContainer(newContainer) { if (container != null) { container.unbind('scroll', handler); } container = newContainer; if (newContainer != null) { container.bind('scroll', handler); } } changeContainer(windowElement); if (scope.infiniteScrollListenForEvent) { unregisterEventListener = $rootScope.$on(scope.infiniteScrollListenForEvent, handler); } function handleInfiniteScrollContainer(newContainer) { // TODO: For some reason newContainer is sometimes null instead // of the empty array, which Angular is supposed to pass when the // element is not defined // (https://github.com/sroze/ngInfiniteScroll/pull/7#commitcomment-5748431). // So I leave both checks. if ((!(newContainer != null)) || newContainer.length === 0) { return; } var newerContainer; if (newContainer.nodeType && newContainer.nodeType === 1) { newerContainer = angular.element(newContainer); } else if (typeof newContainer.append === 'function') { newerContainer = angular.element(newContainer[newContainer.length - 1]); } else if (typeof newContainer === 'string') { newerContainer = angular.element(document.querySelector(newContainer)); } else { newerContainer = newContainer; } if (newerContainer == null) { throw new Error('invalid infinite-scroll-container attribute.'); } changeContainer(newerContainer); } scope.$watch('infiniteScrollContainer', handleInfiniteScrollContainer); handleInfiniteScrollContainer(scope.infiniteScrollContainer || []); // infinite-scroll-parent establishes this element's parent as the // container infinitely scrolled instead of the whole window. if (attrs.infiniteScrollParent != null) { changeContainer(angular.element(elem.parent())); } // infinte-scoll-immediate-check sets whether or not run the // expression passed on infinite-scroll for the first time when the // directive first loads, before any actual scroll. if (attrs.infiniteScrollImmediateCheck != null) { immediateCheck = scope.$eval(attrs.infiniteScrollImmediateCheck); } function intervalCheck() { if (immediateCheck) { handler(); } return $interval.cancel(checkInterval); } checkInterval = $interval(intervalCheck); return checkInterval; }, } }, ]); </script> <script type="text/javascript"> (function(root, $) { 'use strict'; $.fn.tilesdes = function() { return this.each(function() { var $this = $(this), isOverflow = $this.css('overflow') === 'hidden'; if (isOverflow) { var text = $this.text(), lh = parseInt($this.css('line-height')), line = $this.attr('data-tilesdes'), maxHeight = lh * line; for (var i = text.length; i > 0; i--) { if ($this.height() <= maxHeight) { break; } else { $this.text(text.substr(0, i) + '...'); } } } }); } }(window, jQuery)); $(document).ready(function() { $('.grouphub-card-description-ellipse').tilesdes(); $('.grouphub-card-title-ellipse').tilesdes(); $('.grouphub-card-location-ellipse').tilesdes(); }); $(window).resize(function() { $('.grouphub-card-description-ellipse').tilesdes(); $('.grouphub-card-title-ellipse').tilesdes(); $('.grouphub-card-location-ellipse').tilesdes(); }); /*start Dropdown Menu*/ // event handler to hide menu when focused on outside elements $(".ug-card-filter-section-sortby").on('focusout', function(event) { if (this.contains(event.relatedTarget)) { // don't react to this return; } $(".search-dropdown-menu").slideUp(300); $(".select").attr('aria-expanded', 'false'); // do something }); $(".search-dropdown-menu").keydown(function(e){ console.log("event ", e.key) switch (e.key) { case "ArrowUp" : e.preventDefault(); $(this).closest('.dropdown-menu').find('a:first').focus(); break; case "ArrowDown" : e.preventDefault(); $(this).closest('.dropdown-menu').find('a:first').focus(); break; } }); $(".select").on("keyup click", function (event) { if ((event.keyCode == '13' && event.type == "keydown" && event.key == "Escape") || event.type == "click") { event.preventDefault(); if ($(event.target).hasClass('active') == true || $(event.target).parent().hasClass( 'active') == true) { $(this).attr('aria-expanded', 'false'); } else { $(this).attr('aria-expanded', 'true'); } $(this).toggleClass("active"); $(".search-dropdown").find(".search-dropdown-menu").slideToggle(300); } }); $(".search-dropdown").on("keyup", function (event) { if (event.keyCode == '27') { event.preventDefault(); if ($(event.target).hasClass('active') == true || $(event.target).parent().hasClass( 'active') == true) { $(this).attr('aria-expanded', 'false'); } else { $(this).attr('aria-expanded', 'true'); } $('.select').focus(); $(".search-dropdown").find(".search-dropdown-menu").slideUp(300); } }); $(".c .search-dropdown-menu li").click(function () { $(this).parents(".search-dropdown").find("span").text($(this).text()); $(this) .parents(".search-dropdown") .find("input") .attr("value", $(this).attr("id")); }); $(".search-dropdown-menu li").click(function () { var input = "<strong>" + $(this).parents(".search-dropdown").find("input").val() + "</strong>", msg = '<span class="msg">Hidden input value: '; $(".msg").html(msg + input + "</span>"); }); $(".search-dropdown-menu").on("keyup", function (event) { if (event.keyCode == '13') { event.preventDefault(); if ($(event.target).hasClass('active') == true || $(event.target).parent().hasClass( 'active') == true) { $(this).attr('aria-expanded', 'false'); } else { $(this).attr('aria-expanded', 'true'); } $('.select').focus(); $(this).removeClass("active"); $(".search-dropdown").find(".search-dropdown-menu").slideUp(300); } }); window.addEventListener('click', function(e){ var dropdowns = document.getElementsByClassName('search-dropdown') var check = dropdowns[0].contains(e.target) console.log("chefk is ", check) if (check){ // Clicked in box } else{ $(".select").attr('aria-expanded', 'false'); $(".select").removeClass("active"); if (window.innerWidth > 640) { $(".search-dropdown").find(".search-dropdown-menu").slideUp(300); } // Clicked outside the box } }); /*End Dropdown Menu*/ </script> <script> $(window).on("load resize", function() { if ($(this).width() < 680) { var modal = document.getElementById("myModal"); // Get the button that opens the modal var btn = document.getElementById("filter-widget-btn"); // Get the <span> element that closes the modal var span = document.getElementsByClassName("close")[0]; // When the user clicks the button, open the modal btn.onclick = function() { modal.style.display = "block"; btn.classList.add("disabled-filter-icon") } // When the user clicks on <span> (x), close the modal span.onclick = function() { modal.style.display = "none"; } } }) </script> ```