(function () {
// Keyword Searcher
angular
.module('mohistory')
.service('keywordSearcher', keywordSearcher);
keywordSearcher.$inject = ['searchFacets', '$http', '$q', '$location', 'configSeparated', 'currentEnvironment'];
/**
* Wrapper for http calls to retrieve data for the search interfaces, includes methods to handle
* both pagination and infinite scrolling.
* @memberof mohistory
* @name keywordSearcher
* @ngdoc service
*/
function keywordSearcher(searchFacets, $http, $q, $location, configSeparated, currentEnvironment) {
var service = this;
/* ----- Variables ----- */
// Details required to query the APIs given a context
service.apiConfig = {
'search-collections': {
api: configSeparated[currentEnvironment].SERVICES_PATH + 'CCSearchV2/search',
itemAPI: configSeparated[currentEnvironment].SERVICES_PATH + 'CCSearch/getItem&CCS_id=',
childList: configSeparated[currentEnvironment].SERVICES_PATH + 'CCSearch/getChildItems',
eadApi: configSeparated[currentEnvironment].API_BASE + 'collection/',
reqHeaders: {
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
},
},
'search-events': {
api: configSeparated[currentEnvironment].API_BASE + 'search/events',
reqHeaders: {
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
},
},
'search-all': {
api: configSeparated[currentEnvironment].API_BASE + 'search',
reqHeaders: {
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
},
},
'search-blog': {
api: configSeparated[currentEnvironment].API_BASE + 'search/blog',
reqHeaders: {
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
},
},
};
/* ----- Function Bindings ----- */
service.getResultsForPage = getResultsForPage;
service.getCollectionItem = getCollectionItem;
service.getItemEADFromSearch = getItemEADFromSearch;
service.getItemChildList = getItemChildList;
service.getInfinList = getInfinList;
/* ----- Function Definitions ----- */
/**
* Retrieve information for a given collection item.
* @memberof keywordSearcher
* @function getCollectionItem
* @param {string} itemID Slug identifying an item
* @return {object} a promise which will resolve with data from the API or false
*/
function getCollectionItem(itemID) {
var apiInfo = service.apiConfig['search-collections'];
return $http.get(apiInfo.itemAPI + itemID).then(function (response) {
return response.data;
}).catch(function (error) {
handleError(error, '', error.status);
return false;
});
}
/**
* Retrieve EAD information for a given collection item.
* @memberof keywordSearcher
* @function getItemEADFromSearch
* @param {string} collectionID Slug identifying a collection
* @return {object} a promise which will resolve with data from the API or an empty object
*/
function getItemEADFromSearch(collectionID) {
var apiInfo = service.apiConfig['search-collections'];
return $http.get(apiInfo.eadApi + collectionID).then(function (response) {
return response.data;
}).catch(function (error) {
return {};
});
}
/**
* Retrieve sub records (i.e. child list) for a given record. This function
* is called in conjunction with a infinite scroll setup.
* @memberof keywordSearcher
* @function getItemChildList
* @param {string} itemID Slug identifying the item's id
* @param {number} from Starting index for the returned results
* @return {object} a promise which will resolve with data from the API or an empty array
*/
function getItemChildList(itemID, from) {
var apiInfo = service.apiConfig['search-collections'];
var params = {
text: [itemID],
from: from,
};
return $http.post(apiInfo.childList, params, apiInfo.reqHeaders).then(function (response) {
if (response.data.items) {
response.data.total = parseCommaNum(response.data.total);
return response.data;
} else {
return [];
}
}).catch(function (error) {
return [];
});
}
/**
* Get items for search. This function is meant to be called as part of an
* infinite scroll setup.
* @memberof keywordSearcher
* @function getInfinList
* @param {string} context The context in which the search is being
* performed: events, blog, general, collections
* @param {object} params Object containing all the facets that need to be
* sent to the API
* @param {number} from Starting index for the returned results
* @return {object} a promise which will resolve with data from the API or an empty array
*/
function getInfinList(context, params, from) {
params = angular.extend({}, params, {
text: new Array(params.text),
from: from,
});
var apiInfo = service.apiConfig[context];
return $http.post(apiInfo.api, JSON.stringify(params),
apiInfo.reqHeaders).then(function (response) {
if (response.data.items) {
response.data.total = parseCommaNum(response.data.total);
service.data = response.data;
calculatePage(service.data, params);
return service.data;
} else {
return [];
}
}).catch(function (error) {
return 'error'; // normally we would return a $q.reject(), but we want
// the route to succeed, so we return a value passing it along to the next then in the change were we will handle it.
});
}
/**
* Get items for search. This function is meant to be called as part of a paged result.
* @memberof keywordSearcher
* @function getResultsForPage
* @param {string} context The context in which the search is being
* performed: events, blog, general, collections
* @param {object} params Object containing all the facets that need to be
* sent to the API
* @return {object} a promise which will resolve with data from the API or a string message
*/
function getResultsForPage(context, params) {
params = angular.extend({}, params, {
text: new Array(params.text),
from: (params.page - 1) * params.size,
});
var apiInfo = service.apiConfig[context];
return $http.post(apiInfo.api,
JSON.stringify(params),
apiInfo.reqHeaders).then(function (response) {
response.data.total = parseCommaNum(response.data.total);
service.data = response.data;
calculatePage(service.data, params);
return service.data;
}).catch(function (error) {
return 'error'; // normally we would return a $q.reject(), but we want
// the route to succeed, so we return a value passing it along to the next then in the change were we will handle it.
});
}
/**
* Calculate values related to pagination.
* @memberof keywordSearcher
* @function calculatePage
* @param {string} data Results object retrieved from the API
* @param {object} urlParams Object containing all the facets that need to be
* sent to the API
*/
function calculatePage(data, urlParams) {
var totalPages = Math.ceil(data.total / urlParams.size);
// Cannot ask for more than 10000 results due to Elastic Search
data.maxPages = Math.floor(10000 / urlParams.size);
data.totalPages = totalPages < data.maxPages ? totalPages : (data.maxPages - 1);
data.curPage = urlParams.from < urlParams.size ? 1 : Math.ceil((urlParams.from + 1) / urlParams.size);
}
/**
* If total results comes back as a string from the API. Remove any commas and
* convert it to a number.
* @memberof keywordSearcher
* @function parseCommaNum
* @param {string} num Total results returned from the API
*/
function parseCommaNum(num) {
if (typeof num !== 'number') {
num = num.replace(/,/g, "");
return parseInt(num, 10);
} else {
return num;
}
}
/**
* If something goes wrong redirect to the resolver script.
* @memberof keywordSearcher
* @function handleError
* @param {object} error The problem as reported by the API
* @param {string} path URL which produced the error
* @param {string} status Status returned by the API
*/
function handleError(error, path, status) {
if (path === '') {
console.log('Error Redirecting - http://utils.mohistory.org/resolve')
window.location.href = 'http://utils.mohistory.org/resolve';
} else {
console.log('Error Redirecting - http://utils.mohistory.org/resolve' + '?path=' + $location.absUrl() + '&status=' + status)
window.location.href = 'http://utils.mohistory.org/resolve' + '?path=' + $location.absUrl() + 'status=' + status;
}
}
}
})();