Move Article Search JavaScript in a separate file (#14194)
* search js in a separate file * add file searchParams and import utilities * fix imports * use global header eslint * add spaces in eslint comments in searchParams.js Co-authored-by: rhymes <github@rhymes.dev> Co-authored-by: rhymes <github@rhymes.dev>
This commit is contained in:
parent
39945f81b4
commit
75144aaaf3
3 changed files with 221 additions and 199 deletions
220
app/javascript/packs/searchParams.js
Normal file
220
app/javascript/packs/searchParams.js
Normal file
|
|
@ -0,0 +1,220 @@
|
|||
/* global checkUserLoggedIn, showLoginModal, userData, buildArticleHTML, initializeReadingListIcons, initializeAllFollowButts, initializeUserFollowButts */
|
||||
/* eslint no-undef: "error" */
|
||||
|
||||
function getQueryParams(qs) {
|
||||
qs = qs.split('+').join(' ');
|
||||
|
||||
const params = {},
|
||||
re = /[?&]?([^=]+)=([^&]*)/g;
|
||||
let tokens;
|
||||
|
||||
while ((tokens = re.exec(qs))) {
|
||||
params[decodeURIComponent(tokens[1])] = decodeURIComponent(tokens[2]);
|
||||
}
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
const params = getQueryParams(document.location.search);
|
||||
|
||||
function searchMain(substories) {
|
||||
const query = filterXSS(params.q);
|
||||
const filters = filterXSS(params.filters || 'class_name:Article');
|
||||
const sortBy = filterXSS(params.sort_by || '');
|
||||
const sortDirection = filterXSS(params.sort_direction || '');
|
||||
|
||||
substories.innerHTML =
|
||||
'<div class="p-9 align-center crayons-card"><br></div>';
|
||||
if (document.getElementById('query-wrapper')) {
|
||||
search(query, filters, sortBy, sortDirection);
|
||||
initializeFilters(query, filters);
|
||||
initializeSortingTabs(query);
|
||||
}
|
||||
}
|
||||
|
||||
function initializeSortingTabs(query) {
|
||||
const sortingTabs = document.querySelectorAll(
|
||||
'#sorting-option-tabs .crayons-tabs__item',
|
||||
);
|
||||
|
||||
for (let i = 0; i < sortingTabs.length; i++) {
|
||||
const tab = sortingTabs[i];
|
||||
|
||||
tab.addEventListener('click', (e) => {
|
||||
const currentParams = getQueryParams(document.location.search);
|
||||
const filters = filterXSS(currentParams.filters);
|
||||
|
||||
const { sortBy, sortDirection } = e.target.dataset;
|
||||
const sortString = buildSortString(sortBy, sortDirection);
|
||||
|
||||
if (filters) {
|
||||
window.history.pushState(
|
||||
null,
|
||||
null,
|
||||
`/search?q=${query}&filters=${filters}${sortString}`,
|
||||
);
|
||||
search(query, filters, sortBy, sortDirection);
|
||||
} else {
|
||||
window.history.pushState(null, null, `/search?q=${query}${sortString}`);
|
||||
search(query, '', sortBy, sortDirection);
|
||||
}
|
||||
|
||||
for (let j = 0; j < sortingTabs.length; j++) {
|
||||
if (sortingTabs[j] !== e.target) {
|
||||
sortingTabs[j].classList.remove('crayons-tabs__item--current');
|
||||
sortingTabs[j].setAttribute('aria-current', '');
|
||||
}
|
||||
}
|
||||
|
||||
e.target.classList.add('crayons-tabs__item--current');
|
||||
e.target.setAttribute('aria-current', 'page');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function initializeFilters(query, filters) {
|
||||
const filterButts = document.getElementsByClassName('query-filter-button');
|
||||
for (let i = 0; i < filterButts.length; i++) {
|
||||
if (filters === filterButts[i].dataset.filter) {
|
||||
filterButts[i].classList.add('crayons-link--current');
|
||||
}
|
||||
filterButts[i].onclick = function (e) {
|
||||
const currentParams = getQueryParams(document.location.search);
|
||||
const sortBy = filterXSS(currentParams.sort_by);
|
||||
const sortDirection = filterXSS(currentParams.sort_direction);
|
||||
const sortString = buildSortString(sortBy, sortDirection);
|
||||
|
||||
if (
|
||||
e.target.classList.contains('my-posts-query-button') &&
|
||||
!checkUserLoggedIn()
|
||||
) {
|
||||
showLoginModal();
|
||||
return;
|
||||
}
|
||||
const filters = e.target.dataset.filter;
|
||||
window.history.pushState(
|
||||
null,
|
||||
null,
|
||||
`/search?q=${query}&filters=${filters}${sortString}`,
|
||||
);
|
||||
const { className } = e.target;
|
||||
for (let i = 0; i < filterButts.length; i++) {
|
||||
filterButts[i].classList.remove('crayons-link--current');
|
||||
}
|
||||
if (className.indexOf('crayons-link--current') === -1) {
|
||||
e.target.classList.add('crayons-link--current');
|
||||
window.history.replaceState(
|
||||
null,
|
||||
null,
|
||||
`/search?q=${query}&filters=${filters}${sortString}`,
|
||||
);
|
||||
search(query, filters, sortBy, sortDirection);
|
||||
} else {
|
||||
window.history.replaceState(
|
||||
null,
|
||||
null,
|
||||
`/search?q=${query}${sortString}`,
|
||||
);
|
||||
search(query, '', sortBy, sortDirection);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function buildSortString(sortBy, sortDirection) {
|
||||
return sortBy && sortDirection
|
||||
? `&sort_by=${sortBy}&sort_direction=${sortDirection}`
|
||||
: '';
|
||||
}
|
||||
|
||||
function search(query, filters, sortBy, sortDirection) {
|
||||
const hashtags = query.match(/#\w+/g);
|
||||
const searchTerm = query.replace(/#/g, '').trim();
|
||||
const searchHash = { per_page: 60, page: 0 };
|
||||
|
||||
if (sortBy && sortDirection) {
|
||||
searchHash.sort_by = sortBy;
|
||||
searchHash.sort_direction = sortDirection;
|
||||
}
|
||||
|
||||
if (filters === 'MY_POSTS' && userData()) {
|
||||
searchHash.user_id = userData()['id'];
|
||||
searchHash.class_name = 'Article';
|
||||
}
|
||||
|
||||
if (hashtags && hashtags.length > 0) {
|
||||
for (let i = 0; i < hashtags.length; i++) {
|
||||
hashtags[i] = hashtags[i].replace(/#/, '');
|
||||
}
|
||||
searchHash.tag_names = hashtags;
|
||||
}
|
||||
|
||||
if (filters) {
|
||||
filters.split('&').forEach((filter) => {
|
||||
const [key, value] = filter.split(':');
|
||||
searchHash[key] = value;
|
||||
});
|
||||
}
|
||||
|
||||
if (searchTerm) {
|
||||
searchHash.search_fields = searchTerm;
|
||||
}
|
||||
|
||||
// Brute force copying code from a utlity for quick fix
|
||||
const searchParams = new URLSearchParams();
|
||||
Object.keys(searchHash).forEach((key) => {
|
||||
const value = searchHash[key];
|
||||
if (Array.isArray(value)) {
|
||||
value.forEach((arrayValue) => {
|
||||
searchParams.append(`${key}[]`, arrayValue);
|
||||
});
|
||||
} else {
|
||||
searchParams.append(key, value);
|
||||
}
|
||||
});
|
||||
|
||||
fetch(`/search/feed_content?${searchParams.toString()}`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
'X-CSRF-Token': window.csrfToken,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
credentials: 'same-origin',
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then((content) => {
|
||||
const resultDivs = [];
|
||||
content.result.forEach((story) => {
|
||||
resultDivs.push(buildArticleHTML(story));
|
||||
});
|
||||
document.getElementById('substories').innerHTML = resultDivs.join('');
|
||||
initializeReadingListIcons();
|
||||
initializeAllFollowButts();
|
||||
initializeUserFollowButts();
|
||||
document
|
||||
.getElementById('substories')
|
||||
.classList.add('search-results-loaded');
|
||||
if (content.result.length === 0) {
|
||||
document.getElementById('substories').innerHTML =
|
||||
'<div class="p-9 align-center crayons-card">No results match that query</div>';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const waitingOnSearch = setInterval(() => {
|
||||
if (
|
||||
typeof search === 'function' &&
|
||||
typeof filterXSS === 'function' &&
|
||||
typeof buildArticleHTML === 'function'
|
||||
) {
|
||||
clearInterval(waitingOnSearch);
|
||||
const substories = document.getElementById('substories');
|
||||
if (
|
||||
substories &&
|
||||
document.getElementsByClassName('search-results-loaded').length === 0
|
||||
) {
|
||||
searchMain(substories);
|
||||
}
|
||||
}
|
||||
}, 1);
|
||||
|
|
@ -1,197 +0,0 @@
|
|||
<script defer>
|
||||
|
||||
function getQueryParams(qs) {
|
||||
qs = qs.split('+').join(' ');
|
||||
|
||||
var params = {},
|
||||
tokens,
|
||||
re = /[?&]?([^=]+)=([^&]*)/g;
|
||||
|
||||
while (tokens = re.exec(qs)) {
|
||||
params[decodeURIComponent(tokens[1])] = decodeURIComponent(tokens[2]);
|
||||
}
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
var params = getQueryParams(document.location.search);
|
||||
|
||||
function searchMain(substories) {
|
||||
var query = filterXSS(params.q);
|
||||
var filters = filterXSS(params.filters || "class_name:Article");
|
||||
var sortBy = filterXSS(params.sort_by || "");
|
||||
var sortDirection = filterXSS(params.sort_direction || "");
|
||||
|
||||
substories.innerHTML = '<div class="p-9 align-center crayons-card"><br></div>';
|
||||
if (document.getElementById("query-wrapper")) {
|
||||
search(query, filters, sortBy, sortDirection);
|
||||
initializeFilters(query, filters);
|
||||
initializeSortingTabs(query);
|
||||
}
|
||||
}
|
||||
|
||||
function htmlEntities(str) {
|
||||
return String(str).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
|
||||
}
|
||||
|
||||
function initializeSortingTabs(query) {
|
||||
var sortingTabs = document.querySelectorAll('#sorting-option-tabs .crayons-tabs__item');
|
||||
|
||||
for (var i=0; i < sortingTabs.length; i++) {
|
||||
var tab = sortingTabs[i];
|
||||
|
||||
tab.addEventListener("click", function(e) {
|
||||
var currentParams = getQueryParams(document.location.search);
|
||||
var filters = filterXSS(currentParams.filters);
|
||||
|
||||
var { sortBy, sortDirection } = e.target.dataset;
|
||||
var sortString = buildSortString(sortBy, sortDirection);
|
||||
|
||||
if (filters) {
|
||||
window.history.pushState(null, null, "/search?q=" + query + "&filters=" + filters + sortString);
|
||||
search(query, filters, sortBy, sortDirection);
|
||||
} else {
|
||||
window.history.pushState(null, null, "/search?q=" + query + sortString);
|
||||
search(query, "", sortBy, sortDirection);
|
||||
}
|
||||
|
||||
for (var j=0; j < sortingTabs.length; j++) {
|
||||
if (sortingTabs[j] !== e.target) {
|
||||
sortingTabs[j].classList.remove("crayons-tabs__item--current");
|
||||
sortingTabs[j].setAttribute('aria-current', '');
|
||||
}
|
||||
}
|
||||
|
||||
e.target.classList.add("crayons-tabs__item--current");
|
||||
e.target.setAttribute('aria-current', 'page');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function initializeFilters(query, filters) {
|
||||
var filterButts = document.getElementsByClassName("query-filter-button");
|
||||
for (var i = 0; i < filterButts.length; i++) {
|
||||
if (filters === filterButts[i].dataset.filter) {
|
||||
filterButts[i].classList.add("crayons-link--current");
|
||||
}
|
||||
filterButts[i].onclick = function (e) {
|
||||
var currentParams = getQueryParams(document.location.search);
|
||||
var sortBy = filterXSS(currentParams.sort_by);
|
||||
var sortDirection = filterXSS(currentParams.sort_direction);
|
||||
var sortString = buildSortString(sortBy, sortDirection);
|
||||
|
||||
if (e.target.classList.contains("my-posts-query-button") && !checkUserLoggedIn()) {
|
||||
showLoginModal();
|
||||
return;
|
||||
}
|
||||
var filters = e.target.dataset.filter;
|
||||
window.history.pushState(null, null, "/search?q=" + query + "&filters=" + filters + sortString);
|
||||
var className = e.target.className;
|
||||
for (var i = 0; i < filterButts.length; i++) {
|
||||
filterButts[i].classList.remove("crayons-link--current");
|
||||
}
|
||||
if (className.indexOf("crayons-link--current") === -1) {
|
||||
e.target.classList.add("crayons-link--current");
|
||||
window.history.replaceState(null, null, "/search?q=" + query + "&filters=" + filters + sortString);
|
||||
search(query, filters, sortBy, sortDirection);
|
||||
} else {
|
||||
window.history.replaceState(null, null, "/search?q=" + query + sortString);
|
||||
search(query, "", sortBy, sortDirection);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function addOptionalBanner(query, displayBanner, jobsUrl) {
|
||||
var lowerCaseQuery = query.toLowerCase();
|
||||
|
||||
if (displayBanner && lowerCaseQuery.includes("job")) {
|
||||
document.getElementById("banner-section").innerHTML = '<div class="crayons-notice crayons-notice--info mb-3 fs-base" aria-live="polite">Interested in joining our team? Explore our <a href=' + jobsUrl + '>open roles</a>.</div>';
|
||||
}
|
||||
}
|
||||
|
||||
function buildSortString(sortBy, sortDirection) {
|
||||
return sortBy && sortDirection ? "&sort_by=" + sortBy + "&sort_direction=" + sortDirection : "";
|
||||
}
|
||||
|
||||
function search(query, filters, sortBy, sortDirection) {
|
||||
var hashtags = query.match(/#\w+/g);
|
||||
var searchTerm = query.replace(/#/g, '').trim();
|
||||
var searchHash = { per_page: 60, page: 0 };
|
||||
|
||||
if (sortBy && sortDirection) {
|
||||
searchHash.sort_by = sortBy;
|
||||
searchHash.sort_direction = sortDirection;
|
||||
}
|
||||
|
||||
if (filters === "MY_POSTS" && userData()) {
|
||||
searchHash.user_id = userData()['id'];
|
||||
searchHash.class_name = "Article";
|
||||
}
|
||||
|
||||
if (hashtags && hashtags.length > 0) {
|
||||
for(var i = 0; i < hashtags.length; i++){
|
||||
hashtags[i] = hashtags[i].replace(/#/,'');
|
||||
}
|
||||
searchHash.tag_names = hashtags;
|
||||
}
|
||||
|
||||
if (filters) {
|
||||
filters.split('&').forEach((filter) => {
|
||||
const [key, value] = filter.split(':');
|
||||
searchHash[key] = value;
|
||||
});
|
||||
}
|
||||
|
||||
if (searchTerm) { searchHash.search_fields = searchTerm; }
|
||||
|
||||
// Brute force copying code from a utlity for quick fix
|
||||
const searchParams = new URLSearchParams();
|
||||
Object.keys(searchHash).forEach((key) => {
|
||||
const value = searchHash[key];
|
||||
if (Array.isArray(value)) {
|
||||
value.forEach((arrayValue) => {
|
||||
searchParams.append(`${key}[]`, arrayValue);
|
||||
});
|
||||
} else {
|
||||
searchParams.append(key, value);
|
||||
}
|
||||
});
|
||||
|
||||
fetch(`/search/feed_content?${searchParams.toString()}`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
'X-CSRF-Token': window.csrfToken,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
credentials: 'same-origin',
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then((content) => {
|
||||
var resultDivs = []
|
||||
content.result.forEach(function (story, i) {
|
||||
resultDivs.push(buildArticleHTML(story));
|
||||
})
|
||||
document.getElementById("substories").innerHTML = resultDivs.join("");
|
||||
initializeReadingListIcons();
|
||||
initializeAllFollowButts();
|
||||
initializeUserFollowButts();
|
||||
document.getElementById("substories").classList.add("search-results-loaded");
|
||||
if (content.result.length === 0) {
|
||||
document.getElementById("substories").innerHTML = '<div class="p-9 align-center crayons-card">No results match that query</div>'
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var waitingOnSearch = setInterval(function () {
|
||||
if (typeof search === 'function' && typeof filterXSS === 'function' && typeof buildArticleHTML === 'function') {
|
||||
clearInterval(waitingOnSearch);
|
||||
const substories = document.getElementById("substories");
|
||||
if (substories && document.getElementsByClassName('search-results-loaded').length === 0) {
|
||||
searchMain(substories);
|
||||
}
|
||||
}
|
||||
}, 1);
|
||||
|
||||
</script>
|
||||
|
|
@ -54,6 +54,5 @@
|
|||
</div>
|
||||
</div>
|
||||
</main>
|
||||
<%= render "articles/search" %>
|
||||
|
||||
<%= javascript_packs_with_chunks_tag "storiesList", defer: true %>
|
||||
<%= javascript_packs_with_chunks_tag "searchParams", "storiesList", defer: true %>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue