Select Git revision
ContentModules.vue
Forked from
Stud.IP / Stud.IP
Source project has a limited visibility.
-
Rasmus Fuhse authored
Closes #2440 Merge request studip/studip!1695
Rasmus Fuhse authoredCloses #2440 Merge request studip/studip!1695
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
global_search.js 9.17 KiB
const GlobalSearch = {
lastSearch: null,
/**
* Toggles visibility of search input field and hints.
* @param visible boolean indicating whether shown or not
* @param cleanup boolean whether to clear search term and results
* @returns {boolean}
*/
toggleSearchBar: function(visible, cleanup) {
$('#globalsearch-searchbar').toggleClass('is-visible', visible);
$('#globalsearch-input').attr('aria-expanded', visible ? 'true' : 'false');
$('#globalsearch-input').toggleClass('hidden-small-down', !visible);
$('#globalsearch-icon').toggleClass('hidden-small-down', visible);
$('#globalsearch-clear').toggleClass('hidden-small-down', !visible);
if (!visible && cleanup) {
GlobalSearch.lastSearch = null;
$('#globalsearch-searchbar').removeClass('has-value');
$('#globalsearch-results').html('');
$('#globalsearch-input').blur().val('');
}
$('html:not(.size-large)').toggleClass('globalsearch-visible', visible);
return false;
},
/**
* Performs the actual search.
*/
doSearch: function() {
var searchterm = $('#globalsearch-input').val().trim();
var hasValue = searchterm.length >= 3;
var results = $();
var resultsDiv = $('#globalsearch-results');
var resultsPerType = resultsDiv.data('results-per-type');
var moreResultsText = resultsDiv.data('more-results');
var limit = resultsPerType * 3;
var wrapper = $('#globalsearch-searchbar');
if (searchterm === '') {
return;
}
wrapper.toggleClass('has-value', hasValue);
if (!hasValue || GlobalSearch.lastSearch === searchterm) {
return;
}
GlobalSearch.lastSearch = searchterm;
// Display spinner symbol, user should always see something is happening.
wrapper.addClass('is-searching');
// Call AJAX endpoint and get search results.
$.getJSON(STUDIP.URLHelper.getURL('dispatch.php/globalsearch/find/' + limit, {}, true), {
search: searchterm,
filters: '{"category":"show_all_categories","semester":"future"}'
}).done(function(json) {
resultsDiv.empty();
// No results found...
if (!$.isPlainObject(json) || $.isEmptyObject(json)) {
wrapper.removeClass('is-searching');
resultsDiv.html(resultsDiv.data('no-result'));
return;
}
// Iterate over each result category.
$.each(json, function(name, value) {
// Create an <article> for category.
var category = $(`<article id="globalsearch-${name}" role="list">`),
header = $('<header>').appendTo(category),
counter = 0;
// Create header name
$('<a href="#">')
.text(value.name)
.wrap('<div class="globalsearch-category">')
.parent() // Element is now the wrapper
.data('category', name)
.appendTo(header);
// We have more search results than shown, provide link to
// full search if available.
if (value.more && value.fullsearch !== '') {
$('<a>')
.attr('href', value.fullsearch)
.text(moreResultsText)
.wrap('<div class="globalsearch-more-results">')
.parent() // Element is now the wrapper
.appendTo(header);
}
// Process results and create corresponding entries.
$.each(value.content, function(index, result) {
// Create single result entry.
var single = $(`<a href="${result.url}" role="listitem" ${dataDialog}>`),
data = $('<div class="globalsearch-result-data">'),
details = $('<div class="globalsearch-result-details">');
if (counter >= resultsPerType) {
single.addClass('globalsearch-extended-result');
}
// Which result types should be opened via dialog?
const openInDialog = ['GlobalSearchFiles', 'GlobalSearchMessages'];
var dataDialog = (openInDialog.indexOf(name) >= 0 ? dataDialog = 'data-dialog' : dataDialog = '');
//var link = $(`<a href="${result.url}" ${dataDialog}>`).appendTo(single);
// Optional image...
if (result.img !== null) {
$(`<img src="${result.img}" alt="">`)
.wrap('<div class="globalsearch-result-img">')
.parent() // Element is now the wrapper
.appendTo(single);
}
single.append(data);
// Name/title
$('<div class="globalsearch-result-title">')
.html(result.name)
.appendTo(data);
// Details: Descriptional text
if (result.description !== null) {
$('<div class="globalsearch-result-description">')
.html(result.description)
.appendTo(details);
}
// Details: Additional information
if (result.additional !== null) {
$('<div class="globalsearch-result-additional">')
.html(result.additional)
.appendTo(details);
}
data.append(details);
// Date/Time of entry
if (result.date !== null) {
$('<div class="globalsearch-result-time">')
.html(result.date)
.appendTo(single);
}
// "Expand" attribute for further, result-related search
// (e.g. search in course of found forum entry)
if (result.expand !== null && result.expand !== value.fullsearch && value.more) {
$(`<a href="${result.expand}" title="${result.expandtext}">`)
.wrap('<div class="globalsearch-result-expand">')
.parent() // Element is now the wrapper
.appendTo(single);
}
category.append(single);
counter += 1;
});
results = results.add(category);
});
resultsDiv.html(results);
wrapper.removeClass('is-searching');
}).fail(function(xhr, status, error) {
if (error) {
window.alert(error);
}
});
},
/**
* Clear search term and remove results for previous search term.
*/
resetSearch: function() {
GlobalSearch.lastSearch = null;
$('#globalsearch-searchbar').removeClass('is-visible has-value');
$('#globalsearch-input').attr('aria-expanded', 'false');
$('#globalsearch-input').val('');
$('#globalsearch-results').html('');
$('#globalsearch-input').focus();
},
/**
* Expand a single category, showing more results, and hide other
* categories.
* @param category
* @returns {boolean}
*/
expandCategory: function(category) {
// Hide other categories.
$(`#globalsearch-results article:not([id="globalsearch-${category}"])`).hide();
// Show all results.
$(`#globalsearch-${category} section.globalsearch-extended-result`).removeClass(
'globalsearch-extended-result'
);
$(`article#globalsearch-${category}`).get(0).scrollIntoView();
// Reassign category click to closing extended view.
$(`#globalsearch-results article#globalsearch-${category} header div.globalsearch-category a`)
.off('click')
.on('click', function() {
GlobalSearch.showAllCategories(category);
return false;
});
return false;
},
/**
* Close expanded view of a single category, showing normal view with
* all categories again.
* @param currentCategory
*/
showAllCategories: function(currentCategory) {
$(`#globalsearch-results article#globalsearch-${currentCategory} header div.globalsearch-category a`)
.off('click')
.on('click', function() {
GlobalSearch.expandCategory(currentCategory);
return false;
});
var resultCount = $('#globalsearch-results').data('results-per-type') - 1;
$(`#globalsearch-${currentCategory} section:gt(${resultCount})`).addClass(
'globalsearch-extended-result'
);
$('#globalsearch-results')
.children(`article:not([id="globalsearch-${currentCategory}"])`)
.show();
return false;
}
};
export default GlobalSearch;