website/conservancy/static/js/supporter-page.js
Ben Sturmfels 44c0a9db32
Remove remaining jQuery
This avoids every page on the site parsing 250KB of JavaScript.

supporter-page.js isn't the most elegant code, but at least it's a little more
modular now and no longer user jQuery.
2024-05-09 22:15:33 +10:00

138 lines
5 KiB
JavaScript

/* Copyright (C) 2012-2013 Denver Gingerich,
** Copyright (C) 2013-2014, 2020 Bradley M. Kuhn,
** Copyright (C) 2016, 2020 Brett Smith.
** License: GPLv3-or-later
** Find a copy of GPL at https://sfconservancy.org/GPLv3
*/
"use strict";
var flipClass = function(elem, byeClass, hiClass) {
var classList = elem.classList;
classList.remove(byeClass);
classList.add(hiClass);
}
var buildAmountData = function(amountInput) {
var amountData = {
minAmount: parseFloat(amountInput.min),
newAmount: parseFloat(amountInput.value),
}
if (amountInput.dataset.oldAmount !== undefined) {
amountData.oldAmount = parseFloat(amountInput.dataset.oldAmount);
}
return amountData;
}
/* We've sometimes published links that say #renew instead of #renewal.
Rewrite that to work as intended. */
if (window.location.hash === "#renew") {
window.location.hash = "#renewal";
}
var formCorrectionNeeded = qs('#form-correction-needed');
function new_amount(amountData, amountInput, amountError) {
var isValid = amountData.newAmount >= amountData.minAmount;
if (amountData.oldAmount === undefined) {
if (isValid) {
hide(amountError);
} else {
flipClass(amountInput, 'valid', 'invalid');
show(amountError);
}
} else if (isValid) {
flipClass(amountInput, 'invalid', 'valid');
hide(amountError);
} else if (amountData.oldAmount >= amountData.minAmount) {
flipClass(amountInput, 'valid', 'invalid');
show(amountError);
}
}
function init_sustainer_form_validation () {
// Forms start in "invalid" form, with the errors shown, so that
// non-Javascript users see the errors by default and know what they must
// enter. Now we hide those for JavaScript users:
formCorrectionNeeded.classList.add('hidden');
qsa('form.supporter-form').forEach(function(form) {
var amountInput = qs('input[type=number]', form);
var amountError = qs('.supporter-form-input .form-error', form);
function amount_change_handler () {
var amountData = buildAmountData(amountInput);
new_amount(amountData, amountInput, amountError);
amountInput.dataset.oldAmount = amountData.newAmount;
}
amountInput.addEventListener('input', function() {
amountInput.classList.remove('invalid');
})
amountInput.addEventListener('focusout', amount_change_handler);
amount_change_handler();
form.addEventListener('submit', function(event) {
var amountData = buildAmountData(amountInput);
if (amountData.newAmount >= amountData.minAmount) {
formCorrectionNeeded.classList.add('hidden');
} else {
formCorrectionNeeded.classList.remove('hidden')
.css("font-weight", "bold").css("font-size", "150%");
event.preventDefault();
}
});
});
}
function init_sustainer_type_switching () {
function selectSupportType(selectedLink) {
qsa(".supporter-type-selector a").forEach(function(el) {
el.classList.remove("supporter-type-selector-selected");
});
selectedLink.classList.add("supporter-type-selector-selected");
qsa(".supporter-type-selection").forEach(function(el) { hide(el); });
let hash = window.location.hash !== '' ? window.location.hash : '#annual';
show(qs(hash));
formCorrectionNeeded.classList.add('hidden');
return false;
};
qsa(".supporter-type-selector a").forEach(function(el) {
el.addEventListener("click", () => selectSupportType(el));
});
let el = qs(window.location.hash !== '' ? window.location.hash + 'Selector' : '#annualSelector');
selectSupportType(el);
window.addEventListener("hashchange", function () {
let el = qs(window.location.hash !== '' ? window.location.hash + 'Selector' : '#annualSelector');
selectSupportType(el);
});
};
function init_expanders () {
// To avoid hitting visitors with a wall of text, we initially hide the
// "Year in Review" and similar text inside expandable <details>
// sections. If the URL fragment references one of these sections, we open
// that section.
let details = qs('details' + window.location.hash) // eg. #WritingAndSpeaking
if (window.location.hash && details) {
details.open = true;
details.scrollIntoView();
}
// Exable convenient "expand all" link to expand/hide all sections at once.
qsa('.expander').forEach(function(expander) {
expander.innerHTML = expander.dataset['expandLinkText'];
expander.addEventListener('click', function() {
let details_elements = qsa('.expandable-section details');
let some_closed = Array.from(details_elements).some(el => !el.open);
details_elements.forEach(function(el) {
el.open = some_closed;
});
});
});
}
init_sustainer_form_validation();
init_sustainer_type_switching();
init_expanders();