1/* 2 Seamless Donations by David Gewirtz, adopted from Allen Snook 3 4 Lab Notes: http://zatzlabs.com/lab-notes/ 5 Plugin Page: http://zatzlabs.com/seamless-donations/ 6 Contact: http://zatzlabs.com/contact-us/ 7 8 Copyright (c) 2015 by David Gewirtz 9 */ 10 11jQuery(document).ready(function () { 12 13 // this is the new option that generates the UUID in the browser 14 // UUID code based on https://github.com/broofa/node-uuid 15 16 jQuery("input[name='_dgx_donate_session_id']").val(function () { 17 var guid = jQuery(this).val(); 18 var ver = 'SDB01-'; // Session ID version: SD=Seamless Donations, B=Browser, 01=first versiom 19 20 if (guid === "browser-uuid") { 21 return ver + uuid.v4().toUpperCase(); 22 } else { 23 return guid; 24 } 25 }); 26 27 // radio button revealer, works with multiple sets per page 28 // each input tag gets either (or both) a data-revealer or data-hide attribute 29 // the contents of that attribute is a class or id (with the . or # as part of the string) 30 // for the purposes of the forms engine, we'll work only with classes. 31 32 jQuery("input:radio").change(function () { 33 var revealTarget = jQuery(this).attr("data-reveal"); 34 var concealTarget = jQuery(this).attr("data-conceal"); 35 var checkTarget = jQuery(this).attr('data-check'); 36 var uncheckTarget = jQuery(this).attr('data-uncheck'); 37 if (revealTarget !== undefined) { 38 console.log("radio button: show " + revealTarget); 39 jQuery(revealTarget).show('fast'); 40 showSelectedOptions(revealTarget); 41 } 42 if (concealTarget !== undefined) { 43 console.log("radio button: hide " + concealTarget); 44 jQuery(concealTarget).hide('fast'); 45 hideSelectedOptions(concealTarget); 46 } 47 if (jQuery(this).is(":checked")) { 48 checkSelectedNamedItems(checkTarget); 49 uncheckSelectedNamedItems(uncheckTarget); 50 } 51 }); 52 53 // checkbox revealer, also works with multiple checkbox and hide/reveal sets per page 54 // this uses only the data-revealer attribute, and reveals if checked and hides if unchecked. 55 56 jQuery("input:checkbox").click(function () { 57 var revealTarget = jQuery(this).attr('data-reveal'); 58 var concealTarget = jQuery(this).attr('data-conceal'); 59 var checkTarget = jQuery(this).attr('data-check'); 60 var uncheckTarget = jQuery(this).attr('data-uncheck'); 61 if (checkTarget !== undefined) { 62 console.log("checkbox checktarget:" + checkTarget); 63 } 64 if (jQuery(this).is(":checked")) { 65 console.log("checkbox click:is-checked (revealTarget:" + revealTarget + ")"); 66 jQuery(revealTarget).show('fast'); 67 showSelectedOptions(revealTarget); 68 checkSelectedNamedItems(checkTarget); 69 uncheckSelectedNamedItems(uncheckTarget); 70 } 71 if (jQuery(this).is(":not(:checked)")) { 72 console.log("checkbox click:not-checked"); 73 //hideSelect(); 74 hideSelectedOptions(concealTarget); 75 jQuery(revealTarget).hide('fast'); 76 } 77 }); 78 79 80 function checkSelectedNamedItems(whatToCheck) { 81 if (whatToCheck !== undefined) { 82 var whatToCheckArray = whatToCheck.split(" "); 83 for (itemToCheckIndex in whatToCheckArray) { 84 var itemToCheck = whatToCheckArray[itemToCheckIndex]; 85 console.log("-- checkSelectedNamedItems (itemToCheck):" + itemToCheck); 86 jQuery("[id=" + itemToCheck + "] input").attr('checked', true); 87 } 88 } 89 } 90 91 function uncheckSelectedNamedItems(whatToCheck) { 92 if (whatToCheck !== undefined) { 93 var whatToCheckArray = whatToCheck.split(" "); 94 for (itemToCheckIndex in whatToCheckArray) { 95 var itemToCheck = whatToCheckArray[itemToCheckIndex]; 96 console.log("-- checkSelectedNamedItems (itemToCheck):" + itemToCheck); 97 jQuery("[id=" + itemToCheck + "] input").attr('checked', false); 98 } 99 } 100 } 101 102 103 jQuery("form").on("change", "select", function () { 104 var nameOfChangedSelect = jQuery(this).attr("name"); 105 console.log("select change (invoked):" + nameOfChangedSelect); 106 jQuery("select[name=" + nameOfChangedSelect + "] option:selected").each(function () { 107 // triggering for everything, not just visible items 108 var parent = jQuery(this).parent("select").attr("name"); 109 console.log("-- option:selected (parent select): " + parent); 110 var reveal = jQuery(this).attr("data-reveal"); 111 console.log("---- option:selected (reveal: " + reveal); 112 var optionKey = jQuery(this).attr("value"); 113 console.log("---- option:selected (optionKey): " + optionKey); 114 var conceal = jQuery(this).parent("select").attr("data-conceal"); 115 console.log("---- option:selected (conceal): " + conceal); 116 117 hideSelectedOptions(conceal); 118 jQuery(reveal).show(); 119 }); 120 }).on("change"); 121 122 // if the select item that matches the cloak becomes visible, make the active option classes visible 123 // we're looking at the class of the select item to see if it matches the what to reveal values 124 function showSelectedOptions(whatToReveal) { 125 // whatToReveal could be a set of classes 126 if (whatToReveal !== undefined) { 127 console.log("showSelectedOptions (" + whatToReveal + ")"); 128 var whatToRevealArray = whatToReveal.split(","); 129 for (itemToCheckIndex in whatToRevealArray) { 130 var itemToReveal = whatToRevealArray[itemToCheckIndex]; 131 console.log("-- showSelectedOptions (itemToReveal):" + itemToReveal); 132 jQuery("select" + itemToReveal + " option:selected").each(function () { 133 var reveal = jQuery(this).attr("data-reveal"); 134 jQuery(reveal).show(); 135 var optionKey = jQuery(this).attr("value"); 136 console.log("-- showSelectedOptions (option key:" + optionKey + "):" + reveal); 137 }); 138 } 139 } 140 } 141 142 function hideSelectedOptions(whatToConceal) { 143 // whatToConceal could be a set of classes 144 console.log("hideSelectedOptions (" + whatToConceal + ")"); 145 if (whatToConceal !== undefined) { 146 var whatToConcealArray = whatToConceal.split(","); 147 for (itemToConcealIndex in whatToConcealArray) { 148 var itemToConceal = whatToConcealArray[itemToConcealIndex].trim(); 149 console.log("-- hideSelectedOptions (itemToConceal):" + itemToConceal); 150 jQuery("select" + itemToConceal + " option:selected").each(function () { 151 var conceal = jQuery(this).attr("data-conceal"); 152 jQuery(conceal).show(); 153 var optionKey = jQuery(this).attr("value"); 154 console.log("-- showSelectedOptions (option key:" + optionKey + "):" + conceal); 155 }); 156 jQuery(itemToConceal).hide(); 157 } 158 } 159 } 160 161 // should be showSelectedOptions? 162 function showSelectedOptionsx(whatToReveal) { 163 // whatToReveal could be a set of classes 164 var whatToRevealArray = whatToReveal.split(","); 165 console.log("showSelectedOptions (" + whatToReveal + ")"); 166 jQuery("select option:selected").each(function () { 167 var reveal = jQuery(this).attr("data-reveal"); 168 if (reveal !== undefined) { 169 var revealArray = reveal.split(","); 170 171 for (itemToCheckIndex in whatToRevealArray) { 172 var itemToReveal = whatToRevealArray[itemToCheckIndex]; 173 console.log("-- showSelectedOptions itemToReveal: " + whatToRevealArray[itemToCheckIndex]); 174 for (classToRevealIndex in revealArray) { 175 var classToReveal = revealArray[classToRevealIndex]; 176 console.log("-- showSelectedOptions classToReveal: " + classToReveal); 177 if (itemToReveal.trim() == classToReveal.trim()) { 178 console.log("---- showSelectedOptions revealing: " + itemToReveal); 179 jQuery(itemToReveal).show(); 180 } 181 } 182 } 183 } 184 }); 185 } 186 187 188 // unhacked version -- hacking new one called showSelectedOptions 189 function showSelect() { 190 console.log("showSelect (invoked)"); 191 jQuery("select option:selected").each(function () { 192 var reveal = jQuery(this).attr("data-reveal"); 193 var optionKey = jQuery(this).attr("value"); 194 console.log("-- showSelect (option key:" + optionKey + "):" + reveal); 195 jQuery(reveal).show(); 196 }); 197 } 198 199 function hideSelect() { 200 jQuery("select option:selected").each(function () { 201 var conceal = jQuery(this).parent("select").attr("data-conceal"); 202 console.log("hideSelect:" + conceal); 203 jQuery(conceal).hide(); 204 }); 205 } 206}); 207 208/** 209 * @return {boolean} 210 */ 211function SeamlessDonationsFormsEngineValidator() { 212 var formOkay = true; 213 214 // first hide the error message data 215 jQuery('.seamless-donations-forms-error-message').hide('fast').text(); 216 jQuery('.seamless-donations-error-message-field').hide('fast'); 217 218 // the approach is to find visible elements with 'validation' and check them 219 jQuery('#seamless-donations-form input:visible').each(function (index) {
220 var validations = jQuery(this).attr('data-validate'); 221 if (validations !== undefined) { 222 // the element has a validation request 223 // the validation request can be one or more validation names, separated by commas 224 var validationArray = validations.split(","); 225 var valDex; 226 for (valDex = 0; valDex < validationArray.length; ++valDex) { 227 var validationTest = validationArray[valDex]; 228 switch (validationTest) { 229 case 'required': 230 if (!SeamlessDonationsValidateRequired(this)) { 231 formOkay = false; 232 } 233 break; 234 case 'currency': 235 if (!SeamlessDonationsValidateCurrency(this)) { 236 formOkay = false; 237 } 238 break; 239 case 'email': 240 if (!SeamlessDonationsValidateEmail(this)) { 241 formOkay = false; 242 } 243 break; 244 } 245 } 246 } 247 }); 248 249 console.log("SeamlessDonationsFormsEngineValidator: before if(!formOkay)"); 250 if (!formOkay) { 251 jQuery('.seamless-donations-forms-error-message').text('Please correct your input.').show('fast'); 252 jQuery('body').scrollTop(0); 253 console.log("-- SeamlessDonationsFormsEngineValidator: form not okay"); 254 return false; // returning false blocks the page loader from executing on submit 255 } else { 256 // the form is okay, so go on to the form submit function, another JavaScript 257 console.log("-- SeamlessDonationsFormsEngineValidator: form passed validation"); 258 return true; 259 } 260} 261 262function SeamlessDonationsValidateRequired(validationObject) { 263 var elementID = jQuery(validationObject).attr('id'); 264 var elementType = jQuery(validationObject).attr('type'); 265 var elementName = jQuery(validationObject).attr('name'); 266 var elementValue = jQuery(validationObject).val(); 267 if (elementType == 'text') { 268 var divSelector = "input[name=" + elementName + "]"; 269 var errorSelector = "div[id=" + elementName + "-error-message]"; 270 if (SeamlessDonationsTrim(elementValue) == '') { 271 jQuery('#seamless-donations-form').find(divSelector).addClass('seamless-donations-invalid-input'); 272 jQuery('#seamless-donations-form').find(errorSelector).text('This is a required field.').show('fast'); 273 274 return false; 275 } else { 276 jQuery('#seamless-donations-form').find(divSelector).removeClass('seamless-donations-invalid-input'); 277 return true 278 } 279 280 } 281 if (elementType == 'radio' || elementType == 'checkbox') { 282 valid = jQuery(validationObject).prop("checked"); 283 } 284 285 if (valid) { 286 jQuery('#seamless-donations-form').find(divSelector).removeClass('seamless-donations-invalid-input'); 287 return true; 288 } else { 289 jQuery('#seamless-donations-form').find(divSelector).addClass('seamless-donations-invalid-input'); 290 jQuery('#seamless-donations-form').find(errorSelector).text('This is a required field.').show('fast'); 291 return false; 292 } 293 return true; 294} 295 296function SeamlessDonationsValidateEmail(validationObject) { 297 298 var elementID = jQuery(validationObject).attr('id'); 299 var elementType = jQuery(validationObject).attr('type'); 300 var elementName = jQuery(validationObject).attr('name'); 301 var elementValue = jQuery(validationObject).val(); 302 303 if (elementType == 'text' && elementValue != '') { 304 var divSelector = "input[name=" + elementName + "]"; 305 var errorSelector = "div[id=" + elementName + "-error-message]"; 306 307 var lastAtPos = elementValue.lastIndexOf('@'); 308 var lastDotPos = elementValue.lastIndexOf('.'); 309 var isEmail = (lastAtPos < lastDotPos && lastAtPos > 0 310 && elementValue.indexOf('@@') == -1 && lastDotPos > 2 && (elementValue.length - lastDotPos) > 2); 311 if (!isEmail) { 312 jQuery('#seamless-donations-form').find(divSelector).addClass('seamless-donations-invalid-input'); 313 jQuery('#seamless-donations-form').find(errorSelector).text('Please enter a valid email address.').show('fast'); 314 return false;
315 } 316 jQuery('#seamless-donations-form').find(divSelector).removeClass('seamless-donations-invalid-input'); 317 } 318 return true; 319} 320 321function SeamlessDonationsValidateCurrency(validationObject) { 322 var elementID = jQuery(validationObject).attr('id'); 323 var elementType = jQuery(validationObject).attr('type'); 324 var elementName = jQuery(validationObject).attr('name'); 325 var elementValue = jQuery(validationObject).val(); 326 327 if (elementType == 'text') { 328 329 var divSelector = "input[name=" + elementName + "]"; 330 var errorSelector = "div[id=" + elementName + "-error-message]"; 331 332 // Check if amount is empty 333 if (!elementValue) { 334 jQuery('#seamless-donations-form').find(divSelector).addClass('seamless-donations-invalid-input'); 335 jQuery('#seamless-donations-form').find(errorSelector).text('This is a required field.').show('fast'); 336 return false; 337 } 338 339 // Check for anything other than numbers and decimal points 340 var matchTest = elementValue.match(/[^0123456789.]/g); 341 if (matchTest != null) { 342 jQuery('#seamless-donations-form').find(divSelector).addClass('seamless-donations-invalid-input'); 343 jQuery('#seamless-donations-form').find(errorSelector).text('Please use only numbers.').show('fast'); 344 return false; 345 } 346 347 // Count the number of decimal points 348 var pointCount = DgxDonateCountNeedles(".", elementValue); 349 350 // If more than one decimal point, fail right away 351 if (pointCount > 1) { 352 jQuery('#seamless-donations-form').find(divSelector).addClass('seamless-donations-invalid-input'); 353 jQuery('#seamless-donations-form').find(errorSelector).text('Please use only numbers.').show('fast'); 354 return false; 355 } 356 357 // A leading zero is not allowed 358 if (elementValue.substr(0, 1) == "0") { 359 jQuery('#seamless-donations-form').find(divSelector).addClass('seamless-donations-invalid-input'); 360 jQuery('#seamless-donations-form').find(errorSelector).text('A leading zero is not allowed.').show('fast'); 361 return false; 362 } 363 364 // A leading decimal point is not allowed (minimum donation is 1.00) 365 if (elementValue.substr(0, 1) == ".") { 366 jQuery('#seamless-donations-form').find(divSelector).addClass('seamless-donations-invalid-input'); 367 jQuery('#seamless-donations-form').find(errorSelector).text('Minimum value is 1.00.').show('fast'); 368 return false; 369 } 370 371 // If we have a decimal point and there is anything other than two digits after it, fail 372 if (pointCount == 1) { 373 var pointIndex = elementValue.indexOf("."); 374 if (pointIndex + 2 != (elementValue.length - 1)) { 375 jQuery('#seamless-donations-form').find(divSelector).addClass('seamless-donations-invalid-input'); 376 jQuery('#seamless-donations-form').find(errorSelector).text('Please use only numbers.').show('fast'); 377 return false; 378 } 379 } 380 jQuery('#seamless-donations-form').find(divSelector).removeClass('seamless-donations-invalid-input'); 381 } 382 return true; 383} 384 385function SeamlessDonationsTrim(s) { 386 if (s == undefined) { 387 s = ""; 388 } 389 390 s = s.replace(/(^\s*)|(\s*$)/gi, ""); 391 s = s.replace(/[ ]{2,}/gi, " "); 392 s = s.replace(/\n /, "\n"); 393 return s; 394} 395 396function DgxDonateCountNeedles(a, b) { 397 var c = b.split(a) - 1; 398 return c.length; 399}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.