1/** 2 * 3 * @source: https://github.com/fightforthefuture/eunetneutrality 4 * 5 * @licstart The following is the entire license notice for the 6 * JavaScript code in this page. 7 * 8 * Copyright (C) Fight for the Future 9 * 10 * 11 * The JavaScript code in this page is free software: you can 12 * redistribute it and/or modify it under the terms of the GNU 13 * General Public License (GNU GPL) as published by the Free Software 14 * Foundation, either version 3 of the License, or (at your option) 15 * any later version. The code is distributed WITHOUT ANY WARRANTY; 16 * without even the implied warranty of MERCHANTABILITY or FITNESS 17 * FOR A PARTICULAR PURPOSE. See the GNU GPL for more details. 18 * 19 * As additional permission under GNU GPL version 3 section 7, you 20 * may distribute non-source (e.g., minimized or compacted) forms of 21 * that code without the copy of the GNU GPL normally required by 22 * section 4, provided you include this license notice and a URL 23 * through which recipients can access the Corresponding Source. 24 * 25 * @licend The above is the entire license notice 26 * for the JavaScript code in this page. 27 * 28 */ 29 30/** 31 * util : random grab bag functions 32 */ 33 34var $c = document.createElement.bind(document); 35var $el = document.getElementById.bind(document); 36 37if (!util) var util = {}; 38 39util.getReferrerTag = function() { 40 var ref = document.referrer; 41 if (ref.indexOf('facebook.com') !== -1) 42 return 'from-facebook'; 43 else if (ref.indexOf('twitter.com') !== -1 || ref.indexOf('t.co') !== -1) 44 return 'from-twitter'; 45 else if (ref.indexOf('reddit.com') !== -1) 46 return 'from-reddit'; 47 else if (window.location.href.indexOf('_src=ga') !== -1) 48 return 'from-google-adwords'; 49 else if (ref.indexOf('google.com') !== -1) 50 return 'from-google'; 51}; 52 53util.parseQueryString = function () { 54 var 55 i, 56 pairs, 57 queryObject = {}, 58 queryString = window.location.search; 59 60 if (queryString[0] === '?') { 61 queryString = queryString.substr(1); 62 } 63 64 pairs = queryString.split('&'); 65 i = pairs.length; 66 67 while (i--) { 68 queryObject[pairs[i].split('=')[0]] = pairs[i].split('=')[1]; 69 } 70 71 // Remove extra key 72 delete queryObject['']; 73 74 return queryObject; 75}; 76 77 78window.components = window.components || {}; 79window.components.chat = function (doc, win) { 80 /** 81 * Retrieves petition data from Action Network API, then submits signature 82 * @param {object} doc - Document object 83 * @param {object} win - Window object 84 * */ 85 "use strict"; 86 87 var overlay = doc.querySelector('.chat'), 88 chatbox = doc.getElementById('messages'), 89 form = doc.querySelector('.chat form'), 90 share = doc.querySelector('.chat .share'), 91 input = form.querySelector('input'), 92 phoneNumber = null, 93 failures = 0, 94 partner = 'fftf', 95 queryString = util.parseQueryString(), 96 isInTest = ('isInTest' in queryString) || (document.location.pathname.indexOf('test') > -1), 97 isInMyPage = ('isInMyPage' in queryString), 98 isInStudio = ('isInStudio' in queryString), 99 isInCustom = document.body.classList.contains('my'), 100 isInSafeMode = isInStudio || isInCustom, 101 hueShift = false, 102 brightness = false; 103 104 105 var bubble = function(sender, html, events, textOnly) { 106 events || (events = []); 107 108 var dots = chatbox.querySelectorAll('.dots'); 109 110 for (var i = 0; i < dots.length; i++) 111 chatbox.removeChild(dots[i]); 112 113 var message = $c('div'), 114 clear = $c('div'); 115 116 clear.className = 'clear'; 117 118 message.className = 'message minimized '+sender; 119 120 if (!textOnly) 121 message.innerHTML = html; 122 else 123 message.textContent = html; 124 125 if (hueShift) 126 doHueShift(message, hueShift, brightness); 127 128 chatbox.appendChild(message); 129 chatbox.appendChild(clear); 130 131 var links = message.querySelectorAll('a'); 132 133 for (var i = 0; i < events.length; i++) { 134 if (i > links.length - 1) 135 break; 136 137 links[i].addEventListener('click', events[i]); 138 } 139 140 scrollToBottom(); 141 142 setTimeout(function() { 143 message.classList.remove('minimized'); 144 }, 20); 145 146 } 147 148 var scrollToBottom = function() { 149 chatbox.scrollTop = chatbox.scrollHeight; 150 } 151 152 var dots = function() { 153 var dots = $c('div'); 154 155 for (var i = 0; i < 3; i++) { 156 var dot = $c('div'), 157 lol = $c('div'); 158 159 dot.appendChild(lol); 160 dots.appendChild(dot); 161 } 162 163 dots.className = 'dots'; 164 165 if (hueShift) 166 doHueShift(dots, hueShift, brightness); 167 168 chatbox.appendChild(dots); 169 170 scrollToBottom(); 171 } 172
173 var validatePhone = function(num) { 174 175 num = num.replace(/\s/g, '').replace(/\(/g, '').replace(/\)/g, ''); 176 num = num.replace("+", "").replace(/\-/g, ''); 177 178 if (num.charAt(0) == "1") 179 num = num.substr(1); 180 181 if (num.length != 10) 182 return false; 183 184 return num; 185 } 186 187 var sendPhoneNumber = function() { 188 var data = { 189 "type":"web", 190 "recipients":[ 191 {"username": phoneNumber} 192 ], 193 "options": { 194 "locale": iso, 195 }, 196 "partner": partner 197 }; 198 console.log('sending', data); 199 200 var submission = new XMLHttpRequest(); 201 if (isInTest) { 202 // get conversation type from querystring 203 data['chain'] = queryString.conv || 'vote_1'; 204 submission.open('POST', 'https://votebot-api-staging.herokuapp.com/conversations/', true); 205 } else { 206 submission.open('POST', 'https://votebot-api.herokuapp.com/conversations/', true); 207 } 208 submission.setRequestHeader("Content-Type", "application/json"); 209 submission.send(JSON.stringify(data)); 210 if (_paq) { _paq.push(['trackGoal', 1]); } 211 212 setTimeout(function() { 213 bubble('bot', l10n['CHECK_YOUR_PHONE']); 214 showShareForm(); 215 }, 4000); 216 217 setTimeout(function() { 218 if (modal) modal.show('overlay1'); 219 }, 4000); 220 } 221 222 var showShareForm = function() { 223 form.classList.add('hidden'); 224 225 share.style.display = 'block'; 226 void share.offsetWidth; // Layout 227 share.style.opacity = 1; 228 229 if (isInMyPage) { 230 top.postMessage('show-share-form', 'https://my.hello.vote'); 231 } 232 } 233 234 var animationTimeouts = []; 235 236 var cancelAnimations = function() { 237 document.querySelector('#messages').textContent = ''; 238 animationTimeouts.forEach(clearTimeout); 239 }; 240 241 var initialAnimations = function() { 242 cancelAnimations(); 243 function text(message, textOnly) { 244 return function() { 245 bubble('bot', message, false, textOnly); 246 }; 247 } 248 249 dots(); 250 251 var messages = window.speechBubbles.slice(); 252 253 if (isInSafeMode) { 254 messages = messages.concat([ 255 'I can help you register to vote, remember to vote, and remind your friends to vote too.', 256 'Try me out! Enter your phone number to start<span class="mobileOnly">, or <a href="https://m.me/hellovote">chat on Facebook Messenger</a></span>.', 257 ]); 258 } 259 260 animationTimeouts.push(setTimeout(text(messages.shift(), isInSafeMode), 1000)); 261 animationTimeouts.push(setTimeout(dots, 1100)); 262 263 var delay = 2500; 264 messages.forEach(function(message, i) { 265 var isFinal = (i === messages.length - 1); 266 var textOnly = isInSafeMode && !isFinal; 267 animationTimeouts.push(setTimeout(text(message, textOnly), delay)); 268 delay += 500; 269 270 // Show dots, if there are more messages 271 if (isFinal) { 272 return; 273 } 274 275 animationTimeouts.push(setTimeout(dots, delay)); 276 delay += 500; 277 }); 278 } 279 280 form.addEventListener('submit', function(e) { 281 e.preventDefault(); 282 283 if (!input.value) 284 return input.focus(); 285 286 bubble('user', input.value, [], true); 287 288 if (!phoneNumber) { 289 var _tmpPhoneNumber = validatePhone(input.value) 290 if (_tmpPhoneNumber) { 291 phoneNumber = _tmpPhoneNumber; 292 293 setTimeout(function() { dots() }, 500); 294 295 sendPhoneNumber(); 296 297 } else { 298 setTimeout(function() { dots() }, 500); 299 setTimeout(function() { 300 failures++; 301 302 var msg = 'Sorry, I didn\'t recognize that phone number. Please try again!' 303 304 if (failures > 1) 305 msg = 'I\'m still having trouble. Make sure you enter a U.S. phone number.'; 306 307 bubble('bot', msg); 308 309 input.focus(); 310 }, 1500); 311 } 312 } 313 314 input.placeholder = ''; 315 input.value = ''; 316 }); 317 318 var localize = function() { 319 overlay.querySelector('input').placeholder = l10n['ENTER_PHONE']; 320 overlay.querySelector('button').textContent = l10n['TEXT_ME']; 321 322 if (window.partner && !window.partner.no_disclosure) { 323 overlay.querySelector('.disclosure em').innerHTML = l10n['DISCLOSURE_PARTNER']; 324 overlay.querySelector('.disclosure em a.partner').textContent = window.partner.name; 325 overlay.querySelector('.disclosure em a.partner').href = window.partner.link; 326 if (window.partner.extra_disclosure) { 327 overlay.querySelector('.disclosure em').innerHTML += window.partner.extra_disclosure; 328 } 329 } else { 330 overlay.querySelector('.disclosure em').innerHTML = l10n['DISCLOSURE']; 331 } 332 // update shortcode keyword 333 if (document.querySelector('section span.sms-keyword') && window.partner && window.partner.keyword) { 334 document.querySelector('section span.sms-keyword').textContent = window.partner.keyword.toUpperCase(); 335 } 336 337 overlay.querySelector('.facebook').textContent = l10n['SHARE']; 338 overlay.querySelector('.twitter').textContent = l10n['TWEET']; 339 overlay.querySelector('.donate').textContent = l10n['DONATE']; 340 341 // JL TODO ~ may need to customize on a per-page basis outside of l10n structure 342 overlay.querySelector('.disclosure a.learn-more').textContent = l10n['LEARN_MORE']; 343 344 var poweredBy = overlay.querySelector('.powered-by strong'); 345 if (poweredBy) 346 poweredBy.textContent = l10n['POWERED_BY']; 347 } 348 349 var doHueShift = function(elem, degree, brightness) { 350 elem.style["filter"] = 'hue-rotate(' + degree + 'deg) brightness('+brightness+'%)'; 351 elem.style["-webkit-filter"] = 'hue-rotate(' + degree + 'deg) brightness('+brightness+'%)'; 352 elem.style["-moz-filter"] = 'hue-rotate(' + degree + 'deg) brightness('+brightness+'%)'; 353 elem.style["-ie-filter"] = 'hue-rotate(' + degree + 'deg) brightness('+brightness+'%)'; 354 elem.style["-o-filter"] = 'hue-rotate(' + degree + 'deg) brightness('+brightness+'%)'; 355 } 356 357 var determinePartner = function() { 358 var metaTag = doc.querySelector('meta[name="hellovote:partner"]') 359 360 if (queryString.partner) 361 return partner = queryString.partner; 362 363 if (metaTag && metaTag.content) 364 return partner = metaTag.content; 365 } 366 367 var prefillPhone = function() { 368 if (queryString.phone) { 369 overlay.querySelector('input').value = queryString.phone; 370 } 371 } 372 373 var iframeHandler = function() { 374 if (doc.body.className.indexOf('iframe') === -1) 375 return; 376 377 var learnMore = overlay.querySelector('.disclosure a.learn-more'); 378 if (window.partner) { 379 learnMore.href = 'https://www.hello.vote/'+window.partner.slug.toLowerCase()+'/#what-is-hellovote'; 380 } else { 381 learnMore.href = 'https://www.hello.vote#what-is-hellovote'; 382 } 383 learnMore.target = '_blank'; 384 385 if (isInMyPage) { 386 doc.body.classList.add('my-page'); 387 } else { 388 customizeColors(); 389 } 390 } 391 392 393 394 var parseColor = function(str) { 395 if (str.match('rgb') || str.match('#')) { 396 return unescape(str); 397 } else { 398 return '#' + unescape(str); 399 } 400 } 401 402 var customizeColors = function(newHueShift, newBrightness, newDisclosureColor, newTextColor) { 403 if (newHueShift || queryString.hueShift) { 404 hueShift = newHueShift || queryString.hueShift; 405 brightness = 100; 406 if (newBrightness || queryString.brightness) { 407 brightness = newBrightness || queryString.brightness 408 } 409 doHueShift(form, hueShift, brightness); 410 411 var dots = doc.querySelector('.dots'); 412 if (dots) { 413 doHueShift(dots, hueShift, brightness); 414 } 415 416 var disclosureLinks = overlay.querySelectorAll('.disclosure a, .disclosure img'); 417 for (var i=0; i<disclosureLinks.length; i++) { 418 doHueShift(disclosureLinks[i], hueShift, brightness); 419 } 420 421 var logo = document.querySelector('.logo'); 422 doHueShift(logo, hueShift, brightness); 423 } 424 425 if (newTextColor || queryString.textColor) { 426 var color = parseColor(newTextColor || queryString.textColor); 427 overlay.querySelector('.message').style.color = color; 428 overlay.querySelector('button[type="submit"]').style.color = color; 429 } 430 431 if (newDisclosureColor || queryString.disclosureColor) { 432 var color = parseColor(newDisclosureColor || queryString.disclosureColor); 433 overlay.querySelector('.disclosure').style.color = color; 434 } 435 } 436 437 localize(); 438 determinePartner(); 439 prefillPhone(); 440 iframeHandler(); 441 if (isInSafeMode) { 442 // Allow for live updates 443 window.initialAnimations = initialAnimations; 444 window.customizeColors = customizeColors; 445 } else { 446 initialAnimations(); 447 } 448 449}; 450 451window.components = window.components || {}; 452window.components.petitions = function (doc, win) { 453 /** 454 * Retrieves petition data from Action Network API, then submits signature 455 * @param {object} doc - Document object 456 * @param {object} win - Window object 457 * */ 458 "use strict"; 459 460 var 461 body = doc.getElementsByTagName('body')[0], 462 petitionSignatureForm = doc.getElementById('petition-form'), 463 apiHost = petitionSignatureForm.dataset.host, 464 objectIdentifier = petitionSignatureForm.dataset.petitionId, 465 submitButton = body.querySelector('[type="submit"]'), 466 countryInput = doc.getElementById('hidden-country'), 467 countrySelect = doc.getElementById('select-country'), 468 countryLabel = doc.querySelector('[for="select-country"]'), 469 queryString = win.util.parseQueryString(); 470 471 function numberCommafier(number) { 472 /** 473 * Returns a string representing a number with commas 474 * @param {int} number - the number to transform 475 * */ 476 477 return number.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","); 478 } 479 480 function progressBar(targetValue, targetGoal) { 481 /** 482 * Animates the value of a progress bar 483 * @param {int} targetValue - the target value attribute of the progress bar 484 * @param {int} targetGoal - the target max attribute of the progress bar 485 * */ 486 487 var 488 guardedTargetVal = targetValue.isNaN ? 0 : targetValue, 489 animate, 490 value = 0, 491 progressbar = doc.getElementById('signatures-progress-bar'), 492 max = parseInt(targetGoal), 493 step = (guardedTargetVal / 1500) * 30; // 1500 ms total, 30ms minimum 494 // interval 495 496 if (!progressbar) 497 return false;
498 499 function loading() { 500 value += step; 501 value = Math.ceil(value); 502 if (value >= guardedTargetVal || value >= max) { 503 value = guardedTargetVal; 504 clearInterval(animate); 505 } 506 507 var 508 commafiedNumber = numberCommafier(value); 509 510 progressbar.setAttribute('max', max.toString(10)); 511 progressbar.setAttribute('value', value.toString(10)); 512 progressbar.setAttribute('title', commafiedNumber + ' signatures'); 513 doc.getElementById('total-sigs').textContent = commafiedNumber; 514 doc.getElementById('sigs-to-go').textContent = numberCommafier(targetGoal - value) + ' needed to reach ' + numberCommafier(targetGoal); 515 progressbar.textContent = commafiedNumber + ' signatures'; 516 } 517 518 animate = setInterval(function () { 519 loading(); 520 }, 30); 521 } 522 523 function handleProgressBarError() { 524 /** 525 * Sets values for the progress bar even if there's a server or XHR error 526 * */ 527 progressBar(1519, 2500); 528 } 529 530 function requestAPIInfo() { 531 /** 532 * Builds and sends request to API server 533 * */ 534 var 535 apiData, 536 anRequest = new XMLHttpRequest(); 537 538 anRequest.open('GET', apiHost + '/petition?identifier=' + objectIdentifier, true); 539 anRequest.addEventListener('load', function () { 540 if (anRequest.status >= 200 && anRequest.status < 400) { 541 542 apiData = JSON.parse(anRequest.responseText); 543 544 progressBar(apiData.signatures, apiData.goal); 545 546 // remove this after save-chelsea has > 1000 signatures 547 if (win.location.hostname === 'www.freechelsea.com' && apiData.signatures < 1000) { 548 doc.querySelector('.signatures').style.display = 'none'; 549 } 550 551 } else { 552 handleProgressBarError(); 553 } 554 }); 555 anRequest.addEventListener('error', handleProgressBarError); 556 anRequest.send(); 557 } 558 559 function updateZIPPlaceholder() { 560 /** 561 * Updates placeholder on ZIP/Post Code field to be appropriate for country 562 * selected 563 * */ 564 var 565 ZIPLabel = doc.getElementById('form-zip_code'); 566 567 if (countrySelect.value !== 'US') { 568 ZIPLabel.setAttribute('placeholder', 'Post Code'); 569 } else { 570 ZIPLabel.setAttribute('placeholder', 'ZIP'); 571 } 572 } 573 574 function toggleCountryField() { 575 /** 576 * Hides the label and shows the select when someone changes their signature 577 * country. 578 * */ 579 580 countryInput.parentNode.removeChild(countryInput); 581 countrySelect.setAttribute('name', 'signature[country]'); 582 countrySelect.classList.add('visible'); 583 countryLabel.classList.add('hidden'); 584 } 585 586 function submitForm(event) { 587 /** 588 * Submits the form to ActionNetwork. If the script doesnât, by now, know 589 * the action_network identifier, default isnât prevented on the event and 590 * form submission proceeds as normal. 591 * @param {event} event - Form submission event 592 * */ 593 594 if (objectIdentifier) { 595 event.preventDefault(); 596 } 597 598 var 599 signatureSubmission = new XMLHttpRequest(); 600 601 win.callbacks.petitions.preSubmit(); 602 603 function compilePayload() { 604 /** 605 * Compiles the form data into a JSON payload for Ajax submission 606 * @return {object} petitionFormData - just the info the API needs 607 * */ 608 var tags = JSON.parse(doc.querySelector('[name="subscription[tag_list]"]').value); 609 if (util.getReferrerTag()) 610 tags.push(util.getReferrerTag()); 611 612 var formData = new FormData(); 613 formData.append('guard', ''); 614 formData.append('hp_enabled', true); 615 formData.append('org', window.org ? window.org : 'fftf'); 616 formData.append('an_tags', JSON.stringify(tags)); 617 formData.append('an_url', win.location.href); 618 formData.append('an_petition', petitionSignatureForm.action.replace('/signatures', '')); 619 formData.append('member[first_name]', doc.getElementById('form-first_name').value); 620 formData.append('member[email]', doc.getElementById('form-email').value); 621 formData.append('member[postcode]', doc.getElementById('form-zip_code').value); 622 formData.append('member[country]', countrySelect.value); 623 624 if (doc.getElementById('opt-in') && doc.getElementById('opt-in').getAttribute('type') === 'checkbox' && doc.getElementById('opt-in').checked === false) { 625 formData.append('opt_out', true); 626 } 627 628 if (doc.getElementById('form-street_address')) { 629 formData.append('member[street_address]', doc.getElementById('form-street_address').value); 630 } 631 632 if (doc.getElementById('form-phone_number')) { 633 formData.append('member[phone_number]', doc.getElementById('form-phone_number').value); 634 } 635 636 if (doc.getElementById('form-comments')) { 637 formData.append('action_comment', doc.getElementById('form-comments').value); 638 } 639 640 if (queryString.source) { 641 formData.append('subscription[source]', queryString.source); 642 } 643 644 var autoresponderHours = doc.querySelector('meta[name="autoresponder_hours"]'), 645 autoresponderActive = doc.querySelector('meta[name="autoresponder_active"]'); 646 formData.append('autoresponder_hours', autoresponderHours ? autoresponderHours.content : 72); 647 648 if (autoresponderActive) 649 formData.append('autoresponder_active', 1); 650 651 var mothershipTag = document.querySelector('input[name="_mothership_tag"]'); 652 if (mothershipTag && mothershipTag.value) 653 formData.append('tag', mothershipTag.value); 654 else 655 formData.append('tag', window.location.pathname); 656 657 return formData; 658 } 659 660 signatureSubmission.open('POST', 'https://queue.fightforthefuture.org/action', true); 661 // signatureSubmission.open('POST', 'http://localhost:9001/action', true); // JL DEBUG ~ 662 signatureSubmission.addEventListener('error', win.callbacks.petitions.handleSigningError); 663 signatureSubmission.addEventListener('load', win.callbacks.petitions.loadSignatureResponse); 664 signatureSubmission.send(compilePayload()); 665 666 if (typeof FreeProgress !== "undefined") 667 FreeProgress.convert(); 668 } 669 670 function addEventListeners() { 671 /** 672 * Attaches all the listeners all the places 673 * */ 674 countryLabel.addEventListener('click', toggleCountryField); 675 countrySelect.addEventListener('change', updateZIPPlaceholder); 676 petitionSignatureForm.addEventListener('submit', submitForm); 677 } 678
679 function init() { 680 requestAPIInfo(); 681 addEventListeners(); 682 } 683 684 init(); 685}; 686 687(function (doc, win) { 688 "use strict"; 689 690 win.callbacks = win.callbacks || {}; 691 win.callbacks.petitions = { 692 preSubmit: function() { 693 /** 694 * Fires up the loading modal and disables the form 695 * @return {object} - modal with spinner 696 * */ 697 doc.querySelector('[type="submit"]').setAttribute('disabled', true); // JL DEBUG ~ disable for testing 698 }, 699 700 loadSignatureResponse: function(e) { 701 /** 702 * Does the thing after we get a response from the API server 703 * */ 704 705 var xhr = e.target; 706 707 if (xhr.status >= 200 && xhr.status < 400) { 708 709 hideForm() 710 711 } else { 712 win.callbacks.petitions.handleSigningError(xhr); 713 } 714 }, 715 716 handleSigningError: function(e) { 717 /** 718 * Figures out what to say at just the right moment 719 * @param {event|XMLHttpRequest} e - Might be an event, might be a response 720 * from an XMLHttpRequest 721 * */ 722 723 724 doc.querySelector('[type="submit"]').removeAttribute('disabled'); 725 726 alert('AN ERROR OCCURRED DURING SUBMISSION :(\n\nPlease contact [email protected]'); 727 } 728 } 729 730})(document, window); 731 732(function (doc, win) { 733 "use strict"; 734 735 var triggerComponents = function() { 736 win.components = win.components || {}; 737 var 738 i = 0, 739 components = doc.querySelector('body').getAttribute('data-components'); 740 741 if (components !== undefined) { 742 components = components.split(' '); 743 i = components.length; 744 745 while (i--) { 746 if (components[i] !== '' && win.components[components[i]] !== undefined) { 747 win.components[components[i]](doc, win); 748 } 749 } 750 } 751 } 752 753 triggerComponents(); // JL NOTE ~ disabled for "beta" 754 755 var showChat = function() { 756 doc.querySelector('.chat').classList.remove('hidden'); 757 setTimeout(function() { 758 doc.querySelector('.chat').classList.remove('transparent'); 759 doc.body.classList.remove('scrolling'); 760 }, 10); 761 } 762 763 var hideChat = function() { 764 doc.querySelector('.chat').classList.add('transparent'); 765 setTimeout(function() { 766 doc.querySelector('.chat').classList.add('hidden'); 767 doc.body.classList.add('scrolling'); 768 }, 500); 769 } 770 771 var handleGetStarted = function(e) { 772 if (getComputedStyle(document.querySelector('.chat')).position == 'fixed') { 773 showChat(); 774 } else { 775 smoothScroll(0); 776 } 777 } 778 779 var onDomContentLoaded =function() { 780 781 var learnMore = doc.querySelector('a.learn-more'); 782 if (learnMore && doc.body.className.indexOf('iframe') === -1) { 783 learnMore.addEventListener('click', function(e) { 784 785 if (getComputedStyle(document.querySelector('.chat')).position == 'fixed') { 786 hideChat(); 787 } else { 788 smoothScroll(doc.querySelector('h1')); 789 } 790 }); 791 } 792 793 window.onhashchange = function (e) { 794 if (e.newURL.slice(-1) == '#') { 795 handleGetStarted(); 796 } 797 } 798 799 initModal(); 800 801 // JL NOTE ~ strip all this junk out when the "beta" is over --------------- 802 // ------------------------------------------------------------------------- 803 // var showMainPage = function(immediately) { 804 // var triggered = function() { 805 // doc.getElementById('beta').style.display = 'none'; 806 // triggerComponents(); 807 // } 808 // if (!immediately) { 809 // doc.getElementById('beta').style.opacity = 0; 810 // setTimeout(function() { 811 // triggered() 812 // }, 500); 813 // } else { 814 // triggered() 815 // } 816 // } 817 818 // var beta = doc.getElementById('beta'); 819 // if (beta) { 820 // doc.getElementById('beta-form').addEventListener('submit', function(e) { 821 // e.preventDefault(); 822 // if (doc.getElementById('beta-code').value.toLowerCase() != 'porunga') { 823 // doc.getElementById('beta-explanation').innerHTML = 'Sorry, that beta key didn\'t work. Contact <a href="mailto:[email protected]">[email protected]</a> if you need assistance.'; 824 // doc.getElementById('beta-explanation').className = 'error'; 825 // doc.getElementById('beta-form').className = 'error'; 826 // } else { 827 // doc.getElementById('beta-form').style.display = 'none'; 828 // doc.getElementById('beta').querySelector('h2').style.display = 'block'; 829 // document.cookie = "beta=true; expires=Thu, 01 Dec 2016 12:00:00 UTC"; 830 // setTimeout(function() { showMainPage(); }, 1500); 831 // } 832 // }); 833 // } 834 // if (document.cookie.indexOf('beta=true') !== -1) 835 // showMainPage(true); 836 // ------------------------------------------------------------------------- 837 838 }; 839 840 var initModal = function() {
841 var overlay = doc.getElementById('overlay1'); 842 843 if (!overlay) 844 return; 845 846 overlay.style.position = 'fixed'; 847 overlay.style.left = '0px'; 848 overlay.style.top = '0px'; 849 overlay.style.display = 'none'; 850 overlay.classList.add('hidden'); 851 852 overlay.addEventListener('click', function(e) { 853 if (e.target == overlay) 854 modal.hide('overlay1'); 855 }); 856 857 overlay.querySelector('.x').addEventListener('click', function(e) { 858 e.preventDefault(); 859 modal.hide('overlay1'); 860 }); 861 } 862 863 var isReady = document.readyState; 864 865 if (isReady == "complete" || isReady == "loaded" || isReady == "interactive") 866 onDomContentLoaded(); 867 else if (document.addEventListener) 868 document.addEventListener('DOMContentLoaded', onDomContentLoaded, false); 869 870 871})(document, window); 872 873var modal = { 874 show: function(id) { 875 var overlay = document.getElementById(id); 876 877 if (!overlay) 878 return; 879 880 overlay.style.display = 'block'; 881 882 setTimeout(function() { 883 overlay.classList.remove('hidden'); 884 }, 25); 885 886 }, 887 hide: function(id) { 888 var overlay = document.getElementById(id); 889 890 if (!overlay) 891 return; 892 893 overlay.classList.add('hidden'); 894 setTimeout(function() { 895 overlay.style.display = 'none'; 896 }, 350); 897 898 } 899} 900 901// Show archived site modal on page load 902document.addEventListener("DOMContentLoaded", function() { 903 var body = document.querySelector('body'); 904 body.classList.add('modal-open'); 905 var html = "<div class='overlay js-archive-modal js-close'>"+ 906 "<div class='modal'>"+ 907 "<img src='/images/fftf-logo-dark.svg' alt='Fight for the Future logo'>"+ 908 "<p class='push-top'>"+ 909 "Please note that HelloVote's functionality has been disabled. You "+ 910 "can see the results from our experiment in civic engagement via "+ 911 "mobile voter registration "+ 912 "<a href='https://www.hello.vote/stats/'>here</a>. If you are a "+ 913 "developer, the source code for HelloVote is "+ 914 "<a href='https://github.com/fightforthefuture/votebot-api'>here</a>. "+ 915 "Stay tuned..."+ 916 "</p>"+ 917 "<p>"+ 918 "To see what Fight for the Future is up to, "+ 919 "<a href='https://www.fightforthefuture.org/'>please visit our homepage</a>."+ 920 "</p>"+ 921 "<a class='x js-close'>Ã</a>"+ 922 "</div>"+ 923 "</div>"; 924 var injector = document.createElement('div'); 925 injector.innerHTML = html; 926 body.appendChild(injector); 927 928 document.addEventListener('click', function(ev) { 929 if (ev.target.classList.contains('js-close')) { 930 ev.preventDefault(); 931 var modalEl = document.querySelectorAll('.js-archive-modal'); 932 modalEl[0].classList.add('hidden'); 933 body.classList.remove('modal-open'); 934 } 935 }, false); 936});
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.