(function () {
'use strict';
// Search and filter
angular.module('mohistory').component('searchAndFilter', {
templateUrl: 'app/components/search-and-filter/search-and-filter.component.html',
controller: searchAndFilter,
controllerAs: 'searchAndFilter',
bindings: {
facets: '<',
totalResults: '<',
searchQuery: '<',
dateToDisplay: '<',
onSearchSubmit: '<',
flattenedFacets: '<',
addFacet: '<',
removeFacet: '<',
clearFacets: '<',
toggleFacet: '<',
isFacetSelected: '<',
isAFacetSelected: '<',
isHelpVisible: '<',
hasDisclaimer: '<',
isDisclaimerVisible: '<',
disclaimerContent: '<',
onDisclaimerClose: '<',
isRedirection: '<',
zeroResultContent: '<',
layouts: '<',
curLayout: '<',
setViewLayout: '<',
apiError: '<',
context: '<',
images: '<',
}
});
searchAndFilterCtrl.$inject = ['$transitions', '$location', '$anchorScroll', '$timeout'];
/**
* Manages the search box and facet tabs that are part of each search interface.
* @memberof mohistory
* @name searchAndFilter
* @ngdoc component
* @param {object} $transitions UI-Router service for registering hooks to listen for route changes
* @param {object} $location AngularJS wrapper for document.
* @param {object} $anchorScroll AngularJS service for scrolling the interface
* @param {object} $timeout wrapper for window.setTimeout()
*/
function searchAndFilterCtrl($transitions, $location, $anchorScroll, $timeout) {
var vm = this;
/* ----- Variables ----- */
vm.tab = null;
vm.tabNames = [];
// UI-Router hook triggered when a route succeeds. Update the local copy of search query and scroll
// to the search bar.
var uiOnSuccess = $transitions.onSuccess({}, function ($transition$) {
var stateName = $transition$.to().name;
if (stateName === 'main.events' || stateName === 'main.collections' || stateName === 'main.blog' || stateName === 'main.search') {
// This will only update 'vm.searchQuery' locally not in the parent
vm.searchQuery = $transition$.params('to')['text'];
vm.searchQueryToShow = vm.searchQuery;
// Scroll to the search box
$timeout(function () {
if (Object.keys($location.search()).length !== 0) {
$('html, body').animate({
scrollTop: $('#search-container').offset().top - $('#site-navigation').outerHeight() - 10,
}, 1000);
}
}, 100);
}
});
/* ----- Function Bindings ----- */
vm.$onInit = onInit;
vm.$onDestroy = onDestroy;
vm.isNumber = isNumber;
// Displaying text from input
vm.searchQueryToShow = '';
vm.placeholderText = 'Enter Keyword(s)';
// Manipulating tabs
vm.isTabVisible = isTabVisible;
vm.setTab = setTab;
vm.addFacetPlusCloseTab = addFacetPlusCloseTab;
/* ----- Function Definitions ----- */
/**
* Initial setup for the searchAndFilter component
* @memberof searchAndFilter
* @function onInit
*/
function onInit() {
// Temporary until audience is figured out
if (vm.facets.audience) {
delete vm.facets.audience;
}
// Update query to show
vm.searchQueryToShow = vm.searchQuery;
// Derive tab names from facets
vm.tabNames = Object.keys(vm.facets);
// Technically, this DOM manipulation should be in a link function.
// However, I didn't think it was worth converting the component to
// a directive for this one thing.
if (Object.keys($location.search()).length !== 0) {
var page = $('html, body');
// Scroll to search bar, if there are facets selected. Allow the user to interrupt scroll event.
page.on("scroll mousedown wheel DOMMouseScroll mousewheel keyup touchmove", function () {
page.stop();
});
page.animate({
scrollTop: $('#search-container').offset().top,
}, 3000, function () {
page.off("scroll mousedown wheel DOMMouseScroll mousewheel keyup touchmove");
});
}
}
/**
* Clean up code run when the component is destroyed
* @memberof searchAndFilter
* @function onDestroy
*/
function onDestroy() {
uiOnSuccess();
}
/**
* The search APIs return result counts either as numbers or strings.
* This function returns true if item is a number.
* @memberof searchAndFilter
* @function isNumber
* @param {string | number} item
* @return {boolean} true if the input is a number, false otherwise
*/
function isNumber(item) {
return typeof item === 'number';
}
/**
* Returns true if a tab should be visible to the user, false otherwise.
* @memberof searchAndFilter
* @function isTabVisible
* @param {number} tabToCheck Index of the tab to check.
* @return {boolean} True if tab should be shown, false otherwise
*/
function isTabVisible(tabToCheck) {
return vm.isFacetTabVisible && vm.tab === tabToCheck;
}
/**
* Update the current tab. If vm.tab matches the passed parameter,
* then the tab is closed.
* @memberof searchAndFilter
* @function setTab
* @param {number} activeTab Index of tab to make visible.
*/
function setTab(activeTab) {
if ((activeTab !== 0 && !activeTab) || vm.tab === activeTab) {
vm.tab = null;
vm.isFacetTabVisible = false;
} else {
vm.tab = activeTab;
vm.isFacetTabVisible = true;
}
}
/**
* Add facet to the state and by consequence the URL query string. This will cause the
* state to reload, so to reduce confusion close the currently open tab.
* @memberof searchAndFilter
* @function addFacetPlusCloseTab
* @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 addFacetPlusCloseTab(facetType, currentFacet) {
vm.tab = null;
vm.isFacetTabVisible = false;
vm.addFacet(facetType, currentFacet);
}
}
})();