");vwo_$('head').append(_vwo_sel);return vwo_$('head')[0] && vwo_$('head')[0].lastChild;})("HEAD")}}, R_940895_48_1_2_0:{ fn:function(log,nonce=''){return (function(x) {
if(!vwo_$.fn.vwoRevertHtml){
return;
};
var ctx=vwo_$(x),el;
/*vwo_debug log("Revert","content",""); vwo_debug*/;
el=vwo_$('[vwo-element-id="1742919897117"]');
el.revertContentOp().remove();})("HEAD")}}, C_940895_61_1_2_0:{ fn:function(log,nonce=''){return (function(x) {var el,ctx=vwo_$(x);
/*vwo_debug log("editElement","#tfa_75-L > b:nth-of-type(1)"); vwo_debug*/(el=vwo_$("#tfa_75-L > b:nth-of-type(1)")).html("1. How frequently do you listen to Minnesota Public Radio?");})("#tfa_75-L > b:nth-of-type(1)")}}, R_940895_61_1_2_0:{ fn:function(log,nonce=''){return (function(x) {
if(!vwo_$.fn.vwoRevertHtml){
return;
};
var el,ctx=vwo_$(x);
/*vwo_debug log("Revert","editElement","#tfa_75-L > b:nth-of-type(1)"); vwo_debug*/(el=vwo_$("#tfa_75-L > b:nth-of-type(1)")).vwoRevertHtml();})("#tfa_75-L > b:nth-of-type(1)")}}, C_940895_61_1_2_1:{ fn:function(log,nonce=''){return (function(x) {var el,ctx=vwo_$(x);
/*vwo_debug log("editElement","#tfa_87-L > b:nth-of-type(1)"); vwo_debug*/(el=vwo_$("#tfa_87-L > b:nth-of-type(1)")).html("2. Which MPR programs or segments do you listen to most often?");})("#tfa_87-L > b:nth-of-type(1)")}}, C_940895_62_1_2_0:{ fn:function(log,nonce=''){return (function(x) {var el,ctx=vwo_$(x);
/*vwo_debug log("visibility","H1:tm('Support The Splendid Table Today')"); vwo_debug*/(el=vwo_$("H1:tm('Support The Splendid Table Today')")).vwoCss({visibility:"hidden !important"}),(el=vwo_$("H1:tm('Support The Splendid Table Today')")).vwoCss({display:"none !important"});})("H1:tm('Support The Splendid Table Today')")}}, R_940895_62_1_2_0:{ fn:function(log,nonce=''){return (function(x) {
if(!vwo_$.fn.vwoRevertHtml){
return;
};
var el,ctx=vwo_$(x);
/*vwo_debug log("Revert","remove","H1:tm('Support The Splendid Table Today')"); vwo_debug*/(el=vwo_$("H1:tm('Support The Splendid Table Today')")).vwoRevertCss(),(el=vwo_$("H1:tm('Support The Splendid Table Today')")).vwoRevertCss();})("H1:tm('Support The Splendid Table Today')")}}, C_940895_62_1_2_1:{ fn:function(log,nonce=''){return (function(x) {var el,ctx=vwo_$(x);
/*vwo_debug log("editElement","STRONG:tm('Success! You’re subscribed!')"); vwo_debug*/(el=vwo_$("STRONG:tm('Success! You’re subscribed!')")).vwoCss({"font-size":"22px !important"}),(el=vwo_$("STRONG:tm('Success! You’re subscribed!')")).vwoCss({"font-size":"24px !important"});})("STRONG:tm('Success! You’re subscribed!')")}}, R_940895_62_1_2_1:{ fn:function(log,nonce=''){return (function(x) {
if(!vwo_$.fn.vwoRevertHtml){
return;
};
var el,ctx=vwo_$(x);
/*vwo_debug log("Revert","editElement","STRONG:tm('Success! You’re subscribed!')"); vwo_debug*/(el=vwo_$("STRONG:tm('Success! You’re subscribed!')")).vwoRevertCss(),(el=vwo_$("STRONG:tm('Success! You’re subscribed!')")).vwoRevertCss();})("STRONG:tm('Success! You’re subscribed!')")}}, C_940895_62_1_3_0:{ fn:function(log,nonce=''){return (function(x) {var el,ctx=vwo_$(x);
/*vwo_debug log("visibility","H1:tm('Support The Splendid Table Today')"); vwo_debug*/(el=vwo_$("H1:tm('Support The Splendid Table Today')")).vwoCss({visibility:"hidden !important"}),(el=vwo_$("H1:tm('Support The Splendid Table Today')")).vwoCss({display:"none !important"});})("H1:tm('Support The Splendid Table Today')")}}, C_940895_61_1_2_4:{ fn:function(log,nonce=''){return (function(x) {var el,ctx=vwo_$(x);
/*vwo_debug log("editElement","#tfa_102-L > b:nth-of-type(1)"); vwo_debug*/(el=vwo_$("#tfa_102-L > b:nth-of-type(1)")).html("5. Which topics or issues are you most interested in hearing about on MPR?");})("#tfa_102-L > b:nth-of-type(1)")}}, R_940895_61_1_2_4:{ fn:function(log,nonce=''){return (function(x) {
if(!vwo_$.fn.vwoRevertHtml){
return;
};
var el,ctx=vwo_$(x);
/*vwo_debug log("Revert","editElement","#tfa_102-L > b:nth-of-type(1)"); vwo_debug*/(el=vwo_$("#tfa_102-L > b:nth-of-type(1)")).vwoRevertHtml();})("#tfa_102-L > b:nth-of-type(1)")}}, C_940895_61_1_2_5:{ fn:function(log,nonce=''){return (function(x) {var el,ctx=vwo_$(x);
/*vwo_debug log("editElement","#tfa_112-L > b:nth-of-type(1)"); vwo_debug*/(el=vwo_$("#tfa_112-L > b:nth-of-type(1)")).html("6. How likely are you to recommend MPR to a friend or family member?");})("#tfa_112-L > b:nth-of-type(1)")}}, R_940895_61_1_2_5:{ fn:function(log,nonce=''){return (function(x) {
if(!vwo_$.fn.vwoRevertHtml){
return;
};
var el,ctx=vwo_$(x);
/*vwo_debug log("Revert","editElement","#tfa_112-L > b:nth-of-type(1)"); vwo_debug*/(el=vwo_$("#tfa_112-L > b:nth-of-type(1)")).vwoRevertHtml();})("#tfa_112-L > b:nth-of-type(1)")}}, C_940895_61_1_2_6:{ fn:function(log,nonce=''){return (function(x) {var el,ctx=vwo_$(x);
/*vwo_debug log("editElement","#tfa_118-L > b:nth-of-type(1)"); vwo_debug*/(el=vwo_$("#tfa_118-L > b:nth-of-type(1)")).html("7. What is your overall impression of the quality of MPR's programs and offering?");})("#tfa_118-L > b:nth-of-type(1)")}}, R_940895_61_1_2_6:{ fn:function(log,nonce=''){return (function(x) {
if(!vwo_$.fn.vwoRevertHtml){
return;
};
var el,ctx=vwo_$(x);
/*vwo_debug log("Revert","editElement","#tfa_118-L > b:nth-of-type(1)"); vwo_debug*/(el=vwo_$("#tfa_118-L > b:nth-of-type(1)")).vwoRevertHtml();})("#tfa_118-L > b:nth-of-type(1)")}}, C_940895_61_1_2_7:{ fn:function(log,nonce=''){return (function(x) {var el,ctx=vwo_$(x);
/*vwo_debug log("editElement","#tfa_124-L > b:nth-of-type(1)"); vwo_debug*/(el=vwo_$("#tfa_124-L > b:nth-of-type(1)")).html("8. How important is MPR to your ability to stay informed?");})("#tfa_124-L > b:nth-of-type(1)")}}, R_940895_61_1_2_7:{ fn:function(log,nonce=''){return (function(x) {
if(!vwo_$.fn.vwoRevertHtml){
return;
};
var el,ctx=vwo_$(x);
/*vwo_debug log("Revert","editElement","#tfa_124-L > b:nth-of-type(1)"); vwo_debug*/(el=vwo_$("#tfa_124-L > b:nth-of-type(1)")).vwoRevertHtml();})("#tfa_124-L > b:nth-of-type(1)")}}, C_940895_61_1_2_8:{ fn:function(log,nonce=''){return (function(x) {var el,ctx=vwo_$(x);
/*vwo_debug log("editElement","#tfa_130-L > b:nth-of-type(1)"); vwo_debug*/(el=vwo_$("#tfa_130-L > b:nth-of-type(1)")).html("9. Do you believe that MPR is an important community resource?");})("#tfa_130-L > b:nth-of-type(1)")}}, R_940895_61_1_2_8:{ fn:function(log,nonce=''){return (function(x) {
if(!vwo_$.fn.vwoRevertHtml){
return;
};
var el,ctx=vwo_$(x);
/*vwo_debug log("Revert","editElement","#tfa_130-L > b:nth-of-type(1)"); vwo_debug*/(el=vwo_$("#tfa_130-L > b:nth-of-type(1)")).vwoRevertHtml();})("#tfa_130-L > b:nth-of-type(1)")}}, C_940895_61_1_2_9:{ fn:function(log,nonce=''){return (function(x) {var el,ctx=vwo_$(x);
/*vwo_debug log("editElement","#tfa_134-L > b:nth-of-type(1)"); vwo_debug*/(el=vwo_$("#tfa_134-L > b:nth-of-type(1)")).html("10. In your own words, why would an MPR listener choose to become a donor?");})("#tfa_134-L > b:nth-of-type(1)")}}, R_940895_61_1_2_9:{ fn:function(log,nonce=''){return (function(x) {
if(!vwo_$.fn.vwoRevertHtml){
return;
};
var el,ctx=vwo_$(x);
/*vwo_debug log("Revert","editElement","#tfa_134-L > b:nth-of-type(1)"); vwo_debug*/(el=vwo_$("#tfa_134-L > b:nth-of-type(1)")).vwoRevertHtml();})("#tfa_134-L > b:nth-of-type(1)")}}, R_940895_48_1_2_3:{ fn:function(log,nonce=''){return (function(x) {
if(!vwo_$.fn.vwoRevertHtml){
return;
};
var el,ctx=vwo_$(x);
/*vwo_debug log("Revert","content",".stylingblock-content-margin-cell > table:nth-of-type(1) > tbody:nth-of-type(1) > tr:nth-of-type(1) > td:nth-of-type(1) > div:nth-of-type(1) > div:nth-of-type(1) > div:nth-of-type(1)"); vwo_debug*/(el=vwo_$(".stylingblock-content-margin-cell > table:nth-of-type(1) > tbody:nth-of-type(1) > tr:nth-of-type(1) > td:nth-of-type(1) > div:nth-of-type(1) > div:nth-of-type(1) > div:nth-of-type(1)")).revertContentOp(),el=vwo_$(".stylingblock-content-margin-cell > table:nth-of-type(1) > tbody:nth-of-type(1) > tr:nth-of-type(1) > td:nth-of-type(1) > div:nth-of-type(1) > div:nth-of-type(1) > div:nth-of-type(1)");})(".stylingblock-content-margin-cell > table:nth-of-type(1) > tbody:nth-of-type(1) > tr:nth-of-type(1) > td:nth-of-type(1) > div:nth-of-type(1) > div:nth-of-type(1) > div:nth-of-type(1)")}}, C_940895_64_1_2_0:{ fn:function(log,nonce=''){return (function(x) {var el,ctx=vwo_$(x);
/*vwo_debug log("content","#tfa_134-L > b:nth-of-type(1)"); vwo_debug*/el=vwo_$("#tfa_134-L > b:nth-of-type(1)"),vwo_$("#tfa_134-L > b:nth-of-type(1)").each((function(){this.__vwoControlOuterHTML=this.__vwoControlOuterHTML||this.outerHTML,vwo_$(this).vwoAttr("class",""),!vwo_$(this).find('[vwo-op-1742933835357-1=""]').length&&vwo_$(this).append('(Optional)'),vwo_$(this).nonEmptyContents().eq(0).replaceWith2(document.createTextNode("In your own words, why would an Marketplace listener choose to become an donor? "))})),el=vwo_$("#tfa_134-L > b:nth-of-type(1)");})("#tfa_134-L > b:nth-of-type(1)")}}, R_940895_64_1_2_0:{ fn:function(log,nonce=''){return (function(x) {
if(!vwo_$.fn.vwoRevertHtml){
return;
};
var el,ctx=vwo_$(x);
/*vwo_debug log("Revert","content","#tfa_134-L > b:nth-of-type(1)"); vwo_debug*/(el=vwo_$("#tfa_134-L > b:nth-of-type(1)")).revertContentOp(),el=vwo_$("#tfa_134-L > b:nth-of-type(1)");})("#tfa_134-L > b:nth-of-type(1)")}}, C_940895_48_1_2_3:{ fn:function(log,nonce=''){return (function(x) {var el,ctx=vwo_$(x);
/*vwo_debug log("content",".stylingblock-content-margin-cell > table:nth-of-type(1) > tbody:nth-of-type(1) > tr:nth-of-type(1) > td:nth-of-type(1) > div:nth-of-type(1) > div:nth-of-type(1) > div:nth-of-type(1)"); vwo_debug*/(el=vwo_$(".stylingblock-content-margin-cell > table:nth-of-type(1) > tbody:nth-of-type(1) > tr:nth-of-type(1) > td:nth-of-type(1) > div:nth-of-type(1) > div:nth-of-type(1) > div:nth-of-type(1)")).replaceWith2("
You'll gain real-world insights into how economics impacts your daily life with this easy-to-follow online course. This crash course is based on the acclaimed textbook Economy, Society, and Public Policy by CORE Econ, tailored to help you grasp key concepts without feeling overwhelmed.
Whether you're new to economics or just want to deepen your understanding, this course covers the basics and connects them to today’s pressing issues—from inequality to public policy decisions.
Each week, you'll receive a reading guide that distills core principles, offers actionable takeaways, and explains how they affect the current world. While the full ebook enriches the experience, the guides alone provide a comprehensive understanding of fundamental economic ideas.
You’ll find this course especially useful and unique because…
It allows you to understand economics in action: Real-life examples and analysis of current events that show you economics at work.
There’s no prior knowledge required: Complex ideas are broken into simple, relatable explanations.
You can be flexible with your learning according to your lifestyle: Go at your own pace, with weekly guides that fit your schedule.
Are you ready to build a foundation in economics that empowers you to think critically about the world around you?
Get instant access today and keep an eye on your inbox for a confirmation email and your first lesson.
"),el=vwo_$(".stylingblock-content-margin-cell > table:nth-of-type(1) > tbody:nth-of-type(1) > tr:nth-of-type(1) > td:nth-of-type(1) > div:nth-of-type(1) > div:nth-of-type(1) > div:nth-of-type(1)");})(".stylingblock-content-margin-cell > table:nth-of-type(1) > tbody:nth-of-type(1) > tr:nth-of-type(1) > td:nth-of-type(1) > div:nth-of-type(1) > div:nth-of-type(1) > div:nth-of-type(1)")}}, R_940895_48_1_2_2:{ fn:function(log,nonce=''){return (function(x) {
if(!vwo_$.fn.vwoRevertHtml){
return;
};
var el,ctx=vwo_$(x);
/*vwo_debug log("Revert","content","[vwo-element-id='1742482566780']"); vwo_debug*/(el=vwo_$("[vwo-element-id='1742482566780']")).revertContentOp(),el=vwo_$("[vwo-element-id='1742482566780']");})("[vwo-element-id='1742482566780']")}}, C_940895_48_1_2_2:{ fn:function(log,nonce=''){return (function(x) {var el,ctx=vwo_$(x);
/*vwo_debug log("content","[vwo-element-id='1742482566780']"); vwo_debug*/(el=vwo_$("[vwo-element-id='1742482566780']")).replaceWith2("You'll gain real-world insights into how economics impacts your daily life with this easy-to-follow online course. This crash course is based on the acclaimed textbook Economy, Society, and Public Policy by CORE Econ, tailored to help you grasp key concepts without feeling overwhelmed.
Whether you're new to economics or just want to deepen your understanding, this course covers the basics and connects them to today’s pressing issues—from inequality to public policy decisions.
Each week, you'll receive a reading guide that distills core principles, offers actionable takeaways, and explains how they affect the current world. While the full ebook enriches the experience, the guides alone provide a comprehensive understanding of fundamental economic ideas.
By submitting, you consent to receive information about MPR\'s programs and offerings. You may opt-out at any time clicking the unsubscribe link at the bottom of any email communication. View our Privacy Policy.
Before you go, would you consider becoming a sustainer to MPR News?
`),
bodySectionHTML: (`
Your monthly gift supports trusted journalism, music discovery, and community
conversation for all – no matter where you live or how you listen. From the
broadcast to the podcast, on-air and online, gifts from individuals power everything
you find at Minnesota Public Radio.
Would you consider becoming a sustainer by converting your one-time gift to a
monthly gift today?
`),
min: 100, // do not show if original gift is below this amount
max: 500, // do not show if original gift is above this amount
askAmount: (originalAmount) => {
// the input is the original amount
// the output is the ask amount, or false if the input does not map to an ask amount
if (originalAmount > 500.00) // $500+
return false; // don't show
if (originalAmount >= 400.00) // $400-$500
return 50.00;
if (originalAmount >= 300.00) // $300-$399
return 40.00;
if (originalAmount >= 200.00) // $200-$299
return 30.00;
if (originalAmount >= 100.00) // $100-$199
return 15.00;
if (originalAmount < 100.00) // $100-
return 10.00;
return false;
},
};
//
//
//
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
//
//
//
window.NA.DonationForm.init({ makeTabbed: false }).then(async (donationFormApi) => {
//console.log("DonationForm:", donationFormApi);
console.log("Donation Form: %c READY %c", 'background-color: MediumSeaGreen; color: white; font-weight: bold;', 'background-color: unset; color: unset; font-weight: unset;');
console.log(donationFormApi);
const interrupter = await donationFormApi.DonationInterrupter.init({
min: DONATION_INTERRUPTER_OPTIONS.min,
max: DONATION_INTERRUPTER_OPTIONS.max,
askAmount: DONATION_INTERRUPTER_OPTIONS.askAmount,
popupHTML: {
headingHTML: DONATION_INTERRUPTER_OPTIONS.headingSectionHTML,
bodyHTML: DONATION_INTERRUPTER_OPTIONS.bodySectionHTML,
},
});
//console.log("DonationInterrupter", interrupter);
console.log("Donation Interrupter: %c READY %c", 'background-color: MediumSeaGreen; color: white; font-weight: bold;', 'background-color: unset; color: unset; font-weight: unset;');
console.log(interrupter);
//interrupter.show(); // debug: always show popup immediately when page loads
}).catch((error) => { console.log("Donation Interrupter: %c FAILED %c An error occured when initializing the API:", 'background-color: Tomato; color: white; font-weight: bold;', 'background-color: unset; color: Tomato; font-weight: unset;'), console.error(error) });
}catch(e) {console.error(e)}
return vwo_$('head')[0] && vwo_$('head')[0].lastChild;})("head")}}, R_940895_39_1_2_0:{ fn:function(log,nonce=''){return (function(x) {
try{
var ctx=vwo_$(x),el;
/*vwo_debug log("Revert","content",""); vwo_debug*/;
el=vwo_$('[vwo-element-id="1740425171461"]');
el.revertContentOp().remove();
} catch(e) {console.error(e)}
try{
var el,ctx=vwo_$(x);
/*vwo_debug log("Revert","addElement","body"); vwo_debug*/(el=vwo_$('[vwo-element-id="1740425171462"]')).remove();
} catch(e) {console.error(e)}
return vwo_$('head')[0] && vwo_$('head')[0].lastChild;})("head")}}, C_940895_39_1_2_0:{ fn:function(log,nonce=''){return (function(x) {
try{
var _vwo_sel = vwo_$("`);
!vwo_$("head").find('#1740425171461').length && vwo_$('head').append(_vwo_sel);}catch(e) {console.error(e)}
try{}catch(e) {console.error(e)}
try{const getCurrentDate = (d = new Date()) => d.toISOString().split('T')[0];
function vwoCustomEvent (labelValue) {
window.VWO = window.VWO || [];
VWO.event = VWO.event || function () {VWO.push(["event"].concat([].slice.call(arguments)))};
VWO.event("customEvent", { "label": labelValue.toString() });
}
class RadioButtonComponent {
constructor (element) {
this.radio = element.querySelector('input[type="radio"]');
this.label = element.querySelector('label');
}
get value () {
let value = this.radio.value;
if (Number.isNaN(parseFloat(value)))
return value;
if (parseFloat(value) % 1 == 0)
return parseInt(value);
return parseFloat(value);
}
set value (newValue) {
this.radio.value = newValue;
}
get text () {
return this.label.textContent;
}
set text (newText) {
if (this.label.querySelector('.form-required')) {
const labelTextNode = [...this.label.childNodes].filter(({ nodeType }) => nodeType === Node.TEXT_NODE)[0];
labelTextNode.nodeValue = newText;
} else {
this.label.textContent = newText;
}
}
get checked () {
return this.radio.checked;
}
set checked (bool) {
this.click(),
bool === true && this.radio.checked === true;
}
click () {
this.label.click();
}
select () {
this.click();
}
addEventListener (eventType, callbackFunction) {
switch (eventType) {
case 'click':
this.label.addEventListener(eventType, callbackFunction);
case 'change':
default:
this.radio.addEventListener(eventType, callbackFunction);
}
}
}
class TextFieldComponent {
constructor (element) {
this.input = element.querySelector('input[type="text"]');
this.label = element.querySelector('label');
}
get value () {
return this.input.value;
}
set value (newValue) {
this.input.dispatchEvent(new Event('focus'));
this.input.value = newValue;
this.input.dispatchEvent(new Event('keyup'));
this.input.dispatchEvent(new Event('change'));
this.input.dispatchEvent(new Event('blur'));
}
get text () {
return this.input.placeholder;
}
set text (newText) {
this.input.placeholder = newText;
}
addEventListener (eventType, callbackFunction) {
this.input.addEventListener(eventType, callbackFunction);
}
}
class GiftArrayButton extends RadioButtonComponent {
constructor (element) {
super(element);
}
get amount () {
return this.value;
}
set amount (newAmount) {
if (Number.isNaN(parseInt(newAmount)) || parseInt(newAmount) <= 0)
throw new Error("New amount must be a valid number greater than 0.");
newAmount = parseInt(newAmount);
this.text = '$' + newAmount;
this.value = newAmount;
}
}
class GiftArrayOtherAmount extends TextFieldComponent {
constructor (element) {
super(element);
}
get amount () {
return parseFloat(this.value);
}
set amount (newAmount) {
if (Number.isNaN(parseInt(newAmount)) || parseInt(newAmount) <= 0)
throw new Error("New amount must be a valid number greater than 0.");
newAmount = parseFloat(newAmount);
this.value = newAmount;
this.input.dispatchEvent(new Event('updateSummary'));
}
}
class GiftArray extends Array {
constructor (items) {
if (!Array.isArray(items) && items.length === 0) {
throw new Error("GiftArray: Arugment 1 is not an instance of Array with a length greater than 0:" + items.join(', '));
}
if (items.every((item) => item instanceof GiftArrayButton || item instanceof GiftArrayOtherAmount)) {
if (items.find((item) => item instanceof GiftArrayOtherAmount)) {
let temp = items.find((item) => item instanceof GiftArrayOtherAmount);
items = items.filter((item) => item instanceof GiftArrayButton);
items.push(temp);
}
} else if (items.every((item) => item instanceof HTMLElement)) {
items = items.map((item) => item.matches(".webform-component-textfield") ? new GiftArrayOtherAmount(item) : new GiftArrayButton(item));
} else {
throw new Error("GiftArray: Arugment 1 is not of type HTMLElement, HTMLElement[], or GiftArrayButton|GiftArrayButton[]:" + items.join(', '));
}
super(...items);
this.Buttons = items.filter((item) => item instanceof GiftArrayButton);
this.OtherAmountInput = items.find((item) => item instanceof GiftArrayOtherAmount);
}
get amount () {
const activeButton = this.Buttons.find((item) => item.checked);
if (activeButton.value === "other") {
const otherButton = activeButton;
if (!otherButton) {
throw new Error("GiftArray.amount: Other Button was not defined.");
}
otherButton.click();
return this.OtherAmountInput.value;
} else {
return activeButton.value;
}
}
set amount (newAmount) {
if (Number.isNaN(parseInt(newAmount)) || parseInt(newAmount) <= 0)
throw new Error("New amount must be a valid number greater than 0.");
newAmount = parseFloat(newAmount);
const matchingButton = this.find((item) => item.value === newAmount);
if (matchingButton) {
matchingButton.click();
} else {
const otherButton = this.Buttons.find((item) => item.value === "other");
otherButton.click();
this.OtherAmountInput.amount = newAmount;
}
}
addEventListeners (eventType, callbackFunction, filter = undefined) {
if (filter && typeof filter === 'function') {
const filteredItems = this.filter((item) => filter.call(this, item));
filteredItems.forEach((item) => item.addEventListener(eventType, callbackFunction));
} else if (filter && typeof filter === 'string') {
if (filter.match(/buttons/gmi))
this.Buttons.forEach((item) => item.addEventListener(eventType, callbackFunction));
if (filter.match(/other/gmi))
this.OtherAmountInput.addEventListener(eventType, callbackFunction);
} else {
this.forEach((item) => item.addEventListener(eventType, callbackFunction));
}
}
}
class FrequencyButton extends RadioButtonComponent {
constructor (element) {
super(element);
}
get frequency () {
return this.text.match(/Monthly/gmi) ? "Monthly" : "One-Time";
}
set freqency (newAmount) {
if (Number.isNaN(parseInt(newAmount)) || parseInt(newAmount) <= 0)
throw new Error("New amount must be a valid number greater than 0.");
newAmount = parseInt(newAmount);
this.text = '$' + newAmount;
this.value = newAmount;
}
}
class FrequencyArray extends Array {
constructor (items) {
if (!Array.isArray(items) && items.length === 0) {
throw new Error("FrequencyArray: Arugment 1 is not an instance of Array with a length greater than 0:" + items.join(', '));
}
/*if (items.every((item) => item instanceof GiftArrayButton || item instanceof GiftArrayOtherAmount)) {
if (items.find((item) => item instanceof GiftArrayOtherAmount)) {
let temp = items.find((item) => item instanceof GiftArrayOtherAmount);
items = items.filter((item) => item instanceof GiftArrayButton);
items.push(temp);
}
} else*/ if (items.every((item) => item instanceof HTMLElement)) {
items = items.map((item) => item.matches(".webform-component-textfield") ? new GiftArrayOtherAmount(item) : new GiftArrayButton(item));
} else {
throw new Error("FrequencyArray: Arugment 1 is not of type HTMLElement or HTMLElement[]:" + items.join(', '));
}
super(...items);
this.Buttons = items.filter((item) => item instanceof GiftArrayButton);
}
get frequency () {
const activeButton = this.Buttons.find((item) => item.checked);
if (activeButton.value === "recurs")
return "monthly";
if (activeButton.value === "NO_RECURR")
return "one-time";
return activeButton.value;
}
set frequency (newFrequency) {
const reNewFrequencyValue = new RegExp(newFrequency, 'gmi');
const matchingButton = this.find((item) => item.value.match(reNewFrequencyValue) || item.text.match(reNewFrequencyValue));
matchingButton.click();
}
get recurring () {
return this.frequency === "monthly" ? true : false;
}
set recurring (bool) {
this.frequency = bool === true ? "monthly" : "one-time";
}
addEventListeners (eventType, callbackFunction, filter = undefined) {
if (filter && typeof filter === 'function') {
const filteredItems = this.filter((item) => filter.call(this, item));
filteredItems.forEach((item) => item.addEventListener(eventType, callbackFunction));
} else if (filter && typeof filter === 'string') {
if (filter.match(/buttons/gmi))
this.Buttons.forEach((item) => item.addEventListener(eventType, callbackFunction));
if (filter.match(/other/gmi))
this.OtherAmountInput.addEventListener(eventType, callbackFunction);
} else {
this.forEach((item) => item.addEventListener(eventType, callbackFunction));
}
}
}
//
const lockedProperty = { writable: false, configurable: false, enumerable: true };
function DonationFormAPI (elements, options = {}) {
const defaultOptions = {
min: 1.00,
max: 999999.99,
makeTabbed: false,
fakeSubmit: true,
overrideGiftArrayValues: false,
};
options = { ...defaultOptions, ...options };
//
const { frequencyRadios, submitButton, root } = elements;
const [ amountRadiosOnetime, amountRadiosMonthly ] = elements.amountRadios;
const oneTimeOtherAmountWrapper = amountRadiosOnetime.find((div) => !div.matches('.webform-component-textfield') || div.querySelector('input[type="text"]'));
const oneTimeRadioButtons = amountRadiosOnetime.filter((div) => div !== oneTimeOtherAmountWrapper);
const monthlyOtherAmountWrapper = amountRadiosMonthly.find((div) => !div.matches('.webform-component-textfield') || div.querySelector('input[type="text"]'));
const monthlyRadioButtons = amountRadiosMonthly.filter((div) => div !== monthlyOtherAmountWrapper);
const debug = {
log: (...args) => window.NA.DonationForm.DEBUG_MODE && console.log(...args),
info: (...args) => window.NA.DonationForm.DEBUG_MODE && console.log(...args),
warn: (...args) => window.NA.DonationForm.DEBUG_MODE && console.log(...args),
error: (...args) => window.NA.DonationForm.DEBUG_MODE && console.log(...args),
};
//
const api = new Object();
Object.defineProperty(api, 'root', {
value: root,
writable: false,
configurable: true,
enumerable: true,
});
Object.defineProperties(api, {
'FORM_MINIMUM': {
value: options.min || 0,
...lockedProperty
},
'FORM_MAXIMUM': {
value: options.max || Infinity,
...lockedProperty
},
});
Object.defineProperties(api, {
GiftArrays: {
value: {
"one-time": new GiftArray([ ...oneTimeRadioButtons, oneTimeOtherAmountWrapper ]),
"monthly": new GiftArray([ ...monthlyRadioButtons, monthlyOtherAmountWrapper ]),
},
writable: false,
configurable: true,
enumerable: true,
},
Frequencies: {
value: new FrequencyArray(frequencyRadios),
writable: false,
configurable: true,
enumerable: true,
},
SubmitButton: {
value: submitButton,
writable: false,
configurable: false,
enumerable: true,
}
});
Object.defineProperties(api, {
'getFrequency': {
value: async function () {
if (!this || this === null) throw new Error("validate: Unable to read API context.");
return new Promise((resolve, reject) => {
try {
resolve(this.Frequencies.frequency);
} catch (error) {
reject(error);
}
});
}, ...lockedProperty
},
'setFrequency': {
value: async function (frequency) {
if (!this || this === null) throw new Error("validate: Unable to read API context.");
return new Promise(async (resolve, reject) => {
try {
this.Frequencies.frequency = frequency;
if (await this.getFrequency() === frequency)
resolve(frequency);
} catch (error) {
reject(error);
}
});
}, ...lockedProperty
},
'getAmount': {
value: async function (frequency = undefined) {
if (!this || this === null) throw new Error("validate: Unable to read API context.");
return new Promise(async (resolve, reject) => {
try {
frequency = frequency || await this.getFrequency();
if (frequency && this.GiftArrays.hasOwnProperty(frequency)) {
const activeGiftArray = this.GiftArrays[frequency];
resolve(activeGiftArray.amount);
} else {
throw new Error("getAmount: Invalid frequency: " + frequency);
}
} catch (error) {
reject(error);
}
});
}, ...lockedProperty
},
'setAmount': {
value: async function (amount, frequency = undefined) {
if (!this || this === null) throw new Error("validate: Unable to read API context.");
return new Promise(async (resolve, reject) => {
try {
const currentFrequency = await this.getFrequency();
if (!frequency) {
frequency = currentFrequency;
} else if (frequency !== currentFrequency) {
frequency = await this.setFrequency(frequency);
}
if (frequency && this.GiftArrays.hasOwnProperty(frequency)) {
const activeGiftArray = this.GiftArrays[frequency];
activeGiftArray.amount = amount;
} else {
throw new Error("setAmount: Invalid frequency: " + frequency);
}
if (await this.getAmount() === amount)
resolve(amount);
} catch (error) {
reject(error);
}
});
}, ...lockedProperty
},
'getRecurring': {
value: async function () {
if (!this || this === null) throw new Error("validate: Unable to read API context.");
return new Promise((resolve, reject) => {
try {
resolve(this.Frequencies.recurring);
} catch (error) {
reject(error);
}
});
}, ...lockedProperty
},
'setRecurring': {
value: async function (bool) {
if (!this || this === null) throw new Error("validate: Unable to read API context.");
return new Promise(async (resolve, reject) => {
try {
this.Frequencies.frequency = bool ? true : false;
if (await this.getRecurring() === bool)
resolve(bool);
} catch (error) {
reject(error);
}
});
}, ...lockedProperty
},
freqency: {
get () { return this.getFrequency() },
set (value) { this.setFrequency(value) },
enumerable: true, configurable: true,
},
amount: {
get () { return this.getAmount() },
set (value) { this.setAmount(value) },
enumerable: true, configurable: true,
},
recurring: {
get () { return this.getRecurring() },
set (value) { this.setRecurring(value) },
enumerable: true, configurable: true,
},
});
Object.defineProperties(api, {
'submit': {
value: async function (condition = this.validate||function(){return true}) {
//this.hooks['onBeforeSubmit'].forEach((callback) => callback.call(this));
let result;
const isAsyncFunction = (func) => func.constructor.name === "AsyncFunction";
if (Array.isArray(condition)) {
if (condition.every((c) => typeof c === 'function' && isAsyncFunction(c))) {
result = await Promise.all(condition.map(async (c) => await c.call(this)));
} else if (condition.every((c) => typeof c === 'function')) {
result = condition.every((c) => c.call(this));
} else if (condition.every((c) => c === true || c === false)) {
result = condition.every((c) => c);
}
} else if (typeof condition === 'function' && isAsyncFunction(condition)) {
result = await condition.call(this);
} else if (typeof condition === 'function') {
result = condition.call(this);
} else if (condition === true || condition === false) {
result = condition;
} else {
console.error("Unknown error.");
debugger;
}
//
if (result === true) {
if (window.NA.DonationForm.hasOwnProperty("DEBUG_MODE") && window.NA.DonationForm["DEBUG_MODE"] == true)
return console.log("Submit aborted (debug mode is enabled).");
this.SubmitButton.click(),
this.hooks['onSubmit'].forEach((callback) => callback.call(this));
//this.hooks['onAfterSubmit'].forEach((callback) => callback.call(this));
} else {
return console.log("Submit failed (conditions did not evaluate to true).");
}
}, ...lockedProperty
},
'interceptSubmit': {
value: function (handleInterceptedSubmit = () => { return new Promise((resolve) => resolve(undefined)) }) {
try {
window.NA.DonationForm.SubmitButtonCopy = window.NA.DonationForm.SubmitButtonCopy || createNewSubmitButton(window.NA.DonationForm.SubmitButton, { cloneOriginal: false, hideOriginal: true, observeOriginal: false });
window.NA.DonationForm.SubmitButtonCopy.addEventListener('click', async (event) => {
event.preventDefault(), event.stopPropagation();
const shouldFormSubmit = await handleInterceptedSubmit.call(this, event);
if (shouldFormSubmit) {
console.info("Submit allowed by initial interceptSubmit callback function resulting in a truthy evaluation.");
const formIsValid = await window.NA.DonationForm.validate();
if (!formIsValid) { // if submit allowed but there are known errors in the form
console.warn("Form has known errors. Attempting to submit to show errors then retrying.");
console.log("Submitting...");
window.NA.DonationForm.submit(true); // submit anyway to trigger the error to be shown
window.NA.DonationForm.SubmitButton.style.setProperty("display", "none"), debug.info("SubmitButton hidden."), // hide the original submit button again
window.NA.DonationForm.SubmitButtonCopy.style.setProperty("display", "none"), debug.info("SubmitButtonCopy hidden."); // hide the copy of the submit button again
window.NA.DonationForm.SubmitButtonCopy.style.removeProperty("display"), debug.info("SubmitButtonCopy unhidden."); // show the copy of the submit button
} else {
console.log("Submitting...");
window.NA.DonationForm.submit(true);
}
} else {
console.log("Submit prevented.");
console.info("Next submit will be allowed.");
window.NA.DonationForm.SubmitButton.style.removeProperty("display"), debug.info("SubmitButton unhidden."); // show the original submit button so that if something goes wrong the user can still click the submit button
window.NA.DonationForm.SubmitButtonCopy.style.setProperty("display", "none"), debug.info("SubmitButtonCopy hidden."); // hide the copy of the submit button that intercepts submit attempts so that there aren't two buttons
}
});
console.log("Submit intercept added.\nButton:", window.NA.DonationForm.SubmitButtonCopy);
} catch (error) {
console.error("Failed to add submit intercept:", error);
}
}, ...lockedProperty
},
'validate': {
value: async function (root = undefined) {
if (!this || this === null)
throw new Error("validate: Unable to read API context.");
root = root || this.root;
const flattenArray = (array) => array.reduce((flat, toFlatten) => flat.concat(Array.isArray(toFlatten) ? flattenArray(toFlatten) : toFlatten), []);
try {
const freqency = await this.getFrequency(),
amount = await this.getAmount();
if (!freqency || !amount)
return false;
if (amount < this.FORM_MINIMUM || amount > this.FORM_MAXIMUM)
return console.error("validate:", "Gift amount is invalid:", amount), false;
let requiredFields = Array.from(root.querySelectorAll('label:has(.form-required)'))
.map((label) => document.getElementById(label.htmlFor) || (label.nextElementSibling || label.previousElementSibling))
.filter((_) => !!_) // remove blanks
.filter((field) => {
if (field.name && field.name.includes('[payment_information]'))
return false;
return true;
})
.map((field) => {
if (field.matches("div"))
return [...field.querySelectorAll('input')];
return field;
})
requiredFields = flattenArray(requiredFields);
const valid = requiredFields.every((input) => {
const type = input.tagName.toLowerCase() === 'select' ? 'select' : input.type;
const { name, value, id } = input;
//console.log(type, name, value);
if (name === 'submitted[payment_information][payment_fields][credit][card_number]') {
if (value && value.length === 16)
return true;
return console.error("validate:", name+':', "CC is invalid."), false;
}
if (name === 'submitted[leadership_circle]')
return true;
if (name === 'submitted[donation][other_amount]' || name === 'submitted[donation][recurring_other_amount]')
if (amount)
return true;
switch (type) {
case 'email':
const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
if (!emailRegex.test(value))
return console.error("validate:", name+':', "Email address is invalid.\n", input, value), false;
return true;
case 'tel':
if (!value || value.length < 10)
return console.error("validate:", name+':', "Phone number is invalid.\n", input, value), false;
return true;
case 'select':
case 'radio':
case 'text':
if (!value || value.length === 0)
return console.error("validate:", name+':', "Field is invalid.\n", input, value), false;
return true;
default:
debug.log("default");
return true;
}
/*if (!value || value.length === 0)
return false;*/
});
return valid;
} catch (error) {
console.error(error);
return false;
}
}, ...lockedProperty
},
//'makeTabbed': { value: function(){} },
'DonationInterrupter': {
value: { init: initDonationInterrupter.bind(api) },
enumerable: true,
configurable: true,
writable: true,
}
});
initHooks(api, ['onFrequencyChange', 'onAmountChange', 'onTrySubmit', 'onSubmit']);
api.Frequencies.addEventListeners('change', (event) => {
if (event.target.checked) {
api.hooks['onFrequencyChange'].forEach((callback) => {
callback.call(api, event.target.value);
});
}
});
Object.entries(api.GiftArrays).forEach(([ key, GiftArray ]) => {
GiftArray.addEventListeners('change', (event) => {
if (event.target.checked) {
api.hooks['onAmountChange'].forEach((callback) => {
callback.call(api, event.target.value);
});
}
});
});
api.SubmitButton.addEventListener('click', (event) => {
api.hooks['onTrySubmit'].forEach((callback) => callback.call(api, event));
});
api.root.addEventListener('submit', (event) => {
api.hooks['onSubmit'].forEach((callback) => callback.call(api, event));
});
if (options.makeTabbed)
api.makeTabbed();
/*if (options.fakeSubmit)
window.NA.DonationForm.SubmitButtonCopy = window.NA.DonationForm.SubmitButtonCopy || createNewSubmitButton(window.NA.DonationForm.SubmitButton, { cloneOriginal: false, hideOriginal: true, observeOriginal: false });*/
return api;
}
function createNewSubmitButton (originalSubmitButton = window.NA.DonationForm.SubmitButton, options = {}) {
const defaultOptions = {
cloneOriginal: true,
hideOriginal: true,
observeOriginal: true,
};
options = { ...defaultOptions, ...options };
const newSubmitButton = document.createElement('button');
//newSubmitButton.id = "submit-button-copy";
newSubmitButton.classList.add("btn");
newSubmitButton.textContent = originalSubmitButton.value;
originalSubmitButton.after(newSubmitButton);
options.hideOriginal && originalSubmitButton.style.setProperty("display", "none");
return newSubmitButton;
}
function initHooks (api, hookNames = []) {
const hooks = Object.fromEntries(hookNames.map((hookName) => ([hookName, new Array()])));
Object.defineProperty(api, 'hooks', {
value: hooks,
...lockedProperty
});
}
function initDonationInterrupter (options = {}) {
const getExpId = () => {
let experiments = window._vwo_exp;
experiments = Object.entries(window._vwo_exp);
let id = experiments.find(([id, data]) => {
const name = data.name;
return name.match(/Donation Interrupter/);
})[1]?.id;
return id;
};
const getExpVariation = (id) => {
let experiment = window._vwo_exp[id];
return experiment.combination_chosen || experiment.combination_selected;
};
const defaultOptions = {
id: [ 'VWO', getExpId(), getExpVariation(getExpId()) ].join('-'),
tokenName: ("NA__MPR_DonationInterrupter:" + [ 'VWO', getExpId(), getExpVariation(getExpId()) ].join('-')),
min: 10,
max: 100,
askAmount: (originalAmount) => {
if (originalAmount > 500) // $500+
return false; // don't show
if (originalAmount >= 400) // $400-$500
return 50;
if (originalAmount >= 300) // $300-$399
return 40;
if (originalAmount >= 200) // $200-$299
return 30;
if (originalAmount >= 100) // $100-$199
return 15;
if (originalAmount < 100) // $100-
return 10;
return false;
},
askFrequency: (originalFrequency) => {
return "monthly";
},
popupHTML: {
headingHTML: (`
Lorem ipsum dolor sit amet
`),
bodyHTML: (`
Consectetur adipiscing elit. Sed nec egestas turpis, hendrerit semper nisl. Pellentesque auctor ipsum at
pharetra eleifend. Pellentesque a rhoncus turpis, ut tempus nibh. Donec vel dui hendrerit nisi imperdiet
tincidunt. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos.
Duis efficitur dolor ut nisl blandit imperdiet. Nullam pretium est nunc, tincidunt viverra ligula dapibus.
Duis malesuada:
dui eu venenatis volutpat
urna libero posuere lectus
non tincidunt mauris ligula consectetur felis
lacinia hendrerit enim at molestie
Sed placerat fringilla consequat. Nullam eu pellentesque sem?
By submitting, you consent that you are at least 18 years of age and to receive information about MPR's or APMG entities' programs and offerings. The personally identifying information you provide will not be sold, shared, or used for purposes other than to communicate with you about MPR, APMG entities, and its sponsors. You may opt-out at any time clicking the unsubscribe link at the bottom of any email communication. View our Privacy Policy.
It was an awful tragedy in Dallas this week when Patti Stevens, 54, took her own life, two weeks after a mentally ill former Texas A&M football player hacked her husband to death with a machete while he was out for an early-morning jog.
She left a note behind with biographical information for a Dallas Morning News reporter, to whom she had talked for a story just a week ago.
“Dave was the love of my life and I’m lost without him,” she said in the interview. “People need to know that this was a wonderful person going out and doing what he loved to do.”
Sharon Grigsby, a Dallas Morning News columnist and deputy editorial page editor, didn't know the couple, who had no children, for the record.
Turn Up Your Support
MPR News helps you turn down the noise and build shared understanding. Turn up your support for this public resource and keep trusted journalism accessible to all.
But she's angry enough by Patti's suicide that she turned in a horrific piece of work that was published this afternoon, shaming Stevens for taking her own life.
"Healthy grieving is the kind of hard work that our society wants to turn tail and run from," she writes. "In its worst manifestations, suicide seems preferable. Especially to younger Americans, who need role models doing the hard, responsible thing."
So many responses other than suicide would be more viable: Like getting help, especially if you have been suffering already from depressive-like symptoms. Like honoring a loved one’s memory by working with and being in fellowship with others who have lost loved ones.
At the end of the day, suicide is a self-centered gesture.
It's a lot to ask of a widow in the immediate aftermath of the murder of a husband. And the "just ask for help" as a simple answer is little more than a simple answer. Lots of people who take their own lives sought help but help didn't work. That often only makes the underlying sense of failure all the more unbearable.
It's hard to see how shaming bolsters the willingness of someone to discuss their thoughts of suicide.
A personal reason why I’m willing to step out and label suicide as incomprehensibly selfish: Because I’ve watched people trudge that harder road. I can’t help thinking about all the brave men and women I’ve known who have somehow, someway moved forward out of their own unspeakable tragedy and loss.
Those people were the role models I held tightly when the unspeakable happened in my own life not so long ago. If you have considered suicide, you know what I’m talking about. If you are considering it right now, hold on to the people with real solutions. Their stories aren’t so cinematic or frothy as curling up on the garage floor to die — but they are so much more courageous and constructive.
Those people are the living proof that suicide is not the answer.
The response to the column took Grigsby up on her assertion.
Said one commenter...
Three months ago I would have agreed with you but once you've lost someone close to you in a senseless tragedy, suicide can seem like the only option to end the unfathomable sorrow and grief. "Suicide is not the answer", sounds good all packaged up into a nice little slogan box that prints perfectly on a bumper sticker or t-shirt, but the reasons for suicide run deep and simply telling someone to get help just doesn't do the trick. We all know it's one thing to put a yellow ribbon sticker on your vehicle that shows your support for troops and quite another to actually send your loved one off to war. Maybe we should stop with the trite slogans and look for more effective ways to help those who are hurting beyond words. We can start by not condemning this poor woman, who, conveniently enough for you, is not here to defend her actions.
"If your point was to encourage others to get help (rather than kill themselves), you failed," writes another. "The tone of your article is harsh and condemning - there is nothing uplifting, positive or encouraging about it. If what you truly want is to encourage those who are heavy-burdened, I encourage you to delete this article and try again."
"If it prevents one suicide, it's worth it," says another.
But more than preventing a suicide, another opinion notes, it helps a stigma to persist that keeps the issue to whispers.
Now that isn't to say you should not try to intervene or help a person with suicidal thoughts or tendencies, that's perfectly fine! As long as when doing so you don't try to guilt the person out of doing so or shaming them for even thinking of doing that to 'all the people that love and care about them'. Try to understand what they are going through, understand that people have different brain chemistry and respond to events/ life in different ways, understand that what you think is a life worth living/endless opportunities might not seem that way to another - everything is subjective. Be compassionate and try to understand rather than judgmental and ignorant.
The reaction to the column has been nearly unanimous in its condemnation of its author, a clear indication that in matters of mental illness and mental health, maybe we actually are making progress.
When it comes to staying informed in Minnesota, our newsletters overdeliver. Sign-up now for headlines, breaking news, hometown stories, weather and much more. Delivered weekday mornings.