(function () {
'use strict';
// Search Facets
angular
.module('mohistory')
.service('searchFacets', searchFacets);
searchFacets.$inject = ['$state', '$uiRouterGlobals'];
/**
* An interface for adding, deleting, and querying search facets stored
* in UI-Router State. Router state and URL parameters are synced on state
* traversal.
* @memberof mohistory
* @name searchFacets
* @ngdoc service
* @param {object} $state UI-Router state
* @param {object} $uiRouterGlobals Stores the current state's parameters
*/
function searchFacets($state, $uiRouterGlobals) {
var service = this;
/* ----- Variables ----- */
// These facets are stored in the hash as strings not arrays.
// They are also not displayed in the tabbed panels.
var STRING_FACETS = ['text', 'layout', '#', 'redirect', 'sort', 'fullscreen', 'view', 'page', 'hasImage'];
/* ----- Function Bindings ----- */
// Retrieve a flattened, aka one level deep version, of the state parameters
// stored as arrays, this is used to populate the selected facets section of
// the view
service.getFlattenedFacets = getFlattenedFacets;
// Manipulating the search facet list
service.addFacetsForKeywordSearch = addFacetsForKeywordSearch;
service.addFacetToHash = addFacetToHash;
service.removeFacetFromHash = removeFacetFromHash;
service.removeAllFacetsFromHash = removeAllFacetsFromHash;
service.toggleFacetInHash = toggleFacetInHash;
// Manipulating information in facet panels
service.isAFacetSelected = isAFacetSelected;
service.isFacetSelected = isFacetSelected;
// Helper which wraps a lookup in $uiRouterGlobals
service.getSearchFacets = getSearchFacets;
/* ----- Function Definitions ----- */
/**
* Helper function to prep the facets to be displayed in the view.
* This function also removes several facets that are displayed in
* other ways in the view.
* @memberof searchFacets
* @function getFlattenedFacets
*/
function getFlattenedFacets() {
var flattenObj = [];
for (var param in $uiRouterGlobals.params) {
if ($uiRouterGlobals.params.hasOwnProperty(param) && Array.isArray($uiRouterGlobals.params[param]) && param !== 'date' && param !== 'icon') {
for (var i = 0; i < $uiRouterGlobals.params[param].length; i++) {
flattenObj.push({
type: param,
name: $uiRouterGlobals.params[param][i],
});
}
}
}
return flattenObj;
}
/**
* Update the state to reflect new keyword search.
* @memberof searchFacets
* @function addFacetsForKeywordSearch
* @param {string} query Text entered into the search box
*/
function addFacetsForKeywordSearch(query) {
$state.go('.', {
page: 1,
text: query,
redirect: '',
}, {
location: 'replace'
});
}
/**
* Adds a search facet (a.k.a. filter) to the state. If the facetType is stored
* as an array, the new facet is added to the end. If the facetType is stored as
* a string, it is replaced by the new value. The calls to $state.go cause an update.
* Any update to the facets, resets the page to 1.
* @memberof searchFacets
* @function addFacetToHash
* @param {string} facetType Major category of facet, e.g. 'department' or 'collection'
* @param {string} currentFacet Specific facet to filter by, e.g. 'Archival Collections'
*/
function addFacetToHash(facetType, currentFacet) {
var searchFacets = service.getSearchFacets(facetType);
var tempObj = {
page: 1,
};
if (Array.isArray(searchFacets) && facetType !== 'date') {
// UI-Router determines a need for a transition by object storage location
// not content, so we need to make a copy of the current facets, modify it,
// then give the copy to UI-router.
searchFacets = searchFacets.slice();
if (searchFacets.indexOf(currentFacet) < 0) {
tempObj[facetType] = searchFacets.concat(currentFacet);
$state.go('.', tempObj, {
location: 'replace'
});
}
} else if (facetType === 'date') {
// Edge case: date is stored as an array, but currently the search
// only supports selecting one date value at a time. So, replace
// the current facet with the value passed into this function.
tempObj[facetType] = [currentFacet];
$state.go('.', tempObj, {
location: 'replace',
});
} else {
tempObj[facetType] = currentFacet;
$state.go('.', tempObj, {
location: 'replace',
});
}
}
/**
* Removes a search facet (a.k.a. filter) from the state. If the facetType is stored
* as an array and the currentFacet is provided, the currentFacet is removed from the array,
* else the entire array is emptied. If the facetType is stored as
* a string, it is replaced by an empty string. The calls to $state.go cause an update.
* Any update to the facets, resets the page to 1.
* @memberof searchFacets
* @function removeFacetFromHash
* @param {string} facetType Major category of facet, e.g. 'department' or 'collection'
* @param {string} currentFacet Specific facet to filter by, e.g. 'Archival Collections'
*/
function removeFacetFromHash(facetType, currentFacet) {
// UI-Router determines a need for a transition by object storage location
// not content, so we need to make a copy of the current facets, modify it,
// then give the copy UI-router.
var searchFacets = service.getSearchFacets(facetType).slice();
var tempObj = {
page: 1,
};
if (Array.isArray(searchFacets)) {
if (currentFacet) {
searchFacets.splice(searchFacets.indexOf(currentFacet), 1);
tempObj[facetType] = searchFacets;
} else {
tempObj[facetType] = [];
}
$state.go('.', tempObj, {
location: 'replace'
});
} else {
tempObj[facetType] = '';
$state.go('.', tempObj, {
location: 'replace'
});
}
}
/**
* Resets state to the defaults stored in the Router config
* @memberof searchFacets
* @function removeAllFacetsFromHash
*/
function removeAllFacetsFromHash() {
$state.go('.', {}, {
inherit: false,
location: 'replace',
});
}
/**
* If the facet's first character is '-' remove it, else add a minus to the front
* of the string, then replace the old facet with the updated one.
* Any update to the facets, resets the page to 1.
* @memberof searchFacets
* @function toggleFacetInHash
* @param {string} facetType Major category of facet, e.g. 'department' or 'collection'
* @param {string} currentFacet Specific facet to filter by, e.g. 'Archival Collections'
*/
function toggleFacetInHash(facetType, currentFacet) {
var tempObj = {
page: 1,
};
// User proofing: this function only works for facets stored in arrays
if (STRING_FACETS.indexOf(facetType) < 0) {
// UI-Router determines a need for a transition by object storage location
// not content, so we need to make a copy of the current facets, modify it,
// ad then give the copy UI-router.
var searchFacets = service.getSearchFacets(facetType).slice();
var indx = searchFacets.indexOf(currentFacet);
if (indx >= 0) {
var toggledFacet = currentFacet.charAt(0) === '-' ? currentFacet.slice(1) : '-' + currentFacet;
searchFacets[indx] = toggledFacet;
tempObj[facetType] = searchFacets;
$state.go('.', tempObj, {
location: 'replace'
});
}
}
if (facetType === 'sort') {
// exception for the collection list sort
var toggledFacet = currentFacet.charAt(0) === '-' ? currentFacet.slice(1) : '-' + currentFacet;
tempObj[facetType] = toggledFacet;
$state.go('.', tempObj, {
location: 'replace'
});
} else {
return false;
}
}
/**
* Returns true if the provided facet type has at least one selected facet in the
* state.
* @memberof searchFacets
* @function isAFacetSelected
* @param {string} facetType Major category of facet, e.g. 'department' or 'collection'
* @return {boolean} true if there is at least one facet of the given type in the
* url hash, false otherwise.
*/
function isAFacetSelected(facetType) {
var searchFacets = service.getSearchFacets(facetType);
return searchFacets && searchFacets.length > 0;
}
/**
* Returns true if the provided facet is in the state.
* @memberof searchFacets
* @function isFacetSelected
* @param {string} facetType Major category of facet, e.g. 'department' or 'collection'
* @param {string} currentFacet Specific facet to filter by, e.g. 'Archival Collections'
* @return {boolean} True if the given facet is in the url hash, false otherwise
*/
function isFacetSelected(facetType, currentFacet) {
var searchFacets = service.getSearchFacets(facetType);
// Type of facet has not yet been selected or all facets of given type have been removed
if (!searchFacets || searchFacets.length === 0) {
return false;
}
return searchFacets.includes(currentFacet) || searchFacets.includes('-' + currentFacet);
}
/**
* Wrapper for a $uiRouterGlobals lookup. If a parameter is provided, the function will
* return all of the facets associated with that type. By default, the function
* returns an object containing all facets currently stored in state.
* @memberof searchFacets
* @function getSearchFacets
* @param {string} facetType Major category of facet, e.g. 'department' or 'collection'
* @return {object | array | string} Object containing all search facets, an array of facets,
* or a string facet for a particular type
*/
function getSearchFacets(facetType) {
if (facetType) {
return $uiRouterGlobals.params[facetType];
}
return $uiRouterGlobals.params;
}
}
})();