* adds focusTrap wrapper to preact Modal component * add view specific code for focus trap in admin add nav link * add script to return a focustrap toggle, use in add nav link modal partial * add trap to edit nav link modal * add handlers for sign up modal * update modal controller for admin section, update nav link modals to use * update other admin modals with new data values for trap * remove unneeded erb script file * remove unneeded target * refactor to remove extra unneeded param * remove duplicate code, store getFocusTrapToggle in window * trap focus in comment and bookmark showModal instances for not logged in user * remove need for activator id * clean up id refs no longer needed * remove custom code and re-use focsu-trap lib * update storybook docs * update default export in focusTrap * prevent close button click triggering a modal toggle twice * ensure if user navigates from a modal the trap is deactivated * add jsdoc comments and add dynamic import * ensure admin controller modal traps are cleaned up on disconnect * update sign up modal to use crayons * update modal controller and admin nav links modals to use preact modal * update profile fields modals for new controller * tweak styling of sign up and admin modals to match previous * update listings modal to use crayons modal, adapt focus trap to work with click outside * memoize deactivate callback to ensure modal can be presented on first page load * add missed focustrap changes * fix focus trap issues in onboarding flow * refactor onboarding focus trap, remove getFocusTrapToggle * tweaks for styling and article modal toggle * add click outside tests to modal * add cypress tests for the login modal * update liquid tag tests affected by change * refactors to address review comments * fix issue with login modal presented twice on comment add * change ids to selectors in admin modals * small pr comment refactors * add listings e2e tests * add nav link modal tests * fix issue with help modal * tweak to fix ui bug from merge * remove context from showLoginModal * rename toggleModal * rename state property for clarity Co-authored-by: Nick Taylor <nick@dev.to>
199 lines
7 KiB
Text
199 lines
7 KiB
Text
<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 || "");
|
|
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.getElementById("sorting-option-tabs").children;
|
|
|
|
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");
|
|
}
|
|
}
|
|
|
|
e.target.classList.add("crayons-tabs__item--current");
|
|
});
|
|
}
|
|
}
|
|
|
|
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">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) => {
|
|
if (searchHash["search_fields"] && content.jobs_url) {
|
|
addOptionalBanner(searchHash["search_fields"], content.display_jobs_banner, content.jobs_url);
|
|
}
|
|
|
|
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>
|