Bradley M. Kuhn
2ba369aa5c
The expandable sections can be expanded either one-by-one, or with the “Expand All” button. Add a counter for each expandable section (which requires their div's to have 'id' attributes, lest they be counted in the '__global' section of expandables). The __global counter will work as advertised if you have no 'id' attributes on any of your 'expandable-section'-classed div's, but if you mix a __global without an id with ones that *do* have an id, it's likely this particular code won't work for that. Finally, add some documentation which is probably over-documenting for someone who knows Javascript and jQuery well, but it took me a while to figure out this code so I felt throwing some notes in there might be helpful.
167 lines
6.8 KiB
JavaScript
167 lines
6.8 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
|
|
*/
|
|
|
|
var NEW_AMOUNT_EVENT = 'conservancy:newamount';
|
|
|
|
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;
|
|
}
|
|
|
|
var supportTypeSelector = function(supportTypeHash) {
|
|
return $(supportTypeHash + "Selector");
|
|
};
|
|
|
|
var $window = $(window);
|
|
|
|
$window.load(function() {
|
|
/* 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 $selectorLink = supportTypeSelector(window.location.hash);
|
|
if ($selectorLink.length > 0) {
|
|
$window.scrollTop($selectorLink.offset().top);
|
|
}
|
|
});
|
|
|
|
$(document).ready(function() {
|
|
// 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:
|
|
var $formCorrectionNeeded = $('#form-correction-needed');
|
|
$formCorrectionNeeded.addClass('hidden');
|
|
|
|
$('form.supporter-form').each(function(index, form) {
|
|
var $amountInput = $('input[type=number]', form).first();
|
|
var $amountError = $('.form-error', $amountInput.parents('.supporter-form-input'));
|
|
|
|
$amountError.on(NEW_AMOUNT_EVENT, function(event, amountData) {
|
|
var isValid = amountData.newAmount >= amountData.minAmount;
|
|
if (amountData.oldAmount === undefined) {
|
|
if (isValid) {
|
|
$amountError.addClass('hidden');
|
|
} else {
|
|
flipClass($amountInput[0], 'valid', 'invalid');
|
|
$amountError.removeClass('hidden');
|
|
}
|
|
} else if (isValid) {
|
|
flipClass($amountInput[0], 'invalid', 'valid');
|
|
$amountError.fadeOut();
|
|
} else if (amountData.oldAmount >= amountData.minAmount) {
|
|
flipClass($amountInput[0], 'valid', 'invalid');
|
|
$amountError.fadeIn();
|
|
}
|
|
});
|
|
|
|
$amountInput.on('input', function(event) {
|
|
event.target.classList.remove('invalid');
|
|
}).on('focusout', function(event) {
|
|
var amountInput = event.target;
|
|
var amountData = buildAmountData(amountInput);
|
|
$amountError.trigger(NEW_AMOUNT_EVENT, amountData);
|
|
amountInput.dataset.oldAmount = amountData.newAmount;
|
|
}).trigger('focusout');
|
|
|
|
$(form).on('submit', function(event) {
|
|
var amountData = buildAmountData($amountInput[0]);
|
|
if (amountData.newAmount >= amountData.minAmount) {
|
|
$formCorrectionNeeded.addClass('hidden');
|
|
} else {
|
|
$formCorrectionNeeded.removeClass('hidden')
|
|
.css("font-weight", "bold").css("font-size", "150%");
|
|
event.preventDefault();
|
|
}
|
|
});
|
|
});
|
|
|
|
var selectSupportType = function(event) {
|
|
var $selectedLink = $(event.target);
|
|
$(".supporter-type-selector a").removeClass("supporter-type-selector-selected");
|
|
$selectedLink.addClass("supporter-type-selector-selected");
|
|
$(".supporter-type-selection").hide();
|
|
$(event.target.hash).show();
|
|
$formCorrectionNeeded.addClass('hidden');
|
|
return false;
|
|
};
|
|
$(".supporter-type-selector a").bind("click", selectSupportType);
|
|
|
|
var selectSupportTypeFromHash = function() {
|
|
return supportTypeSelector(window.location.hash).click();
|
|
};
|
|
$window.bind("hashchange", selectSupportTypeFromHash);
|
|
if (selectSupportTypeFromHash().length === 0) {
|
|
supportTypeSelector("#annual").click();
|
|
}
|
|
var want_id = window.location.hash.substr(1) || "do not match any id";
|
|
var $expandable_counts = [];
|
|
// First, build a count of expandable div sections
|
|
$('div.expandable-section').each(function(index, section) {
|
|
var $ourid = $(section).attr('id');
|
|
if ($ourid == undefined) { $ourid = "__global"; }
|
|
$expandable_counts[$ourid] = 0;
|
|
});
|
|
$('div[data-read-more]').each(function(index, readmore) {
|
|
var $readmore = $(readmore)
|
|
var $header = $readmore.prev('h3');
|
|
if ($header.length && $header[0].id === want_id) {
|
|
// Do nothing, leave it alone
|
|
} else {
|
|
var $ourid = $readmore.closest(".expandable-section" ).attr('id');
|
|
if ($ourid == undefined) { $ourid = "__global"; }
|
|
|
|
// Set up the link for this specific section using the text from
|
|
// the data-read-more atrribute on the div specific to this section
|
|
var $linkpara = $('<p><a class="read-more"></a></p>');
|
|
var $readlink = $linkpara.children('a');
|
|
$readlink.append($readmore.data('read-more'));
|
|
$readlink.on('click', function(event) {
|
|
// When clicked, we'll restore the actual text and fade it in
|
|
// quickly, and also see if there are any remaining
|
|
// expandable sections left in this particular expandable
|
|
// section. If none are left, make the "Expand all" button
|
|
// (which lives in an 'a' anchor of the class 'expander') disappear.
|
|
$linkpara.replaceWith($readmore);
|
|
$readmore.fadeIn('fast');
|
|
$expandable_counts[$ourid]--;
|
|
if ($expandable_counts[$ourid] <= 0) {
|
|
$readmore.closest(".expandable-section" )
|
|
.children('a.expander').each(function(index, element){
|
|
$(element).fadeOut('slow');
|
|
})
|
|
}
|
|
});
|
|
$readmore.hide().replaceWith($linkpara);
|
|
$expandable_counts[$ourid]++;
|
|
}
|
|
});
|
|
// Final two each's enable the "Expand All" link.
|
|
$('a[data-expand-link-text]').each(function(index, element) {
|
|
var $element = $(element);
|
|
$element.append($element.data('expand-link-text'));
|
|
});
|
|
$('.expandable-section').each(function(index) {
|
|
var $expandlink = $(this).children('a.expander');
|
|
var $ourexpandablesection = $(this);
|
|
$expandlink.on('click', function(event) {
|
|
$expandlink.fadeOut('slow');
|
|
$ourexpandablesection.find('.read-more').each(function(index) { $(this).click(); }); });
|
|
});
|
|
});
|