Something went wrong. Try again.
find work, anywhere www.remotehiro.com
rust job-board
Something went wrong. Try again.
4.9 kB · 152 lines
JavaScript
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153const html = { getToggleFiltersButton: () => document.querySelector("#toggle-filters"), getFiltersForm: () => document.querySelector("#filters"), getJobsTableBody: () => document.querySelector(".jobs > tbody"),
getFieldsetCheckbox: (id) => document.querySelector(`fieldset > legend input[id=${id}][type=checkbox]`), getFieldsetsCheckboxes: () => document.querySelectorAll(`fieldset > legend input[id][type=checkbox]`),
getFieldsetOptions: (name, opts) => { let query = `input[name=${name}][type=checkbox]`; if (opts.isChecked != null && opts.isChecked) { query = `${query}:checked` } if (opts.isChecked != null && !opts.isChecked) { query = `${query}:not(:checked)` } return document.querySelectorAll(query); },
getTagsSearchInput: () => document.querySelector("#tags-search"), getCountriesSearchInput: () => document.querySelector("#countries-search"),
filterOptions: (query, selectorName, datasetName) => { let rows = document.querySelectorAll(selectorName); rows.forEach(row => { if (!fuzzysearch(query, row.dataset[datasetName]) && query) { row.style.display = "none"; } else { row.style.display = ""; } }) }};
const FETCH_TIMEOUT = 400;
// Source: https://github.com/bevacqua/fuzzysearchfunction fuzzysearch (needle, haystack) { var hlen = haystack.length; var nlen = needle.length; if (nlen > hlen) { return false; } if (nlen === hlen) { return needle === haystack; } outer: for (var i = 0, j = 0; i < nlen; i++) { var nch = needle.charCodeAt(i); while (j < hlen) { if (haystack.charCodeAt(j++) === nch) { continue outer; } } return false; } return true;}
// On page loadlet submitTicker = null;
html.getToggleFiltersButton()?.addEventListener("click", (e) => { let filtersForm = html.getFiltersForm();
if (filtersForm.style.display == "block") { filtersForm.style.display = "none"; } else { filtersForm.style.display = "block"; }});
html.getFiltersForm()?.addEventListener("input", (e) => { if (submitTicker != null) { clearTimeout(submitTicker); }
let isTextInput = e.target.type == "text" || e.target.type == "search" || e.target.type == "number"; let delay = isTextInput ? FETCH_TIMEOUT : 0;
let form = html.getFiltersForm(); // If it's a fieldset checkbox, then we toggle all of the checkboxes in the // fieldset whose `name` matches the ID. if (e.target.type == "checkbox" && e.target.id != "") { let checkboxes = document.querySelectorAll(`input[name=${e.target.id}][type=checkbox]`); checkboxes.forEach((el) => el.checked = e.target.checked); } else if (e.target.type == "checkbox" && e.target.name != "") { let fieldsetCheckbox = html.getFieldsetCheckbox(e.target.name); let uncheckedBoxes = html.getFieldsetOptions(e.target.name, {"isChecked": false}); let checkedBoxes = html.getFieldsetOptions(e.target.name, {"isChecked": true}); fieldsetCheckbox.indeterminate = uncheckedBoxes.length >= 1 && checkedBoxes.length >= 1; fieldsetCheckbox.checked = checkedBoxes.length >= 1 && uncheckedBoxes.length == 0; } submitTicker = setTimeout(() => submitForm(toFormData(form), form.action), delay);});
function toFormData(form) { const formData = new FormData(form); let minSalary = formData.get("min_salary");
if (minSalary && parseInt(minSalary) <= 0) { formData.delete("min_salary"); }
formData.entries().forEach(([k, v]) => { if (v == "") { formData.delete(k); } }); return formData;}
async function submitForm(formData, action) { console.log(formData); const queryParams = new URLSearchParams(formData);
// Push new query parameters to history const url = new URL(location);
url.search = ""; queryParams.entries().forEach(([k,v]) => { url.searchParams.append(k, v); });
history.pushState({}, "", url);
// Dispatch request and replace content const res = await fetch(action + '?' + queryParams.toString(), { method: "GET", headers: { 'Hx-Request': 'true' } });
let htmlRes = await res.text(); html.getJobsTableBody().innerHTML = htmlRes;}
let fieldsetCheckboxes = html.getFieldsetsCheckboxes();
fieldsetCheckboxes.forEach(el => { let uncheckedBoxes = html.getFieldsetOptions(el.id, {"isChecked": false}); let checkedBoxes = html.getFieldsetOptions(el.id, {"isChecked": true}); el.indeterminate = uncheckedBoxes.length >= 1 && checkedBoxes.length >= 1});
html.getTagsSearchInput().addEventListener("input", (e) => { html.filterOptions(html.getTagsSearchInput().value?.toLowerCase(), ".tag[data-tag-name]", "tagName");});
html.getCountriesSearchInput().addEventListener("input", (e) => { html.filterOptions(html.getCountriesSearchInput().value?.toLowerCase(), ".country[data-country-name]", "countryName");});