## 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>
```